Рассчитать прошедшее время в Java / Groovy - PullRequest
38 голосов
/ 20 февраля 2009

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


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

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

Ответы [ 15 ]

91 голосов
/ 03 мая 2010

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

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

TimeDuration td = TimeCategory.minus( stop, start )
println td
25 голосов
/ 20 февраля 2009

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

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;

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

РЕДАКТИРОВАТЬ: Поскольку люди, кажется, в замешательстве, нет, это не принимает во внимание такие вещи, как високосные годы или переход на летнее время. Прошло чистое время времени , о чем и просил.

19 голосов
/ 20 февраля 2009

Не так просто со стандартным 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());
10 голосов
/ 21 сентября 2009

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

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

6 голосов
/ 19 февраля 2017

ТЛ; др

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 формат для длительностей : PnYnMnDTnHnMnS. P отмечает начало. T отделяет любые годы-месяцы-дни от часов-минут-секунд. Так что два с половиной часа - это PT2H30M.

String output = d.toString();

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


О java.time

Инфраструктура java.time встроена в 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 голосов
/ 01 февраля 2011

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

Есть более простой способ сделать это с Периодом класса Joda-Time:

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

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

6 голосов
/ 18 мая 2010

Хорошо, начиная с 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";
}

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

3 голосов
/ 21 ноября 2009

Помимо вышеупомянутого великолепного JodaTime API, который я делаю , я рекомендую лучшую стандартную альтернативу 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 голосов
/ 20 февраля 2009

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

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

стоп = 6 января 2003 г., 12: 01: 00: 00 * 005 *

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

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

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

1 голос
/ 10 ноября 2010

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

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...