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

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


person Seth    schedule 11.11.2009    source источник
comment
Имейте в виду, что компьютерные часы не настроены на такой уровень точности - два часа на разных компьютерах обычно будут отличаться по крайней мере на несколько миллисекунд, если вы не приложили некоторых усилий для настройки процедуры высокоточной синхронизации. (когда такое возможно даже физически). Я не могу себе представить, какой смысл знать время компьютера с точностью до микросекунды. (Если вы пытаетесь измерить интервал точно на одном компьютере, тогда, конечно, это вполне разумно, но вам не нужна полная временная метка.)   -  person David Z    schedule 11.11.2009
comment
Кроме того, некоторые версии Unix / Linux возвращают только 1 миллисекунду или 10 миллисекунд детализации в поле микросекунды.   -  person Stephen C    schedule 11.11.2009
comment
Косвенный способ - через JDBC, если он подключен к базе данных, такой как Postgres, которая фиксирует текущие время в микросекундах.   -  person Basil Bourque    schedule 03.03.2016
comment
Java 9 и новее: Instant.now()   -  person Basil Bourque    schedule 08.11.2017
comment
Используйте Instant для вычисления микросекунд с начала эпохи: val instant = Instant.now(); val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;   -  person Michael M.    schedule 25.04.2019


Ответы (11)


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

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

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

person AlBlue    schedule 11.11.2009
comment
Можно предположить, что причины, по которым Java не имеет getTimeInMicroseconds (), включают: 1) точность, недоступную на многих платформах, 2) возврат миллисекундной точности в микросекундном вызове приводит к проблемам с переносимостью приложения. - person Stephen C; 11.11.2009
comment
В Linux System.nanoTime () вызывает clock_gettime (CLOCK_MONOTONIC, _). Брайан Оксли покопался в исходном коде Java, чтобы найти этот самородок. - person David Weber; 12.08.2014
comment
Есть ли способ использовать clock_gettime (CLOCK_MONOTONIC, _) самостоятельно в своем Java-коде? - person annedroiid; 21.09.2016
comment
Хорошо бы написать, в чем разница между точностью и аккуратностью. - person Krzysztof Krasoń; 19.07.2017
comment
Этот ответ устарел. Реализации Java 9 в OpenJDK и Oracle поставляются с новой реализацией Clock, который позволяет запечатлеть текущий момент с разрешением меньше миллисекунд. На MacBook Pro Retina я получаю текущее время в микросекундах (шесть цифр десятичной дроби). Фактические результаты и точность зависят от основного тактового оборудования главного компьютера. - person Basil Bourque; 08.11.2017
comment
@BasilBourque: многие системы все еще работают на Java 8 или даже более ранней версии, поскольку нет необходимости их переносить. Хотя ответ устарел, он все еще полезен. - person Dragas; 26.04.2019
comment
@Dragas На самом деле, может их перенести ... чтобы получить текущее время в микросекундах, как задано в этом Вопросе. - person Basil Bourque; 26.04.2019

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 framework. Эти новые классы заменяют ошибочные и проблемные классы времени и даты, поставляемые с самыми ранними версиями Java, такими как java.util.Date/.Calendar и java.text.SimpleDateFormat. Фреймворк определяется JSR 310, вдохновленным Joda-Time, расширенным ThreeTen-Extra проект.

Классы в java.time разрешаются в наносекундах, что намного меньше, чем миллисекунды, используемые как старыми классами даты и времени, так и Joda-Time. И лучше, чем микросекунды, указанные в Вопросе.

введите описание изображения здесь

Clock Реализация

Хотя классы java.time поддерживают данные, представляющие значения в наносекундах, классы еще не генерируют значения в наносекундах. В методах now() используется та же старая реализация часов, что и в старых классах даты и времени, _ 6_. У нас есть новый интерфейс 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 зависит от часов базового компьютерного оборудования, чтобы узнать текущий момент.

  • Разрешение аппаратных часов сильно различается. Например, если аппаратные часы конкретного компьютера поддерживают детализацию только микросекунд, любые сгенерированные значения даты и времени будут имеют только шесть цифр дробной секунды, причем последние три цифры нули.
  • Точность аппаратных часов сильно различается. Просто потому, что часы генерируют значение с несколькими цифрами десятичной доли секунды, эти цифры могут быть неточными, просто приблизительными, дрейфующими от фактического времени, как можно было бы прочитать из атомные часы. Другими словами, то, что вы видите группу цифр справа от десятичного знака, не означает, что вы можете быть уверены, что время, прошедшее между такими показаниями, будет верным до этой минутной степени.
person Basil Bourque    schedule 04.02.2016
comment
Они могут разрешаться в наносекунды, но они все еще основаны на System.currentTimeMillis, поэтому они просто добавляют кучу нулей в конце. Совсем не помогает, если вы пытаетесь получить время в микро / нано секундах, пользователь может просто вручную добавить нули к времени миллисекунды. - person annedroiid; 20.09.2016
comment
@annedroiid Я рассказал об этом в своем ответе. В Java 8 вы можете хранить моменты с разрешением наносекунды, но захват текущего момента осуществляется только в миллисекундах. Исправлено в Java 9 с новой реализацией Clock. Даже в этом случае в Java 8 классы java.time полезны для хранения значений, полученных из других источников, таких как микросекунды, в базе данных Postgres. Но будьте осторожны с неточностью значений в диапазоне микросекунд и наносекунд; обычное компьютерное оборудование может не обеспечивать точное отслеживание времени аппаратных часов. Значение с шестью или девятью цифрами дробной секунды может быть неверным. - person Basil Bourque; 20.09.2016
comment
@Roland Да, теперь исправлено, спасибо. К вашему сведению, в Stack Overflow вам предлагается напрямую отредактировать ответ, чтобы исправить такую ​​ошибку. - person Basil Bourque; 03.12.2018

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

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

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

person cletus    schedule 11.11.2009

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

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

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

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

val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
person Michael M.    schedule 25.04.2019

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

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

person zamhassam    schedule 31.12.2014

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

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

ОБНОВИТЬ:

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

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

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

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

person keisar    schedule 14.10.2015
comment
doc прямо говорит, чтобы не использовать System.nanoTime для времени настенных часов: «Этот метод может использоваться только для измерения прошедшего времени и не связан с каким-либо другим понятием системного времени или времени настенных часов». - person Basil Bourque; 03.11.2015
comment
@BasilBourque, вы правы, написав это, я в конце концов узнал и изменил свой код, но забыл обновить здесь, спасибо за комментарий! - person keisar; 03.11.2015

Java поддерживает микросекунды через TimeUnit enum.

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

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

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

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

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

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

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

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