Как измерить время, прошедшее на Java?
Я хочу иметь что-то вроде этого:
public class Stream { public startTime; public endTime; public getDuration() { return startTime - endTime; } }
Также важно, чтобы, например, если startTime это 23:00 и endTime 1:00, чтобы получить продолжительность 2:00.
Какие типы использовать для выполнения этого в Java?
- Как остановить выполнение через определенное время в Java?
- Как я могу найти количество секунд, прошедших с полуночи с Java?
- Рассчитать разницу во времени / времени в java
- Как измерить время с точностью до микросекунды в Java?
- Проблема с Android, выясняя, как последнее последнее исправление GPS
К сожалению, ни один из десяти ответов, опубликованных до сих пор, не является правильным.
Если вы измеряете прошедшее время и хотите, чтобы оно было правильным , вы должны использовать System.nanoTime()
. Вы не можете использовать System.currentTimeMillis()
, если только вы не возражаете, чтобы ваш результат был неправильным.
objective nanoTime
– измерять прошедшее время, а цель currentTimeMillis
– измерять время настенных часов . Вы не можете использовать его для других целей. Причина в том, что часы компьютера не идеальны; он всегда дрейфует и иногда нуждается в исправлении. Эта коррекция может произойти вручную, или, в случае большинства машин, есть процесс, который выполняется и постоянно выдает небольшие исправления системным часам («настенные часы»). Они часто случаются. Другая такая коррекция происходит всякий раз, когда есть прыжок второй.
Поскольку nanoTime
состоит в том, чтобы измерить прошедшее время, на нее не влияет какая-либо из этих небольших поправок. Это то, что вы хотите использовать. Любые тайминги, которые в настоящее время currentTimeMillis
с currentTimeMillis
будут отключены – возможно, даже отрицательными.
Вы можете сказать: «Это не звучит так, как будто это действительно так важно», на что я говорю, может быть, нет, но в целом, это не правильный код, который лучше, чем неправильный код? Кроме того, в любом случае nanoTime
короче.
Ранее опубликованные заявления об отказе от nanoTime
обычно имеют только микросекундную точность. Также может потребоваться больше, чем целая микросекунда для вызова, в зависимости от обстоятельств (как и другая), поэтому не ожидайте времени очень очень малых интервалов правильно.
Какие типы использовать для выполнения этого в Java?
Короткий ответ long
. Теперь, больше о том, как измерить …
System.currentTimeMillis ()
«Традиционный» способ сделать это – действительно использовать System.currentTimeMillis()
:
long startTime = System.currentTimeMillis(); // ... do something ... long estimatedTime = System.currentTimeMillis() - startTime;
oacltStopWatch
Обратите внимание, что Commons Lang имеет class StopWatch, который может использоваться для измерения времени выполнения в миллисекундах. Он имеет методы, такие как split()
, suspend()
, resume()
и т. Д., Которые позволяют принимать меры в разных точках исполнения и могут оказаться удобными. Посмотри на это.
System.nanoTime ()
Вы можете предпочесть использовать System.nanoTime()
если вы ищете чрезвычайно точные измерения прошедшего времени. Из его javadoc:
long startTime = System.nanoTime(); // ... the code being measured ... long estimatedTime = System.nanoTime() - startTime;
Хамон
Другой вариант – использовать JAMon , инструмент, который собирает статистику (время выполнения, количество ударов, среднее время выполнения, min, max и т. Д.) Для любого кода, который приходит между методами start () и stop (). Ниже, очень простой пример:
import com.jamonapi.*; ... Monitor mon=MonitorFactory.start("myFirstMonitor"); ...Code Being Timed... mon.stop();
Ознакомьтесь с этой статьей на http://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 может быть легко адаптировано для мониторинга любого метода, основанного на имени classа, имени пакета, имени метода или любой их комбинации. Измерение действительно является идеальным вариантом для АОП.
Ваш новый 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); } }
Применение:
TimeWatch watch = TimeWatch.start(); // do something long passedTimeInMs = watch.time(); long passedTimeInSeconds = watch.time(TimeUnit.SECONDS);
После этого прошедшее время может быть преобразовано в любой формат, например, с каландром
Greetz, GHad
Если целью является просто напечатать грубую информацию о времени в ваших журналах программ, то простым решением для проектов Java не является создание собственных classов секундомера или таймера, но просто используйте class 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);
ТЛ; др
например, если startTime это 23:00 и endTime 1:00, чтобы получить продолжительность 2:00.
Невозможно. Если у вас есть только время суток, часы останавливаются в полночь. Без контекста дат, как мы узнаем, если вы имеете в виду 1 AM на следующий день, на следующей неделе или в следующее десятилетие?
Таким образом, с 11: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?
- Захватите текущий момент в UTC, с помощью
Instant.now()
. - Захватите другой такой момент позже.
- Переходите к
Duration.between
. - (a) Из результирующего объекта
Duration
выведите несколько 24-часовых дней, часов, минут, секунд и дробную секунду в наносекундах, вызвав различные методыto…Part
.
(b) Или вызовитеtoString
для генерацииString
в стандартном формате ISO 8601PnYnMnDTnHnMnS
.
Пример кода, используя пару 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 , вдохновленная очень успешным проектом Joda-Time , дополненным проектом ThreeTen-Extra и описанным в учебнике Oracle .
Старые classы времени, такие как java.util.Date/.Calendar в комплекте с самыми ранними версиями Java, оказались плохо спроектированными, запутанными и сложными. Они вытесняются classами java.time.
разрешение
Другие ответы обсуждают решение.
Классы java.time имеют наносекундное разрешение, до девяти цифр десятичной доли секунды. Например, 2016-03-12T04:29:39.123456789Z
.
И старые classы java.util.Date/.Calendar, и classы Joda-Time имеют миллисекундное разрешение (3 цифры дроби). Например, 2016-03-12T04:29:39.123Z
.
В Java 8 текущий момент выбирается с точностью до миллисекунды из-за устаревшей проблемы. В Java 9 и более поздних версиях текущее время может быть определено с точностью до наносекунды при условии, что часы вашего компьютера будут работать так точно.
Time-of-Day
Если вы действительно хотите работать только с отсутствием какой-либо даты или часового пояса, используйте class 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
обозначает начало (как в «Периоде»), а 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 , используйте ZoneOffset
с параметром 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) или другая такая аномалия, classы java.time будут настраиваться по мере необходимости. Прочтите документ classа для получения более подробной информации.
О java.time
Рамка java.time встроена в Java 8 и более поздние версии . Эти classы вытесняют неприятные старые устаревшие classы времени, такие как java.util.Date
, Calendar
и SimpleDateFormat
.
Проект Joda-Time , теперь в режиме обслуживания , советует перейти на classы java.time .
Чтобы узнать больше, ознакомьтесь с учебным пособием Oracle . И поиск Stack Overflow для многих примеров и объяснений. Спецификация – JSR 310 .
Вы можете обменивать объекты java.time непосредственно с вашей базой данных. Используйте JDBC-драйвер, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.*
.
Где можно получить classы 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 classов java.time.
- Для более ранних Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). См. Раздел Как использовать ThreeTenABP ….
Проект ThreeTen-Extra расширяет java.time с дополнительными classами. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные classы, такие как Interval
, YearWeek
, YearQuarter
и другие .
Java предоставляет статический метод System.currentTimeMillis()
. И это возвращает большую ценность, поэтому это хорошая рекомендация. Многие другие classы принимают параметр timeInMillis, который также длинный.
И многим людям проще использовать библиотеку времени Joda для выполнения расчетов по датам и времени.
Какие типы использовать для выполнения этого в 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. Он содержит class интервалов, подходящий для того, что вам нужно.
Стоит отметить, что
- System.currentTimeMillis () в лучшем случае имеет только миллисекундную точность. При достоинстве может быть 16 мс на некоторых системах Windows. Он имеет более низкую стоимость, чем альтернативы <200 нс.
- System.nanoTime () является только микросекундой, точной для большинства систем, и может работать на системах Windows на 100 микросекунд (т.е. иногда это не так точно, как кажется)
- Календарь – очень дорогой способ рассчитать время. (я могу думать, кроме XMLGregorianCalendar). Иногда это наиболее подходящее решение, но помните, что вам нужно только длительные интервалы времени.
Если вы пишете приложение, которое должно иметь дело с продолжительностью времени, пожалуйста, взгляните на Joda-Time, который имеет class специально для обработки продолжительности, интервалов и периодов. Ваш 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); }
Если вы предпочитаете использовать Java Calendar API, вы можете попробовать это,
Date startingTime = Calendar.getInstance().getTime(); //later on Date now = Calendar.getInstance().getTime(); long timeElapsed = now.getTime() - startingTime.getTime();
Если вы получаете временные метки из System.currentTimeMillis()
, то ваши временные переменные должны быть длинными.
Byte Stream Reader Elapsed Time for 23.7 MB is 96 secs import java.io.*; import java.io.IOException; import java.util.Scanner; class ElaspedTimetoCopyAFileUsingByteStream { private long startTime = 0; private long stopTime = 0; private boolean running = false; public void start() { this.startTime = System.currentTimeMillis(); this.running = true; } public void stop() { this.stopTime = System.currentTimeMillis(); this.running = false; } public long getElapsedTime() { long elapsed; if (running) { elapsed = (System.currentTimeMillis() - startTime); } else { elapsed = (stopTime - startTime); } return elapsed; } public long getElapsedTimeSecs() { long elapsed; if (running) { elapsed = ((System.currentTimeMillis() - startTime) / 1000); } else { elapsed = ((stopTime - startTime) / 1000); } return elapsed; } public static void main(String[] args) throws IOException { ElaspedTimetoCopyAFileUsingByteStream s = new ElaspedTimetoCopyAFileUsingByteStream(); s.start(); FileInputStream in = null; FileOutputStream out = null; try { in = new FileInputStream("vowels.txt"); // 23.7 MB File out = new FileOutputStream("output.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } }finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } s.stop(); System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs()); } } [Elapsed Time for Byte Stream Reader][1] **Character Stream Reader Elapsed Time for 23.7 MB is 3 secs** import java.io.*; import java.io.IOException; import java.util.Scanner; class ElaspedTimetoCopyAFileUsingCharacterStream { private long startTime = 0; private long stopTime = 0; private boolean running = false; public void start() { this.startTime = System.currentTimeMillis(); this.running = true; } public void stop() { this.stopTime = System.currentTimeMillis(); this.running = false; } public long getElapsedTime() { long elapsed; if (running) { elapsed = (System.currentTimeMillis() - startTime); } else { elapsed = (stopTime - startTime); } return elapsed; } public long getElapsedTimeSecs() { long elapsed; if (running) { elapsed = ((System.currentTimeMillis() - startTime) / 1000); } else { elapsed = ((stopTime - startTime) / 1000); } return elapsed; } public static void main(String[] args) throws IOException { ElaspedTimetoCopyAFileUsingCharacterStream s = new ElaspedTimetoCopyAFileUsingCharacterStream(); s.start(); FileReader in = null; // CharacterStream Reader FileWriter out = null; try { in = new FileReader("vowels.txt"); // 23.7 MB out = new FileWriter("output.txt"); int c; while ((c = in.read()) != -1) { out.write(c); } }finally { if (in != null) { in.close(); } if (out != null) { out.close(); } } s.stop(); System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs()); } } [Elapsed Time for Character Stream Reader][2] [1]: http://sofru.miximages.com/time/hYo8y.png [2]: http://sofru.miximages.com/time/xPjCK.png
Я нашел этот код полезным при выборе времени:
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; }
Использовать это:
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» может получить правильную
Я построил функцию форматирования, основанную на материалах, которые я украл SO. Мне нужен способ «профилирования» в сообщениях журнала, поэтому мне понадобилось сообщение продолжительностью продолжительной длины.
public static String GetElapsed(long aInitialTime, long aEndTime, boolean aIncludeMillis) { StringBuffer elapsed = new StringBuffer(); Map units = new HashMap(); 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); }
И тестовый class:
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)); } }