it-roy-ru.com

Рассчитать прошедшее время в 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

Поэтому, пожалуйста, прости мое отсутствие точности.

38
opensas

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

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

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

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

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;

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

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

25
Sebastian Celis

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

Возможно, вы захотите посмотреть на 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());
19
toolkit

Что касается 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());

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

10
Fletch

тЛ; др

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.time

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

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

Чтобы узнать больше, смотрите Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация это 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 .

6
Basil Bourque

Ну, начиная с 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
dhesse

На самом деле, относительно вышеупомянутых ответов о Joda-Time .

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

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

Чтобы настроить вывод, загляните в PeriodFormat , PeriodFormatter и PeriodFormatterBuilder classes.

6
simao

Помимо вышеупомянутого замечательного JodaTime API, который я рекомендую _ do, лучшая стандартная альтернатива 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().

3
BalusC

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

начало = 1 января 2001 года, с 10:00 до 00:00 и

остановка = 6 января 2003 г., 12: 01: 00.000

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

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

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

3
billjamesdev

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

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: [начало] 2010-11-10 00: 08: 10.306 
 10.11.2010 00:08:12 ImportData main
INFO: [ конец] 2010-11-10 00: 08: 12.318 
 10.11.2010 00:08:12 ImportData main
INFO: [продолжительность] 00: 00: 02.012 
1
udoline

Это еще одна похожая функция, она не будет отображать дни, часы, минуты и т.д., Если она не нужна, при необходимости измените ее литералы.

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;
    }

}
0
jcgonzalez

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

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

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
0
Hossain Khan

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

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

0
Peter Lawrey