Вопрос-ответ

How do I measure time elapsed in Java? [duplicate]

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

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

public class Stream
{
public startTime;
public endTime;

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

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

Какие типы использовать, чтобы выполнить это в Java?

Переведено автоматически
Ответ 1

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

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

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

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

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

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

Ответ 2

Какие типы использовать, чтобы выполнить это в Java?


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

System.currentTimeMillis()

"Традиционный" способ сделать это - действительно использовать System.currentTimeMillis():

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

o.a.c.l.t.StopWatch

Note that Commons Lang has a StopWatch class that can be used to measure execution time in milliseconds. It has methods methods like split(), suspend(), resume(), etc that allow to take measure at different points of the execution and that you may find convenient. Have a look at it.

System.nanoTime()

You may prefer to use System.nanoTime() if you are looking for extremely precise measurements of elapsed time. From its javadoc:

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

Jamon

Another option would be to use JAMon, a tool that gathers statistics (execution time, number of hit, average execution time, min, max, etc) for any code that comes between start() and stop() methods. Below, a very simple example:

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

Check out this article on www.javaperformancetunning.com for a nice introduction.

Using AOP

Finally, if you don't want to clutter your code with these measurement (or if you can't change existing code), then AOP would be a perfect weapon. I'm not going to discuss this very deeply but I wanted at least to mention it.

Below, a very simple aspect using AspectJ and JAMon (here, the short name of the pointcut will be used for the JAMon monitor, hence the call to 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;
}
}

The pointcut definition could be easily adapted to monitor any method based on the class name, the package name, the method name, or any combination of these. Measurement is really a perfect use case for AOP.

Ответ 3

Your new class:

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

Usage:

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

Afterwards, the time passed can be converted to whatever format you like, with a calender for example

Greetz,
GHad

Ответ 4

tl;dr


for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.


Not possible. If you have only time-of-day, the clock stops at midnight. Without the context of dates, how do we know if you mean 1 AM on the next day, next week, or next decade?

So going from 11 PM to 1 AM means moving backwards in time 22 hours, running the hands of the clock counterclockwise. See the result below, a negative twenty-two hours.

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


Crossing midnight requires the larger context of date in addition to time-of-day (see below).


How do I measure time elapsed in Java?



  1. Capture the current moment in UTC, with Instant.now().

  2. Capture another such moment later.

  3. Pass both to Duration.between.

  4. (a) From the resulting Duration object, extract a number of 24-hour days, hours, minutes, seconds, and fractional second in nanoseconds by calling the various to…Part methods.
    (b) Or, call toString to generate a String in standard ISO 8601 format of PnYnMnDTnHnMnS.

Example code, using pair of Instant objects.

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


New Technology In Java 8+

We have new technology for this now built into Java 8 and later, the java.time framework.

java.time

The java.time framework is defined by JSR 310, inspired by the highly successful Joda-Time project, extended by the ThreeTen-Extra project, and described in the Oracle Tutorial.

The old date-time classes such as java.util.Date/.Calendar bundled with the earliest versions of Java have proven to be poorly designed, confusing, and troublesome. They are supplanted by the java.time classes.

Resolution

Other answers discuss resolution.

The java.time classes have nanosecond resolution, up to nine digits of a decimal fraction of a second. For example, 2016-03-12T04:29:39.123456789Z.

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

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

Время суток

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

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

A 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 отмечает начало (как в 'Period'), а T отделяет любую часть "годы-месяцы-дни" от части "часы-минуты-секунды".

Переход через полночь

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

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

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

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


Дата-время

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

Часовой пояс

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

Если вы определяете дату только по смещению от UTC, используйте a ZoneOffset с a OffsetDateTime. Если у вас есть полный часовой пояс (смещение плюс правила обработки аномалий, таких как переход на летнее время), используйте ZoneId с ZonedDateTime .

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 будут скорректированы по мере необходимости. Подробнее читайте в документе class .


О java.time

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

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

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

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

Где получить классы java.time?


  • Java SE 8, Java SE 9, Java SE 10 и более поздние версии

    • Встроено.

    • Часть стандартного Java API с комплексной реализацией.

    • Java 9 добавляет некоторые незначительные функции и исправления.


  • Java SE 6 и Java SE 7

    • Большая часть функциональности java.time перенесена обратно на Java 6 и 7 в ThreeTen-Backport.


  • Android

    • Более поздние версии Android bundle реализуют классы java.time.

    • Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP ....


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

2023-11-30 16:24 java