Вычислить прошедшее время в Java/Groovy

У меня есть...


Date start = new Date()

...
...
...

Date stop = new Date()

Я хотел бы получить эти годы, месяцы, дни, часы, минуты и секунды между этими двумя датами.

-

Я уточню вопрос.

Я просто хочу получить прошедшее время, как абсолютную меру, которая не учитывает високосные годы, дни каждого месяца и т.д.

Таким образом, я думаю, что невозможно пройти годы и месяцы, и все, что я могу получить, это дни, часы, минуты и секунды.

В частности, я хочу сказать, что определенная задача продолжалась, например.

20 sec
13 min, 4 sec
2 h, 10 min, 2 sec
4 d, 4 h, 2 min, 2 sec

Так что, пожалуйста, простите мою точность.

Ответ 1

Я только что нашел это быстрое решение Groovy:

import groovy.time.TimeCategory 
import groovy.time.TimeDuration

TimeDuration td = TimeCategory.minus( stop, start )
println td

Ответ 2

Вы можете сделать все это с помощью деления и мод.

long l1 = start.getTime();
long l2 = stop.getTime();
long diff = l2 - l1;

long secondInMillis = 1000;
long minuteInMillis = secondInMillis * 60;
long hourInMillis = minuteInMillis * 60;
long dayInMillis = hourInMillis * 24;

long elapsedDays = diff / dayInMillis;
diff = diff % dayInMillis;
long elapsedHours = diff / hourInMillis;
diff = diff % hourInMillis;
long elapsedMinutes = diff / minuteInMillis;
diff = diff % minuteInMillis;
long elapsedSeconds = diff / secondInMillis;

Это должно предоставить вам всю запрашиваемую информацию.

EDIT: поскольку люди, похоже, смущены, нет, это не учитывает такие переменные, как високосные годы или летнее время. Это чисто истекшее время, что и было предложено.

Ответ 3

Не так просто со стандартным API Date.

Возможно, вы захотите посмотреть Joda Time или JSR-310 вместо этого.

Я не эксперт в Joda, но я думаю, что код будет:

Interval interval = new Interval(d1.getTime(), d2.getTime());
Period period = interval.toPeriod();
System.out.printf(
    "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
    period.getYears(), period.getMonths(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());

Ответ 4

Что касается JodaTime, я только что получил это; благодаря ответчику, который это предложил. Здесь предлагается более сжатая версия кода Joda:

Period period = new Period(d1.getTime(), d2.getTime());
System.out.printf(
    "%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n", 
    period.getYears(), period.getMonths(), period.getDays(),
    period.getHours(), period.getMinutes(), period.getSeconds());

(не уверен, что это помогает исходному вопросу, но, конечно, поисковикам).

Ответ 5

Ну, так как Java 1.5 вы должны использовать TimeUnit.

Вот простой и простой пример этого. Я думаю, что в groovy он может быть короче (как всегда).

/**
 * Formats a given {@link Date} to display a since-then timespan.
 * @param created
 * @return String with a format like "3 minutes ago"
 */
public static String getElapsedTime(Date created) {
    long duration = System.currentTimeMillis() - created.getTime();
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
    long days = TimeUnit.MILLISECONDS.toDays(duration);
    long hours = TimeUnit.MILLISECONDS.toHours(duration);
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
    if (days > 0) {
        return days + " days";
    }
    if (hours > 0) {
        return hours + " hrs";
    }
    if (minutes > 0) {
        return minutes + " minutes";
    }

    return seconds + " seconds";
}

О, и избегайте нескольких возвратов, пожалуйста;)

Ответ 6

Собственно, в отношении вышеприведенных ответов о Joda-Time.

Есть более простой способ сделать это с помощью Joda-Times Period class:

Period period = new Period(startDate, endDate);
System.out.println(PeriodFormat.getDefault().print(period));

Чтобы настроить выход, просмотрите PeriodFormat, PeriodFormatter и PeriodFormatterBuilder.

Ответ 7

ТЛ; др

Duration.between( then , Instant.now() )

Использование java.time

Современный способ использует классы java.time, которые вытесняют проблемные старые классы даты и времени.

Вместо Date используйте Instant. Класс Instant представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).

Instant then = Instant.now();
…
Instant now = Instant.now();

Используйте класс Duration для промежутка времени, не привязанного к временной шкале, с разрешением день-часы-минуты-секунды-нано.

Duration d = Duration.between( then , now );

В течение определенного промежутка времени с разрешением лет-месяцев-дней используйте класс Period.

Генерация строки в стандартном формате ISO 8601 format для длительностей: PnYnMnDTnHnMnS. P отмечает начало. T отделяет любые годы-месяцы-дни от часов-минут-секунд. Так что два с половиной часа - это PT2H30M.

String output = d.toString();

В Java 9 и более поздних версиях вы можете получить доступ к отдельным частям с помощью методов toDaysPart, toHoursPart и т.д.

Также в Java 9 и более поздних версиях есть усовершенствование Instant.now, где он фиксирует текущий момент в микросекундах, а не в миллисекундах, наблюдаемых в Java 8. Конечно, во всех версиях Java Класс Instant может содержать значение в наносекундах.


О java.time

Среда java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar и & SimpleDateFormat.

Проект Joda-Time, который теперь находится в режиме обслуживания, рекомендует выполнить переход на классы java.time.

Чтобы узнать больше, см. Учебное пособие по Oracle. И поищите в Кару множество примеров и объяснений. Спецификация: JSR 310.

Где взять классы java.time?

  • Java SE 8 и SE 9 и более поздние
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые мелкие функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональности java.time перенесена на Java 6 & 7 в ThreeTen-Backport.
  • Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и еще more.

Ответ 8

Хмм, если я получу то, что вы просите, вы хотите знать, что если:

start = 1 января 2001 года, 10: 00: 00 000 утра и

stop = 6 января 2003 года, 12: 01: 00.000 вечера

вы хотите получить ответ от 2 лет, 0 месяцев, 5 дней, 2 часов, 1 минута

К сожалению, это благоразумный ответ. Что, если даты были 2 января и 31 января? Это будет 29 дней? Хорошо, но с 2 февраля по 2 марта составляет 28 (29) дней, но будет указан как 1 месяц?

Продолжительность времени в чем-либо, кроме секунд или, возможно, дней, является переменной, не зная контекста, поскольку месяцы и годы имеют разную длину. Разница между двумя датами должна быть в статических единицах, которые легко вычислимы из stop.getTime() - start.getTime() (что является разницей в миллисекундах)

Ответ 9

Помимо вышеупомянутого большого API JodaTime, который я рекомендую сделать, лучшей стандартной альтернативой Java, которую вы можете использовать это java.util.Calendar. Работа с ним громоздка (это преуменьшение. Смотрите здесь однострочные примеры JodaTime), но вы также можете рассчитать истекшее время с ним. Важным ключом является то, что вы должны использовать Calendar#add() в цикле, чтобы получить прошедшее значение в течение нескольких лет, месяцев и дней, чтобы учитывать периоды високосных, лет и веков. Вы не должны вычислять их обратно из (милли) секунд.

Вот базовый пример:

import java.util.Calendar;

public class Test {

    public static void main(String[] args) throws Exception {
        Calendar start = Calendar.getInstance();
        start.set(1978, 2, 26, 12, 35, 0); // Just an example.
        Calendar end = Calendar.getInstance();

        Integer[] elapsed = new Integer[6];
        Calendar clone = (Calendar) start.clone(); // Otherwise changes are been reflected.
        elapsed[0] = elapsed(clone, end, Calendar.YEAR);
        clone.add(Calendar.YEAR, elapsed[0]);
        elapsed[1] = elapsed(clone, end, Calendar.MONTH);
        clone.add(Calendar.MONTH, elapsed[1]);
        elapsed[2] = elapsed(clone, end, Calendar.DATE);
        clone.add(Calendar.DATE, elapsed[2]);
        elapsed[3] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 3600000;
        clone.add(Calendar.HOUR, elapsed[3]);
        elapsed[4] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 60000;
        clone.add(Calendar.MINUTE, elapsed[4]);
        elapsed[5] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 1000;

        System.out.format("%d years, %d months, %d days, %d hours, %d minutes, %d seconds", elapsed);
    }

    private static int elapsed(Calendar before, Calendar after, int field) {
        Calendar clone = (Calendar) before.clone(); // Otherwise changes are been reflected.
        int elapsed = -1;
        while (!clone.after(after)) {
            clone.add(field, 1);
            elapsed++;
        }
        return elapsed;
    }

}

Он должен напечатать мой возраст с этого момента =)

О, я должен добавить, вы можете "конвертировать" Date в Calendar с помощью Calendar#setTime().

Ответ 10

Это легко; Вы должны установить правильный часовой пояс

import java.util.TimeZone;
import java.util.logging.Logger;

import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class ImportData {

    private final static Logger log = Logger.getLogger(ImportData.class.getName());
    private final static DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private final static DateTimeFormatter dtfh = DateTimeFormat.forPattern("HH:mm:ss.SSS");

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
       TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
       DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));
       // Quotes connection=Quotes.getInstance();
       final long start  = System.currentTimeMillis();
       // do something here ...
       // connection.importTickdata();
       Thread.currentThread().sleep(2000);
       final long end  = System.currentTimeMillis();
       log.info("[start]    " + dtf.print(start));
       log.info("[end]      " + dtf.print(end));
       TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
       DateTimeZone.setDefault(DateTimeZone.forID("UTC"));
       log.info("[duration] " + dtfh.print(end - start));
       // connection.logOff();
       // System.exit(0);
    }

возвращает:

10.11.2010 00:08:12 ImportData main
INFO: [start]    2010-11-10 00:08:10.306
10.11.2010 00:08:12 ImportData main
INFO: [end]      2010-11-10 00:08:12.318
10.11.2010 00:08:12 ImportData main
INFO: [duration] 00:00:02.012

Ответ 11

Я делаю это в общем:

def start_time = System.currentTimeMillis()
...
def end_time = System.currentTimeMillis()

println  (end_time - start_time) +' ms'

Затем вы можете разбить это на любую единицу времени, которую вы хотите, используя класс Duration Groovy http://docs.groovy-lang.org/latest/html/api/groovy/time/Duration.html.

Ответ 12

Нет смысла создавать объект Date, поскольку все это происходит, это wrap System.currentTimeMillis(). Функция getTime() просто распаковывает объект Date. Я предлагаю вам использовать эту функцию для получения долгого времени.

Если вам нужна только вторая точность, это нормально. Однако, если вы хотите, чтобы точность в миллисекундах использовала System.nanoTime(), чтобы получить время простоя.

Ответ 13

Это полная функция, которую я реализовал на основе ответа Sebastian Celis. И снова, с его поста - это не принимает во внимание такие вещи, как високосные годы или переход на летнее время. Это чистое истекшее время.

Выход выполнен с учетом моей потребности. Это выводит только три важных раздела. Вместо возврата

4 месяца, 2 недели, 3 дня, 7 часов, 28 минут, 43 секунды

Он просто возвращает первый 3-й блок (см. больше примеров прогона в конце сообщения):

4 месяца, 2 недели, 3 дня

Вот полный исходный код метода:

/**
 * Format milliseconds to elapsed time format
 * 
 * @param time difference in milliseconds
 * @return Human readable string representation - eg. 2 days, 14 hours, 5 minutes
 */
public static String formatTimeElapsedSinceMillisecond(long milisDiff) {
    if(milisDiff<1000){ return "0 second";}

    String formattedTime = "";
    long secondInMillis = 1000;
    long minuteInMillis = secondInMillis * 60;
    long hourInMillis = minuteInMillis * 60;
    long dayInMillis = hourInMillis * 24;
    long weekInMillis = dayInMillis * 7;
    long monthInMillis = dayInMillis * 30;

    int timeElapsed[] = new int[6];
    // Define time units - plural cases are handled inside loop
    String timeElapsedText[] = {"second", "minute", "hour", "day", "week", "month"};
    timeElapsed[5] = (int) (milisDiff / monthInMillis); // months
    milisDiff = milisDiff % monthInMillis;
    timeElapsed[4] = (int) (milisDiff / weekInMillis); // weeks
    milisDiff = milisDiff % weekInMillis;
    timeElapsed[3] = (int) (milisDiff / dayInMillis); // days
    milisDiff = milisDiff % dayInMillis;
    timeElapsed[2] = (int) (milisDiff / hourInMillis); // hours
    milisDiff = milisDiff % hourInMillis;
    timeElapsed[1] = (int) (milisDiff / minuteInMillis); // minutes
    milisDiff = milisDiff % minuteInMillis;
    timeElapsed[0] = (int) (milisDiff / secondInMillis); // seconds

    // Only adds 3 significant high valued units
    for(int i=(timeElapsed.length-1), j=0; i>=0 && j<3; i--){
        // loop from high to low time unit
        if(timeElapsed[i] > 0){
            formattedTime += ((j>0)? ", " :"") 
                + timeElapsed[i] 
                + " " + timeElapsedText[i] 
                + ( (timeElapsed[i]>1)? "s" : "" );
            ++j;
        }
    } // end for - build string

    return formattedTime;
} // end of formatTimeElapsedSinceMillisecond utility method

Вот пример тестового заявления:

System.out.println(formatTimeElapsedSinceMillisecond(21432424234L));
// Output: 8 months, 1 week, 1 day

System.out.println(formatTimeElapsedSinceMillisecond(87724294L));
// Output: 1 day, 22 minutes, 4 seconds

System.out.println(formatTimeElapsedSinceMillisecond(123434L));
// Output: 2 minutes, 3 seconds

Ответ 14

Это еще одна аналогичная функция: она не будет отображаться в течение нескольких дней, часов, минут и т.д., если ее не нужно менять, если нужно, литералы.

public class ElapsedTime {

    public static void main(String args[]) {

        long start = System.currentTimeMillis();
        start -= (24 * 60 * 60 * 1000 * 2);
        start -= (60 * 60 * 1000 * 2);
        start -= (60 * 1000 * 3);
        start -= (1000 * 55);
        start -= 666;
        long end = System.currentTimeMillis();
        System.out.println(elapsedTime(start, end));

    }

    public static String elapsedTime(long start, long end) {

        String auxRet = "";

        long aux = end - start;
        long days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
        // days
        if (aux > 24 * 60 * 60 * 1000) {
            days = aux / (24 * 60 * 60 * 1000);
        }
        aux = aux % (24 * 60 * 60 * 1000);
        // hours
        if (aux > 60 * 60 * 1000) {
            hours = aux / (60 * 60 * 1000);
        }
        aux = aux % (60 * 60 * 1000);
        // minutes
        if (aux > 60 * 1000) {
            minutes = aux / (60 * 1000);
        }
        aux = aux % (60 * 1000);
        // seconds
        if (aux > 1000) {
            seconds = aux / (1000);
        }
        milliseconds = aux % 1000;

        if (days > 0) {
            auxRet = days + " days ";
        }
        if (days != 0 || hours > 0) {
            auxRet += hours + " hours ";
        }
        if (days != 0 || hours != 0 || minutes > 0) {
            auxRet += minutes + " minutes ";
        }
        if (days != 0 || hours != 0 || minutes != 0 || seconds > 0) {
            auxRet += seconds + " seconds ";
        }
        auxRet += milliseconds + " milliseconds ";

        return auxRet;
    }

}

Ответ 15

import groovy.time.TimeCategory
import groovy.time.TimeDuration

time = { closure ->
    use(TimeCategory) {
        def started = new Date()
        def res = closure()
        TimeDuration duration = new Date() - started
        logger.info("Execution duration: " + duration.toMilliseconds() + "ms")
        res
    }
}

time {
    println 'A realy heavy operation here that you want to measure haha'
}

Ответ 16

Это проблема, и нужно сделать алгоритм для учета високосных лет и точного количества месяцев и дней в течение нескольких лет. Интересно, как это просто, если нужно использовать только одну единицу измерения. Например, общее количество дней между двумя днями является правильным, как указано на число напоминаний за несколько дней после того, как количество месяцев и лет рассчитывается в течение двух десятилетий.

В настоящее время я работаю над этим, чтобы предоставить его из моей реализации PML, например, в форме:

unemployed <- date.difference[
    From = 2009-07-01, 
    Till = now, 
    YEARS, MONTHS, DAYS
]: yyyy-MM-dd

$$-> *unemployed -> date.translate[ YEARS, MONTHS, DAYS ] -> print["Unemployed for:", .]

Конечно, это также было бы полезно и требовалось для точных расчетов процентных ставок.