Текущее время в микросекундах в java
В системе Unix существует ли способ получить метку времени с точностью до микросекундного уровня в Java? Что-то вроде функции C gettimeofday
.
Ответы
Ответ 1
Нет, у Java нет этой способности.
У этого есть System.nanoTime(), но это только дает смещение от некоторого ранее известного времени. Поэтому, пока вы не можете взять абсолютное число из этого, вы можете использовать его для измерения точности наносекунд (или выше).
Обратите внимание, что JavaDoc говорит, что, хотя это обеспечивает точность наносекунды, это не означает точности наносекунд. Поэтому возьмите некоторый достаточно большой модуль возвращаемого значения.
Ответ 2
ТЛ; др
Java 9 и более поздние версии: разрешение до наносекунд при захвате текущего момента. Это 9 цифр десятичной дроби.
Instant.now()
2017-12-23T12: 34: 56.123456789Z
Чтобы ограничить микросекундами, обрезать.
Instant // Represent a moment in UTC.
.now() // Capture the current moment. Returns a 'Instant' object.
.truncatedTo( // Lop off the finer part of this moment.
ChronoUnit.MICROS // Granularity to which we are truncating.
) // Returns another 'Instant' object rather than changing the original, per the immutable objects pattern.
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
реализацией Clock
ваши результаты могут отличаться в зависимости от компьютера. Java зависит от базовых аппаратных часов компьютера, чтобы знать текущий момент.
- Разрешение аппаратных часов варьируется в широких пределах. Например, если аппаратные часы конкретного компьютера поддерживают только гранулярность микросекунд, любые сгенерированные значения даты и времени будут иметь только шесть цифр дробной секунды, а последние три цифры будут нулями.
- Точность аппаратных часов сильно различается. Просто потому, что часы генерируют значение с несколькими цифрами десятичной доли секунды, эти цифры могут быть неточными, всего лишь приблизительными, отклоненными от фактического времени, которые могут быть считаны с атомных часов. Другими словами, только то, что вы видите группу цифр справа от десятичной отметки, не означает, что вы можете доверять истекшему времени между такими показаниями, чтобы оно соответствовало этой минутной степени.
Ответ 3
Вы можете использовать System.nanoTime()
:
long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;
чтобы получить время в наносекундах, но это строго относительная мера. Это не имеет никакого значения. Это полезно только для сравнения с другими нано-временами, чтобы определить, сколько времени нужно делать.
Ответ 4
Как уже указывали другие плакаты; ваши системные часы, вероятно, не синхронизированы до микросекунд до фактического мирового времени. Тем не менее, микросекундные временные метки времени полезны в качестве гибрида как для обозначения текущего времени стены, так и для измерения/профилирования продолжительности вещей.
Я помещаю все события/сообщения, записанные в файлы журнала, используя отметки времени, такие как "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) ;
}
}
Ответ 5
Если вы заинтересованы в Linux:
Если вы выкидываете исходный код "currentTimeMillis()", вы увидите, что в Linux, если вы вызовете этот метод, он получит микросекундное время назад. Однако Java затем обрезает микросекунды и передает вам миллисекунды. Отчасти это связано с тем, что Java должна быть кросс-платформой, поэтому предоставление методов, специально предназначенных для Linux, было большим нет-назад в тот же день (помните, что грубая поддержка софт-ссылок от 1.6 назад!). Это также потому, что, пока вы можете дать вам микросекунды в Linux, это не обязательно означает, что это будет полезно для проверки времени. На микросекундных уровнях вам нужно знать, что NTP не перестраивает ваше время и что ваши часы не слишком сильно дрейфовали во время вызовов методов.
Это означает, что теоретически в Linux вы можете написать оболочку JNI, такую же, как в системном пакете, но не усекать микросекунды.
Ответ 6
"быстрое и грязное" решение, с которым я в конечном итоге пошел:
TimeUnit.NANOSECONDS.toMicros(System.nanoTime());
UPDATE:
Я изначально пошел с System.nanoTime, но потом выяснилось, что он должен использоваться только в течение прошедшего времени, я в конечном итоге изменил свой код на работу с миллисекундами или в некоторых местах:
TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
но это просто добавит нули в конце значения (micros = millis * 1000)
Оставите этот ответ здесь как "предупреждающий знак", если кто-то еще подумает о nanoTime:)
Ответ 7
Поддержка микросекунд Java через TimeUnit
перечисление.
Вот документ java:
Enum TimeUnit
Вы можете получить микросекунды в java следующим образом:
long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
Вы также можете преобразовать микросекунды обратно в другие единицы времени, например:
long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);
Ответ 8
Возможно, вы можете создать компонент, который определяет смещение между 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
...
Ответ 9
Если вы собираетесь использовать его для системы реального времени, возможно, java не лучший выбор для получения метки времени. Но если вы собираетесь использовать, если для уникального ключа, то ответ Джейсона Смита будет достаточно. Но на всякий случай, чтобы ожидать, что 2 элемента получат одну и ту же метку времени (возможно, если эти 2 были обработаны почти одновременно), вы можете зацикливаться до тех пор, пока последняя метка времени не будет равна текущей временной отметке.
String timestamp = new String();
do {
timestamp = String.valueOf(MicroTimestamp.INSTANCE.get());
item.setTimestamp(timestamp);
} while(lasttimestamp.equals(timestamp));
lasttimestamp = item.getTimestamp();
Ответ 10
Используйте Instant для вычисления микросекунд с начала эпохи:
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Ответ 11
Вот пример того, как создать временную метку UnsignedLong:
UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());