Как мне измерить время, прошедшее в 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()
:
long startTime = System.currentTimeMillis();
// ... do something ...
long estimatedTime = System.currentTimeMillis() - startTime;
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.
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;
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.
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
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?
Instant.now()
.Duration.between
.Duration
object, extract a number of 24-hour days, hours, minutes, seconds, and fractional second in nanoseconds by calling the various to…Part
methods.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
We have new technology for this now built into Java 8 and later, the java.time framework.
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.
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
Обратите внимание, что выходные данные по умолчанию 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 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?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательным полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и больше.