Текущее время в микросекундах в Яве
В системе Unix, есть ли способ получить метку времени с точностью до микросекундного уровня в Java? Что-то вроде C gettimeofday
функция.
10 ответов
Нет, у Java нет такой возможности.
Он имеет System.nanoTime(), но он просто дает смещение от некоторого ранее известного времени. Таким образом, хотя вы не можете взять из этого абсолютное число, вы можете использовать его для измерения наносекундной (или более высокой) точности.
Обратите внимание, что JavaDoc говорит, что, хотя это обеспечивает точность наносекунды, это не означает точность наносекунды. Итак, возьмите достаточно большой модуль возвращаемого значения.
ТЛ; др
Java 9 и более поздние версии: разрешение до наносекунд при захвате текущего момента. Это 9 цифр десятичной дроби.
Instant.now()
2017-12-23T12: 34: 56.123456789Z
Чтобы ограничить микросекундами, обрезать.
Instant.now().truncatedTo( ChronoUnit.MICROSECONDS );
2017-12-23T12: 34: 56.123456Z
подробности
Другие ответы несколько устарели с Java 8.
java.time
Java 8 и более поздние версии поставляются с фреймворком java.time. Эти новые классы вытесняют дефектные, проблемные классы даты и времени, поставляемые с самыми ранними версиями Java, такими как java.util.Date/.Calendar и java.text.SimpleDateFormat. Каркас определен JSR 310, вдохновленным Joda-Time, расширенным проектом ThreeTen-Extra.
Классы в java.time разрешаются в наносекунды, намного меньше, чем миллисекунды, используемые старыми классами даты и времени и Joda-Time. И лучше, чем микросекунды, заданные в Вопросе.
Clock
Реализация
Хотя классы java.time поддерживают данные, представляющие значения в наносекундах, классы еще не генерируют значения в наносекундах. now()
методы используют ту же старую реализацию часов, что и старые классы даты и времени, System.currentTimeMillis()
, У нас есть новый Clock
интерфейс в java.time, но реализация для этого интерфейса - те же самые старые часы миллисекунд.
Таким образом, вы можете отформатировать текстовое представление результата ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
чтобы увидеть девять цифр доли секунды, но только первые три цифры будут иметь такие цифры:
2017-12-23T12:34:56.789000000Z
Новые часы на Яве 9
Реализации OpenJDK и Oracle в Java 9 имеют новое значение по умолчанию Clock
реализация с более высокой степенью детализации, вплоть до полной наносекундной способности классов java.time.
См. Вопрос OpenJDK, Повышение точности реализации java.time.Clock.systemUTC (). Эта проблема была успешно реализована.
2017-12-23T12:34:56.123456789Z
На MacBook Pro (Retina, 15-дюймовый, конец 2013 г.) с macOS Sierra я получаю текущий момент в микросекундах (до шести цифр десятичной дроби).
2017-12-23T12:34:56.123456Z
Аппаратные часы
Помните, что даже с новым прекрасным Clock
реализации, ваши результаты могут отличаться в зависимости от компьютера. Java зависит от часов аппаратного обеспечения компьютера, чтобы узнать текущий момент.
- Разрешение аппаратных часов варьируется в широких пределах. Например, если аппаратные часы конкретного компьютера поддерживают только гранулярность микросекунд, любые сгенерированные значения даты и времени будут иметь только шесть цифр дробной секунды, а последние три цифры будут нулями.
- Точность аппаратных часов сильно различается. Просто потому, что часы генерируют значение с несколькими цифрами десятичной доли секунды, эти цифры могут быть неточными, только приблизительные значения, отклоняющиеся от фактического времени, которые могут быть считаны с атомных часов. Другими словами, только то, что вы видите группу цифр справа от десятичной отметки, не означает, что вы можете доверять истекшему времени между такими показаниями, чтобы оно соответствовало этой минутной степени.
Ты можешь использовать System.nanoTime()
:
long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;
чтобы получить время в наносекундах, но это строго относительная мера. Это не имеет абсолютного значения. Это полезно только для сравнения с другими временами нано, чтобы измерить, сколько времени заняло что-то сделать.
Как уже указывалось на других плакатах; Ваши системные часы, вероятно, не синхронизированы с микросекундами с реальным мировым временем. Тем не менее, метки времени с микросекундной точностью полезны как гибрид для отображения текущего времени стены и измерения / профилирования продолжительности событий.
Я отмечаю все события / сообщения, записанные в файлы журнала, используя временные метки, такие как "2012-10-21 19:13:45.267128". Они передают как когда это произошло ("настенное" время), так и могут быть использованы для измерения продолжительности этого и следующего события в файле журнала (относительная разница в микросекундах).
Для этого вам нужно связать System.currentTimeMillis() с System.nanoTime() и работать с System.nanoTime() с этого момента. Пример кода:
/**
* Class to generate timestamps with microsecond precision
* For example: MicroTimestamp.INSTANCE.get() = "2012-10-21 19:13:45.267128"
*/
public enum MicroTimestamp
{ INSTANCE ;
private long startDate ;
private long startNanoseconds ;
private SimpleDateFormat dateFormat ;
private MicroTimestamp()
{ this.startDate = System.currentTimeMillis() ;
this.startNanoseconds = System.nanoTime() ;
this.dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") ;
}
public String get()
{ long microSeconds = (System.nanoTime() - this.startNanoseconds) / 1000 ;
long date = this.startDate + (microSeconds/1000) ;
return this.dateFormat.format(date) + String.format("%03d", microSeconds % 1000) ;
}
}
Вы можете создать компонент, который определяет смещение между System.nanoTime() и System.currentTimeMillis() и эффективно получать наносекунды с начала эпохи.
public class TimerImpl implements Timer {
private final long offset;
private static long calculateOffset() {
final long nano = System.nanoTime();
final long nanoFromMilli = System.currentTimeMillis() * 1_000_000;
return nanoFromMilli - nano;
}
public TimerImpl() {
final int count = 500;
BigDecimal offsetSum = BigDecimal.ZERO;
for (int i = 0; i < count; i++) {
offsetSum = offsetSum.add(BigDecimal.valueOf(calculateOffset()));
}
offset = (offsetSum.divide(BigDecimal.valueOf(count))).longValue();
}
public long nowNano() {
return offset + System.nanoTime();
}
public long nowMicro() {
return (offset + System.nanoTime()) / 1000;
}
public long nowMilli() {
return System.currentTimeMillis();
}
}
Следующий тест дает довольно хорошие результаты на моей машине.
final Timer timer = new TimerImpl();
while (true) {
System.out.println(timer.nowNano());
System.out.println(timer.nowMilli());
}
Разница, кажется, колеблется в диапазоне +-3 мс. Я думаю, что можно было бы немного подправить расчет смещения.
1495065607202174413
1495065607203
1495065607202177574
1495065607203
...
1495065607372205730
1495065607370
1495065607372208890
1495065607370
...
Используйте Instant для вычисления микросекунд с начала эпохи:
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Поддержка Java через микросекунды TimeUnit
ENUM.
Вот документация Java: Enum TimeUnit
Вы можете получить микросекунды в Java следующим образом:
long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
Вы также можете преобразовать микросекунды в другие единицы времени, например:
long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);
"быстрое и грязное" решение, с которым я в конце концов пошел:
TimeUnit.NANOSECONDS.toMicros(System.nanoTime());
ОБНОВИТЬ:
Первоначально я использовал System.nanoTime, но потом обнаружил, что его следует использовать только в течение истекшего времени, в конце концов я изменил свой код для работы с миллисекундами или в некоторых местах:
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
но это только добавит нули в конце значения (micros = миллис * 1000)
Оставьте этот ответ здесь как "предупреждающий знак" на случай, если кто-то еще подумает о nanoTime:)
Если вы интересуетесь Linux: если вы извлечете исходный код в "currentTimeMillis()", вы увидите, что в Linux, если вы вызовете этот метод, он вернется на микросекунду назад. Однако Java затем усекает микросекунды и возвращает вам миллисекунды. Отчасти это связано с тем, что Java должна быть кроссплатформенной, поэтому предоставление методов, специально предназначенных для Linux, было очень сложным задним числом (помните, что поддержка грубых программных ссылок начиная с 1.6 и выше?!). Это также потому, что, хотя ваши часы могут возвращать вам микросекунды в Linux, это не обязательно означает, что это будет хорошо для проверки времени. На микросекундных уровнях вы должны знать, что NTP не перераспределяет ваше время и что ваши часы не слишком сильно сдвигаются во время вызовов методов.
Теоретически это означает, что в Linux вы можете написать оболочку JNI, такую же, как в пакете System, но не обрезать микросекунды.
Если вы собираетесь использовать его для системы реального времени, возможно, java не лучший выбор для получения метки времени. Но если вы собираетесь использовать if для уникального ключа, то ответа Джейсона Смита будет достаточно. Но на всякий случай, чтобы ожидать, что 2 элемента в итоге получат одну и ту же метку времени (это возможно, если эти 2 были обработаны почти одновременно), вы можете выполнить цикл, пока последняя метка времени не будет равна текущей метке времени.
String timestamp = new String();
do {
timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();
Вот пример того, как создать текущую метку времени UnsignedLong:
UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());