Текущее время в микросекундах в java

105

В системе Unix есть ли способ получить метку времени с точностью до микросекунд в Java? Что-то вроде gettimeofdayфункции C.

Сет
источник
6
Имейте в виду, что компьютерные часы не настроены на какой-либо уровень точности - два часа на разных компьютерах обычно будут отличаться по крайней мере на несколько миллисекунд, если вы не приложили некоторых усилий для настройки процедуры высокоточной синхронизации. (когда такое возможно даже физически). Я не могу себе представить, какой смысл знать время компьютера с точностью до микросекунды. (Если вы пытаетесь измерить интервал точно на одном компьютере, тогда, конечно, это вполне разумно, но вам не нужна полная временная метка.)
Дэвид З
2
Кроме того, некоторые версии Unix / Linux возвращают только 1 миллисекунду или 10 миллисекунду в поле микросекунды.
Stephen C
Косвенным способом является JDBC , если он подключен к базе данных, такой как Postgres, которая фиксирует текущее время в микросекундах.
Basil Bourque
2
Java 9 и новее:Instant.now()
Basil
Используйте Instant для вычисления микросекунд с момента Epoch: val instant = Instant.now(); val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Майкл М.

Ответы:

149

Нет, у Java такой возможности нет.

У него есть System.nanoTime (), но он просто дает смещение от некоторого ранее известного времени. Таким образом, хотя вы не можете извлечь из этого абсолютное число, вы можете использовать его для измерения наносекундной (или более высокой) точности.

Обратите внимание, что в JavaDoc говорится, что хотя это обеспечивает точность в наносекунду, это не означает точность в наносекунду. Итак, возьмите какой-нибудь достаточно большой модуль возвращаемого значения.

AlBlue
источник
3
Можно было бы предположить, что причины, по которым Java не имеет getTimeInMicroseconds (), включают: 1) точность, недоступную на многих платформах, 2) возврат миллисекундной точности в микросекундном вызове, приводит к проблемам с переносимостью приложения.
Stephen C
9
В Linux System.nanoTime () вызывает clock_gettime (CLOCK_MONOTONIC, _). Брайан Оксли покопался в исходном коде Java, чтобы найти этот самородок.
Дэвид Вебер
8
Этот ответ уже устарел . Реализации Java 9 в OpenJDK и Oracle поставляются с новой реализацией, Clockкоторая обеспечивает захват текущего момента с разрешением меньше миллисекунд. На MacBook Pro Retina я получаю текущее время в микросекундах (шесть цифр десятичной дроби). Фактические результаты и точность зависят от базового тактового оборудования главного компьютера.
Basil
1
@BasilBourque: многие системы все еще работают на Java 8 или даже более ранней версии, поскольку нет необходимости их переносить. Хотя ответ устарел, он все еще полезен.
Драгас
1
@Dragas На самом деле, было бы необходимо перенести их ... чтобы получить текущее время в микросекундах , как задал этот вопрос.
Basil
81

tl; dr

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

На практике вы увидите только микросекунды, захваченные с помощью .nowсовременных обычных компьютерных аппаратных часов, неточности в наносекундах .

подробности

Другие ответы несколько устарели с 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

Новые часы в Java 9

Реализации Java 9 в OpenJDK и Oracle имеют новую 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.currentTimeMillis, поэтому они просто добавляют кучу нулей в конце. Совсем не помогает, если вы пытаетесь получить время в микро / нано секундах, пользователь может просто вручную добавить нули к времени миллисекунды.
annedroiid
@annedroiid Я рассказал об этом в своем ответе. В Java 8 вы можете сохранять моменты с разрешением наносекунды, но запись текущего момента осуществляется только в миллисекундах. Исправлено в Java 9 с помощью новой реализации Clock. Даже в этом случае в Java 8 классы java.time полезны для хранения значений, полученных из других источников, таких как микросекунды, в базе данных Postgres. Но остерегайтесь неточности значений в диапазоне микросекунд и наносекунд; обычное компьютерное оборудование может не обеспечивать точное отслеживание времени аппаратных часов. Значение с шестью или девятью цифрами дробной секунды может быть неверным.
Basil Bourque
Разве это не ChronoUnit.MICROS ?
Роланд
@Roland Да, теперь исправлено, спасибо. К вашему сведению, в Stack Overflow вам предлагается напрямую отредактировать ответ, чтобы исправить такую ​​ошибку.
Basil Bourque
55

Вы можете использовать System.nanoTime():

long start = System.nanoTime();
// do stuff
long end = System.nanoTime();
long microseconds = (end - start) / 1000;

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

Cletus
источник
14

Как уже указывалось на других плакатах; ваши системные часы, вероятно, не синхронизированы с текущим мировым временем с точностью до микросекунд. Тем не менее, это временные метки с точностью до микросекунд, которые можно использовать как гибрид как для индикации текущего времени на стене, так и для измерения / профилирования продолжительности событий.

Я помечаю все события / сообщения, записанные в файлы журнала, с помощью временных меток, например «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
Идея хороша, но вы должны время от времени выполнять повторную синхронизацию. Системное время (currentTime) и часы процессора (nanoTime) НЕ синхронизированы, поскольку они часто основаны на разных аппаратных часах. Кроме того, сервер времени вашей операционной системы повторно синхронизирует системные часы с внешним источником времени, если он доступен. Следовательно, ваш, казалось бы, очень точный класс будет производить отметки времени, которые могут быть далекими!
h2stein
3
Этот код не кажется потокобезопасным. Два одновременных вызова MicroTimestamp.INSTANCE.get()могут быть проблематичными.
Ахмед
@Ahmed Как вы думаете, почему код не является потокобезопасным? В get()методе нет ничего, что обновляло бы переменные-члены; он использует только временные локальные переменные.
Джейсон Смит
6

Возможно, вы могли бы создать компонент, который определяет смещение между 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
...
Kangcz
источник
2

Если вас интересует Linux: если вы извлечете исходный код для «currentTimeMillis ()», вы увидите, что в Linux, если вы вызовете этот метод, он вернется на микросекунду назад. Однако Java затем усекает микросекунды и возвращает вам миллисекунды. Отчасти это связано с тем, что Java должна быть кроссплатформенной, поэтому предоставление методов специально для Linux было большим запретом в те времена (помните, что грубая поддержка софт-ссылок с версии 1.6 назад ?!). Это еще и потому, что, хотя ваши часы могут возвращать вам микросекунды в Linux, это не обязательно означает, что они подходят для проверки времени. На уровне микросекунд вам необходимо знать, что NTP не корректирует ваше время и что ваши часы не слишком сильно отклоняются во время вызовов методов.

Это означает, что теоретически в Linux вы можете написать оболочку JNI, такую ​​же, как в пакете System, но не усекать микросекунды.

замхассам
источник
2

«быстрое и грязное» решение, которое я в итоге выбрал:

TimeUnit.NANOSECONDS.toMicros(System.nanoTime());

ОБНОВИТЬ:

Первоначально я выбрал System.nanoTime, но затем я обнаружил, что его следует использовать только в течение прошедшего времени, в конечном итоге я изменил свой код, чтобы он работал с миллисекундами или в некоторых местах использовал:

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

но это просто добавит нули в конце значения (микрос = миллис * 1000)

Оставил этот ответ здесь как «предупреждающий знак» на случай, если кто-то еще подумает о nanoTime :)

Кейсар
источник
1
Документ явно говорит не использовать System.nanoTimeдля времени настенных часов: «Этот метод может быть использован только для измерения затраченного времени и не связан с каким - либо другим понятием системы или времени на стену часов.»
Basil Bourque
1
@BasilBourque, вы правы, написав это, я в конце концов узнал и изменил свой код, но забыл обновить здесь, спасибо за комментарий!
keisar 03
2

Поддержка микросекунд Java через TimeUnitenum.

Вот java-документ: Enum TimeUnit

Вы можете получить микросекунды в java следующим образом:

long microsenconds = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

Вы также можете преобразовать микросекунды обратно в другие единицы времени, например:

long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds);
Тангао
источник
Это неверно, вы получите время в разрешении / длине MICRO, но само время всегда будет только с точностью MILI (то есть последние 3 цифры всегда будут равны 0).
Михалс,
0

Если вы собираетесь использовать его для системы реального времени, возможно, 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();
крылатая корона
источник
0

Используйте Instant для вычисления микросекунд с момента Epoch:

val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Майкл М.
источник
0
LocalDateTime.now().truncatedTo(ChronoUnit.MICROS)
Walkeros
источник
-3

Вот пример того, как создать текущую метку времени UnsignedLong:

UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());
четыре глаза
источник
2
Неправильный ответ. Класс java.util.Date имеет разрешение в миллисекунды, а не микросекунды, указанные в вопросе. Создание java.sql.Timestamp не приводит к извлечению дополнительных данных из воздуха.
Basil Bourque