Как в Java измерить прошедшее время?

Я хочу иметь что-то вроде этого:

public class Stream
{
    public startTime;
    public endTime;

    public getDuration()
    {
        return startTime - endTime;
    }
}

Также важно, чтобы, например, если startTime равен 23:00, а endTime 1:00, чтобы получить продолжительность 2:00.

Какие типы использовать для этого в Java?


person Omu    schedule 20.11.2009    source источник
comment
Возможные дубликаты: stackoverflow.com/questions/180158, stackoverflow.com/questions/567659 и stackoverflow.com/questions/503877.   -  person Peter Mortensen    schedule 21.11.2009
comment
связанный вопрос не является дубликатом. Название этого вопроса вводит в заблуждение. Содержание этого вопроса касается доступа к текущему времени по часам компьютера. Ответы включают `System.currentTimeMillis ()` и System.nanoTime(). Этот вопрос здесь сосредоточен на вычислении прошедшего времени между двумя моментами без учета получения текущего времени.   -  person Basil Bourque    schedule 17.03.2016


Ответы (14)


К сожалению, ни один из десяти опубликованных ответов не является правильным.

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

Цель nanoTime - измерить прошедшее время, а цель currentTimeMillis - измерить время настенных часов. Вы не можете использовать одно для другой цели. Причина в том, что никакие компьютерные часы не идеальны; он всегда дрейфует и время от времени требует исправления. Это исправление может произойти либо вручную, либо, в случае большинства машин, есть процесс, который выполняется и постоянно вносит небольшие исправления в системные часы («настенные часы»). Это часто случается. Еще одна такая коррекция происходит всякий раз, когда есть дополнительная секунда.

Поскольку целью nanoTime является измерение прошедшего времени, на него не влияют никакие из этих небольших поправок. Это то, что вы хотите использовать. Все текущие тайминги с currentTimeMillis будут отключены - возможно, даже отрицательные.

Вы можете сказать: «Не похоже, что это когда-либо будет иметь такое большое значение», на что я скажу, что, может быть, и нет, но в целом, не правильный код просто лучше, чем неправильный код? К тому же nanoTime все равно короче печатать.

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

person Kevin Bourrillion    schedule 21.11.2009
comment
на самом деле мне нужно измерить продолжительность в минутах, а иногда даже почти в час, что-то в этом роде, есть ли проблемы с производительностью между nanotime и currentmiliseconds? - person Omu; 22.11.2009
comment
опасайтесь nanoTime в многоядерных средах - person jasonk; 25.08.2012
comment
@jasonk можешь уточнить? - person entropy; 02.10.2012
comment
@entropy - конечно; в основном некоторые реализации nanoTime в некоторых версиях OS / Java / CPU будут использовать аппаратный счетчик временных меток ЦП (TSC). Однако этот TSC может не совпадать между ядрами / процессорами. Если ваш поток перепланирован на другое ядро ​​на полпути, вы получите метку времени начала из ядра 1 и метку времени окончания из ядра 2, но они могут быть не в одно и то же время (вы даже можете получить отрицательные значения) - некоторые примеры: stackoverflow.com/questions/510462/ является хорошая е - person jasonk; 02.10.2012
comment
@jasonk, это довольно устаревшая проблема, но факт в том, что, хотя на точность TSC могут влиять многопоточность, регулирование процессора и фаза луны, нет другого способа получить такую ​​точность и точность на стандартная конфигурация ПК. Лучше просто использовать его и понять границы ошибки, которая обычно очень мала! - person Brett; 19.02.2013
comment
@Brett: да, совершенно верно - используйте его и, следовательно, просто остерегайтесь его вводящих в заблуждение ответов. Простым подходом было бы усреднение результатов по большому набору прогонов. - person jasonk; 20.02.2013
comment
Если мне нужен результат прошедшего времени в миллисекундах, мне нужно умножить на 1000000, верно? - person Yuval A.; 13.05.2014
comment
@YuvalA. НЕТ! Никогда не делай этого! Даже не делите на 1000000 (что, по крайней мере, правильно по идее). Всегда используйте библиотеку, например JDK TimeUnit.NANOSECONDS.toMillis(value). - person Kevin Bourrillion; 02.11.2014
comment
@KevinBourrillion Почему бы нам не разделить или умножить затраченное время, чтобы изменить единицы измерения? - person user1071840; 06.11.2014
comment
Потому что это бессмысленно подвержено ошибкам (как показывает комментарий) и труднее читать. - person Kevin Bourrillion; 07.11.2014
comment
@KevinBourrillion TimeUnit.NANOSECONDS.toMillis(value), похоже, имеет неприятный побочный эффект округления. Это не так уж важно, но для toSeconds() или выше вы теряете большую точность. x/1000.0/1000.0/1000.0 работает для преобразования в секунды и очень понятен. - person Autumn Leonard; 04.12.2015
comment
Деление на 1.0e9 намного короче и не требует подсчета нулей. - person Chinoto Vokro; 07.01.2017
comment
@ChinotoVokro И это могло бы быть более точно, как показывает этот тест. - person Stefan Pochmann; 20.03.2017

Какие типы использовать для этого в Java?

Краткий ответ - long. Теперь подробнее о том, как измерить ...

System.currentTimeMillis ()

"Традиционный" способ сделать это действительно - использовать _ 2_:

long startTime = System.currentTimeMillis();
// ... do something ...
long estimatedTime = System.currentTimeMillis() - startTime;

o.a.c.l.t.StopWatch

Обратите внимание, что Commons Lang имеет StopWatch, который можно использовать для измерения времени выполнения в миллисекундах. У него есть такие методы, как _ 4_, _ 5_, _ 6_ и т. д., которые позволяют проводить измерения в различных точках выполнения и могут оказаться удобными. Посмотри на это.

System.nanoTime ()

Вы можете предпочесть использовать System.nanoTime() < / a>, если вы ищете чрезвычайно точные измерения прошедшего времени. Из его javadoc:

long startTime = System.nanoTime();    
// ... the code being measured ...    
long estimatedTime = System.nanoTime() - startTime;

Хамон

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

import com.jamonapi.*;
...
Monitor mon=MonitorFactory.start("myFirstMonitor");
...Code Being Timed...
mon.stop();

Ознакомьтесь с этой статьей на www.javaperformancetunning.com, чтобы получить хорошее представление.

Использование АОП

Наконец, если вы не хотите загромождать свой код этими измерениями (или если вы не можете изменить существующий код), то АОП будет идеальным оружием. Я не собираюсь обсуждать это очень глубоко, но я хотел хотя бы упомянуть об этом.

Ниже очень простой аспект с использованием AspectJ и JAMon (здесь краткое имя pointcut будет использоваться для монитора JAMon, отсюда и вызов thisJoinPoint.toShortString()):

public aspect MonitorAspect {
    pointcut monitor() : execution(* *.ClassToMonitor.methodToMonitor(..));

    Object arround() : monitor() {
        Monitor monitor = MonitorFactory.start(thisJoinPoint.toShortString());
        Object returnedObject = proceed();
        monitor.stop();
        return returnedObject;
    }
}

Определение pointcut можно легко адаптировать для мониторинга любого метода на основе имени класса, имени пакета, имени метода или любой их комбинации. Измерение - действительно идеальный вариант использования АОП.

person Pascal Thivent    schedule 20.11.2009

Ваш новый класс:

public class TimeWatch {    
    long starts;

    public static TimeWatch start() {
        return new TimeWatch();
    }

    private TimeWatch() {
        reset();
    }

    public TimeWatch reset() {
        starts = System.currentTimeMillis();
        return this;
    }

    public long time() {
        long ends = System.currentTimeMillis();
        return ends - starts;
    }

    public long time(TimeUnit unit) {
        return unit.convert(time(), TimeUnit.MILLISECONDS);
    }
}

Использование:

    TimeWatch watch = TimeWatch.start();
    // do something
    long passedTimeInMs = watch.time();
    long passedTimeInSeconds = watch.time(TimeUnit.SECONDS);

Впоследствии прошедшее время можно преобразовать в любой формат, который вам нравится, например, с помощью календаря.

Greetz, GHad

person GHad    schedule 20.11.2009
comment
+1 за упоминание TimeUnit. Я не знал, что он существует (почему его нет в пакете java.util?) - person OscarRyz; 20.11.2009
comment
@Oscar Может быть, мистер Ли считал, что это часть параллельного API - person Pascal Thivent; 20.11.2009
comment
TimeUnit существует с Java 1.5, но был расширен в Java 1.6. Это очень полезное перечисление для работы с - person GHad; 20.11.2009
comment
Отличная идея создать такой класс. Престижность! - person ecruz; 04.05.2020

Если цель состоит в том, чтобы просто напечатать приблизительную информацию о времени в журналах вашей программы, то простое решение для проектов Java - не писать собственные классы секундомера или таймера, а просто использовать org.apache.commons.lang.time.StopWatch класс, который является частью Apache Commons Lang.

final StopWatch stopwatch = new StopWatch();
stopwatch.start();
LOGGER.debug("Starting long calculations: {}", stopwatch);
...
LOGGER.debug("Time after key part of calcuation: {}", stopwatch);
...
LOGGER.debug("Finished calculating {}", stopwatch);
person David Bliss    schedule 20.11.2009
comment
Большинство средств ведения журнала также поддерживают отметки времени как часть вывода журнала. - person James McMahon; 20.11.2009
comment
@ Джеймс МакМахон. Да, но эти временные метки показывают текущее время, а не общее время выполнения данной задачи. - person David Bliss; 20.11.2009
comment
Обратите внимание, что StopWatch использует в своей реализации System.currentTimeMillis (). - person aerobiotic; 18.06.2013
comment
System.currentTimeMillis() предназначен только для getStartTime() собственности. Расчет времени полностью основан на System.nanoTime() (по крайней мере, в версии org.apache.commons.lang3) - person Lu55; 27.01.2020

tl;dr

например, если startTime равен 23:00, а endTime 1:00, чтобы получить продолжительность 2:00.

Невозможно. Если у вас только время суток, часы останавливаются в полночь. Без контекста дат, как мы узнаем, имеете ли вы в виду 1 час ночи следующего дня, на следующей неделе или в следующем десятилетии?

Таким образом, переход с 23:00 до 1:00 означает движение назад во времени на 22 часа, вращая стрелки часов против часовой стрелки. См. Результат ниже, отрицательный через двадцать два часа.

Duration.between(              // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
    LocalTime.of( 23 , 0 ) ,   // A time-of-day without a date and without a time zone. 
    LocalTime.of( 1 , 0 )      // A time-of-day clock stops at midnight. So getting to 1 AM from 11 PM means going backwards 22 hours.
)                              // Return a `Duration` object.
.toString()                    // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS

PT-22H

Пересечение полуночи требует более широкого контекста даты в дополнение к времени суток (см. Ниже).

Как в Java измерить прошедшее время?

  1. Захватите текущий момент в формате UTC с помощью Instant.now() .
  2. Запечатлейте еще один такой момент позже.
  3. Передайте оба значения в _ 3_.
  4. (a) Из полученного объекта Duration извлеките количество 24-часовых дней, часов, минут, секунд и долей секунды в наносекундах, вызвав различные методы to…Part.
    (b) Или вызовите toString, чтобы сгенерировать String в стандартном формате ISO 8601 из PnYnMnDTnHnMnS.

Пример кода с использованием пары объектов Instant.

Duration.between(    // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
    then ,           // Some other `Instant` object, captured earlier with `Instant.now()`.
    Instant.now()    // Capture the current moment in UTC with a resolution as fine as nanoseconds, depending on the limits of your host computer hardware clock and operating system. Generally you will get current moment in microseconds (six decimal digits of fractional second) in Java 9, 10, and 11, but only milliseconds in Java 8. 
)                    // Return a `Duration` object.
.toString()          // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS

PT3M27.602197S

Новые технологии в Java 8+

У нас есть новая технология, встроенная в Java 8 и более поздних версий, java.time framework.

java.time

Фреймворк java.time определяется JSR 310, вдохновленным очень успешным < проект href = "http://www.joda.org/joda-time/" rel = "noreferrer"> Joda-Time, расширенный ThreeTen-Extra, описанный в Oracle Tutorial.

Старые классы даты и времени, такие как java.util.Date/.Calendar, связанные с самыми ранними версиями Java, оказались плохо спроектированными, запутанными и неудобными. Их вытесняют классы java.time.

разрешение

В других ответах обсуждается разрешение.

Классы java.time имеют наносекунду разрешение до девяти цифр десятичной доли секунды. Например, 2016-03-12T04:29:39.123456789Z.

И старые классы java.util.Date/.Calendar, и классы Joda-Time имеют разрешение в миллисекундах (3 цифры дроби). Например, 2016-03-12T04:29:39.123Z.

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

Время суток

Если вы действительно хотите работать только с временем суток, без даты или часового пояса, используйте _ 13_ класс.

LocalTime sooner = LocalTime.of ( 17, 00 );
LocalTime later = LocalTime.of ( 19, 00 );

Duration представляет собой промежуток времени, отсчета секунд плюс наносекунды.

Duration duration = Duration.between ( sooner, later );

Выгрузить в консоль.

System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );

раньше: 17:00 | позже: 19:00 | продолжительность: PT2H

ISO 8601

Обратите внимание, что по умолчанию Duration::toString выводится в стандартном формате ISO 8601. В этом формате P обозначает начало (как в «Периоде»), а T отделяет любую часть «годы-месяцы-дни» от части «часы-минуты-секунды».

Пересечение полуночи

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

Использование того же кода, что и выше, но переход от 23:00 к 01:00 дает отрицательные двадцать два часа (PT-22H).

LocalTime sooner = LocalTime.of ( 23, 0 );
LocalTime later = LocalTime.of ( 1, 0 );

раньше: 23:00 | позже: 01:00 | продолжительность: ПТ-22Н

Дата-время

Если вы намереваетесь пересечь полночь, вам, вероятно, имеет смысл работать со значениями даты и времени, а не только со значениями времени суток.

Часовой пояс

Часовой пояс имеет решающее значение для дат. Итак, мы указываем три элемента: (1) желаемую дату, (2) желаемое время дня и (3) часовой пояс как контекст, с помощью которого можно интерпретировать эту дату и время. Здесь мы произвольно выбираем часовой пояс Монреаль.

Если вы определяете дату только с помощью смещения от UTC, используйте _ 26_ с _ 27_. Если у вас есть полный часовой пояс (смещение плюс правила обработки аномалий, таких как переход на летнее время), используйте _ 28_ с _ 29_.

LocalDate localDate = LocalDate.of ( 2016, 1, 23 );
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime sooner = ZonedDateTime.of ( localDate, LocalTime.of ( 23, 0 ), zoneId );

Мы указываем более позднее время как следующий день в 1:00 утра.

ZonedDateTime later = ZonedDateTime.of ( localDate.plusDays ( 1 ), LocalTime.of ( 1, 0 ), zoneId );

Мы вычисляем Duration таким же образом, как показано выше. Теперь мы получаем два часа, ожидаемые этим Вопросом.

Duration duration = Duration.between ( sooner, later );

Выгрузить в консоль.

System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );

раньше: 2016-01-23T23: 00-05: 00 [Америка / Монреаль] | позже: 2016-01-24T01: 00-05: 00 [Америка / Монреаль] | продолжительность: PT2H

Летнее время

Если бы в имеющейся дате использовалось летнее время (DST) или другая подобная аномалия, классы java.time корректировались бы по мере необходимости. Подробности читайте в документации по классу.


О java.time

java.time framework встроена в Java 8 и новее. Эти классы заменяют неудобные старые устаревшие классы даты и времени, такие как _ 35_, _ 36_, & _ 37_.

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

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

Вы можете обмениваться объектами java.time непосредственно с вашей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.* классах.

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

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

person Basil Bourque    schedule 16.03.2016
comment
этот ответ выглядит как в основном копипаст из - stackoverflow.com/questions/32437550/ и, хотя время упоминается, не отвечает на вопрос - person Entea; 27.06.2018
comment
@Entea Предлагаю вам перечитать повнимательнее. Что касается копирования и вставки, в этом связанном ответе нет раздела о разрешении, не обсуждается Duration и нет объяснения аномалий, таких как переход на летнее время, которые игнорируются при вычислении только времени суток. Что касается того, что здесь вопрос не обсуждается, я бы сказал, что Duration.between ( sooner, later ) в сочетании с объяснением проблемы перехода за полночь - это точный ответ на вопрос, если startTime равен 23:00, а endTime 1:00, чтобы получить продолжительность 2: 00. Я ценю конструктивную критику, но рассчитываю на большее усердие. - person Basil Bourque; 27.06.2018
comment
Я последовал твоему предложению и перечитал ответ более внимательно. Это действительно ответ на вопрос. Я слишком быстро пришел к выводу, прочитав первые 2-3 абзаца и не обнаружив большой связи с вопросом. Это моя ошибка, прошу прощения за свой предыдущий комментарий. Интересно, будет ли здесь конструктивный комментарий: ответ можно улучшить, перестроив его таким образом, чтобы он начинался с самого заданного вопроса. Абзацы можно было бы сформировать в порядке убывания абстракции, возможно, начав с ответа на вопрос «Как измерить прошедшее время» в общем виде и затем перейдя к деталям. - person Entea; 28.06.2018
comment
@Entea Извинения приняты. В соответствии с вашим комментарием я добавил раздел tl; dr вверху, который переходит прямо к сути вопроса, с практическими примерами кода неправильного и правильного способа вычисления прошедшего времени. Хорошее улучшение этого ответа. Спасибо за ваше предложение. - person Basil Bourque; 29.06.2018
comment
Спасибо, что нашли время ответить на мои комментарии. Я усвоил хороший урок, что тезис, который сначала кажется расплывчатым, не следует отвергать полностью, потому что он действительно может содержать веские аргументы. Вероятно, это несколько общее правило, которому люди должны учиться, поскольку они испытывают потребность в эффективном общении. - person Entea; 29.06.2018

Стоит отметить, что

  • System.currentTimeMillis () в лучшем случае имеет точность до миллисекунды. В некоторых системах Windows оно может составлять 16 мс. Он имеет меньшую стоимость, чем альтернативы ‹200 нс.
  • System.nanoTime () имеет точность всего до микросекунды в большинстве систем и может прыгать в системах Windows на 100 микросекунд (т.е. иногда это не так точно, как кажется)
  • Календарь - очень дорогой способ расчета времени. (я могу думать об этом отдельно от XMLGregorianCalendar) Иногда это наиболее подходящее решение, но имейте в виду, что вам следует использовать только длинные интервалы времени.
person Peter Lawrey    schedule 20.11.2009
comment
Что с 16мс и виндой? Windows считывает системные часы каждые 16 мс? - person Koray Tugay; 28.11.2018
comment
В старых версиях Windows @KorayTugay используются часы с частотой 60 Гц или примерно каждые 16,7 мс. Я думаю, что он также использовался, чтобы определить, какие клавиши были нажаты на клавиатуре. - person Peter Lawrey; 29.11.2018

Какие типы использовать для этого в Java?

Ответ: длинный

public class Stream {
    public long startTime;
    public long endTime;

    public long getDuration() {
        return endTime - startTime;
    }
    // I  would add
    public void start() {
        startTime = System.currentTimeMillis();
    }
    public void stop() {
         endTime = System.currentTimeMillis();
     }
}

Использование:

  Stream s = .... 

  s.start();

  // do something for a while 

  s.stop();

  s.getDuration(); // gives the elapsed time in milliseconds. 

Это мой прямой ответ на ваш первый вопрос.

В качестве последнего «примечания» я бы посоветовал вам использовать Joda Time. Он содержит класс interval, подходящий для ваших нужд.

person OscarRyz    schedule 20.11.2009
comment
System.currentTimeMillis () возвращает разницу в миллисекундах между текущим временем и полуночью 1 января 1970 г. по всемирному координированному времени. :) Думаю, меня это устраивает; Я боялся, что у меня будут проблемы, если старт был вчера, а остановка - сегодня. - person Omu; 20.11.2009
comment
Приятно видеть, что @ChuckNorris использует StackOverFlow. - person Tim; 19.04.2012

Java предоставляет статический метод System.currentTimeMillis(). И это возвращает длинное значение, так что это хорошая ссылка. Многие другие классы принимают параметр timeInMillis, который также является длинным.

И многим людям проще использовать библиотеку Joda Time для вычисления даты и времени. .

person Andreas Dolk    schedule 20.11.2009
comment
+1 за упоминание joda time. что случилось с переносом этого на Java? jsr310? - person blank; 20.11.2009
comment
@Bedwyr: к сожалению, он еще не закончен. Может быть, Java8. - person BalusC; 20.11.2009
comment
@BalusC хм - может быть, они найдут для этого время, сейчас закрытие уже началось, и все откладывается. - person blank; 20.11.2009

Если вы предпочитаете использовать Calendar API Java, можете попробовать это,

Date startingTime = Calendar.getInstance().getTime();
//later on
Date now = Calendar.getInstance().getTime();
long timeElapsed = now.getTime() - startingTime.getTime();
person James McMahon    schedule 20.11.2009
comment
Плохая идея. Это добавляет НАМНОГО больше накладных расходов, чем только время в миллисекундах. Если вам нужно только время в миллисекундах, просто используйте System.currentTimeMillis(), вам не нужно знать часовой пояс и все то, что вы видите в Calendar#toString(). - person BalusC; 20.11.2009
comment
Возможно, вы правы. Я не знаю, окажет ли это когда-либо ощутимое влияние на производительность, но, вероятно, это хорошая практика. Однако, если у вас уже есть объект Calendar или вы хотите выполнять более сложные манипуляции, которые облегчает Calendar, этот подход может быть допустимым. - person James McMahon; 20.11.2009

Если вы пишете приложение, которое должно работать с продолжительностью времени, обратите внимание на Joda-Time, в котором есть класс, специально предназначенный для обработки длительностей, Интервалы и периоды. Ваш метод getDuration() выглядит так, как будто он может возвращать интервал времени Joda:

DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0);

public Interval getInterval() {
    Interval interval = new Interval(start, end);
}
person David Bliss    schedule 20.11.2009

Если вы получаете метки времени от System.currentTimeMillis(), тогда ваши временные переменные должны быть длинными.

person uckelman    schedule 20.11.2009

Я обнаружил, что этот код полезен при выборе времени:

public class Et {
    public Et() {
    reset();
    }
    public void reset() {
    t0=System.nanoTime();
    }
    public long t0() {
        return t0;
    }
    public long dt() {
        return System.nanoTime()-t0();
    }
    public double etms() {
    return etms(dt());
    }
    @Override public String toString() {
        return etms()+" ms.";
    }
    public static double etms(long dt) {
        return dt/1000000.; // 1_000_000. breaks cobertura
    }
    private Long t0;
}
person Ray Tayek    schedule 16.03.2016

Использовать это:

SimpleDateFormat format = new SimpleDateFormat("HH:mm");

Date d1 = format.parse(strStartTime);
Date d2 = format.parse(strEndTime);

long diff = d2.getTime() - d1.getTime();
long diffSeconds,diffMinutes,diffHours;

if (diff > 0) {
diffSeconds = diff / 1000 % 60;
diffMinutes = diff / (60 * 1000) % 60;
diffHours = diff / (60 * 60 * 1000);
}
else{
long diffpos = (24*((60 * 60 * 1000))) + diff;
diffSeconds = diffpos / 1000 % 60;
diffMinutes = diffpos / (60 * 1000) % 60;
diffHours = (diffpos / (60 * 60 * 1000));
}

(Также важно, чтобы, например, если startTime равен 23:00, а endTime 1:00, чтобы получить продолжительность 2:00.)

часть "else" может исправить это

person N. N    schedule 21.04.2016

Я построил функцию форматирования на основе материала, который я украл SO. Мне нужен был способ «профилирования» материалов в сообщениях журнала, поэтому мне нужно было сообщение фиксированной продолжительности.

public static String GetElapsed(long aInitialTime, long aEndTime, boolean aIncludeMillis)
{
  StringBuffer elapsed = new StringBuffer();

  Map<String, Long> units = new HashMap<String, Long>();

  long milliseconds = aEndTime - aInitialTime;

  long seconds = milliseconds / 1000;
  long minutes = milliseconds / (60 * 1000);
  long hours = milliseconds / (60 * 60 * 1000);
  long days = milliseconds / (24 * 60 * 60 * 1000);

  units.put("milliseconds", milliseconds);
  units.put("seconds", seconds);
  units.put("minutes", minutes);
  units.put("hours", hours);
  units.put("days", days);

  if (days > 0)
  {
    long leftoverHours = hours % 24;
    units.put("hours", leftoverHours);
  }

  if (hours > 0)
  {
    long leftoeverMinutes = minutes % 60;
    units.put("minutes", leftoeverMinutes);
  }

  if (minutes > 0)
  {
    long leftoverSeconds = seconds % 60;
    units.put("seconds", leftoverSeconds);
  }

  if (seconds > 0)
  {
    long leftoverMilliseconds = milliseconds % 1000;
    units.put("milliseconds", leftoverMilliseconds);
  }

  elapsed.append(PrependZeroIfNeeded(units.get("days")) + " days ")
      .append(PrependZeroIfNeeded(units.get("hours")) + " hours ")
      .append(PrependZeroIfNeeded(units.get("minutes")) + " minutes ")
      .append(PrependZeroIfNeeded(units.get("seconds")) + " seconds ")
      .append(PrependZeroIfNeeded(units.get("milliseconds")) + " ms");

  return elapsed.toString();

}

private static String PrependZeroIfNeeded(long aValue)
{
  return aValue < 10 ? "0" + aValue : Long.toString(aValue);
}

И тестовый класс:

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import junit.framework.TestCase;

public class TimeUtilsTest extends TestCase
{

  public void testGetElapsed()
  {
    long start = System.currentTimeMillis();
    GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance();
    calendar.setTime(new Date(start));

    calendar.add(Calendar.MILLISECOND, 610);
    calendar.add(Calendar.SECOND, 35);
    calendar.add(Calendar.MINUTE, 5);
    calendar.add(Calendar.DAY_OF_YEAR, 5);

    long end = calendar.getTimeInMillis();

    assertEquals("05 days 00 hours 05 minutes 35 seconds 610 ms", TimeUtils.GetElapsed(start, end, true));

  }

}
person Buffalo    schedule 16.03.2018