Hora actual en microsegundos en java

En un sistema Unix, ¿hay alguna forma de obtener una marca de tiempo con precisión de nivel de microsegundo en Java? Algo así como la función gettimeofday de C.

No, Java no tiene esa habilidad.

Tiene System.nanoTime (), pero eso solo da un desplazamiento de un tiempo previamente conocido. Entonces, aunque no puede tomar el número absoluto de esto, puede usarlo para medir la precisión de nanosegundos (o más).

Tenga en cuenta que el JavaDoc dice que, si bien esto proporciona una precisión de nanosegundos, eso no significa una precisión de nanosegundos. Por lo tanto, tome un módulo adecuadamente grande del valor de retorno.

Puede usar System.nanoTime() :

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

para obtener tiempo en nanosegundos, pero es una medida estrictamente relativa. No tiene un significado absoluto. Solo es útil para comparar con otros nanosegundos medir cuánto tiempo tardo en hacer algo.

tl; dr

Java 9 y posterior: Hasta una resolución de nanosegundos al capturar el momento actual. Eso es 9 dígitos de fracción decimal.

 Instant.now() 

2017-12-23T12: 34: 56.123456789Z

Para limitar a microsegundos, truncar.

 Instant.now().truncatedTo( ChronoUnit.MICROSECONDS ); 

2017-12-23T12: 34: 56.123456Z

Detalles

Las otras respuestas están algo anticuadas a partir de Java 8.

java.time

Java 8 y versiones posteriores vienen con el framework java.time . Estas nuevas clases suplantan a las problemáticas clases de fecha y hora enviadas con las primeras versiones de Java, como java.util.Date/.Calendar y java.text.SimpleDateFormat. El marco está definido por JSR 310, inspirado en Joda-Time , extendido por el proyecto ThreeTen-Extra.

Las clases en java.time se resuelven en nanosegundos , mucho más finos que los milisegundos utilizados por las antiguas clases de fecha y hora y por Joda-Time. Y más fino que los microsegundos preguntados en la Pregunta.

enter image description here

Implementación del Clock

Si bien las clases java.time admiten datos que representan valores en nanosegundos, las clases aún no generan valores en nanosegundos. Los métodos now() usan la misma implementación de reloj antigua que las antiguas clases de fecha y hora, System.currentTimeMillis() . Tenemos la nueva interfaz de Clock en java.time pero la implementación para esa interfaz es el mismo viejo reloj de milisegundos.

Entonces, podría formatear la representación textual del resultado de ZonedDateTime.now( ZoneId.of( "America/Montreal" ) ) para ver nueve dígitos de una fracción de segundo, pero solo los primeros tres dígitos tendrán números como este:

2017-12-23T12:34:56.789000000Z

Nuevo reloj en Java 9

Las implementaciones OpenJDK y Oracle de Java 9 tienen una nueva implementación de Clock predeterminada con granularidad más fina, hasta la capacidad máxima de nanosegundo de las clases java.time.

Ver el problema OpenJDK, boost la precisión de la implementación de java.time.Clock.systemUTC () . Ese problema se ha implementado con éxito.

2017-12-23T12:34:56.123456789Z

En una MacBook Pro (Retina, 15 pulgadas, finales de 2013) con macOS Sierra, obtengo el momento actual en microsegundos (hasta seis dígitos de fracción decimal).

2017-12-23T12:34:56.123456Z

Reloj de hardware

Recuerde que incluso con una nueva implementación de Clock más fina, sus resultados pueden variar según la computadora. Java depende del reloj del hardware subyacente de la computadora para conocer el momento actual.

  • La resolución de los relojes de hardware varía ampliamente. Por ejemplo, si el reloj de hardware de una computadora en particular solo admite microsegundos de granularidad, los valores de fecha y hora generados tendrán solo seis dígitos de fracción de segundo y los últimos tres dígitos serán ceros.
  • La precisión de los relojes de hardware varía ampliamente. El hecho de que un reloj genere un valor con varios dígitos de fracción decimal de un segundo, esos dígitos pueden ser inexactos, solo aproximaciones, a la deriva del tiempo real como podría leerse en un reloj atómico . En otras palabras, solo porque vea un grupo de dígitos a la derecha de la marca decimal no significa que pueda confiar en que el tiempo transcurrido entre dichas lecturas será verdadero hasta ese grado de minuto.

Como otros carteles ya indicaron; el reloj del sistema probablemente no esté sincronizado hasta microsegundos con el tiempo mundial real. No obstante, hay marcas de tiempo de precisión de microsegundos útiles como híbrido para indicar el tiempo de pared actual y medir / perfilar la duración de las cosas.

Etiqueto todos los eventos / mensajes escritos en un archivo de registro usando marcas de tiempo como “2012-10-21 19: 13: 45.267128”. Estos transmiten tanto cuándo sucedió (tiempo de “pared”), y también se pueden usar para medir la duración entre este y el próximo evento en el archivo de registro (diferencia relativa en microsegundos).

Para lograr esto, debe vincular System.currentTimeMillis () con System.nanoTime () y trabajar exclusivamente con System.nanoTime () a partir de ese momento. Código de ejemplo:

 /** * 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) ; } } 

Si estás interesado en Linux: si pescas el código fuente en “currentTimeMillis ()”, verás que, en Linux, si llamas a este método, se recupera en un microsegundo. Sin embargo, Java trunca los microsegundos y te devuelve milisegundos. Esto se debe en parte a que Java tiene que ser multiplataforma, por lo que proporcionar métodos específicamente para Linux fue un gran “no-no” en el pasado (¿recuerdas ese soporte de enlace blando cruddy desde 1.6 hacia atrás ?!). También es porque, mientras que el reloj puede devolver microsegundos en Linux, eso no significa necesariamente que sea bueno para verificar el tiempo. En niveles de microsegundos, debe saber que NTP no está realineando su tiempo y que su reloj no se ha desplazado demasiado durante las llamadas a métodos.

Esto significa, en teoría, que en Linux, podría escribir un contenedor JNI que sea el mismo que el del paquete del Sistema, pero no truncar los microsegundos.

una solución “rápida y sucia” con la que finalmente fui:

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

ACTUALIZAR:

Originalmente fui con System.nanoTime, pero luego descubrí que solo debería usarse durante el tiempo transcurrido, finalmente cambié mi código para trabajar con milisegundos o, en algunos lugares, uso:

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

pero esto solo agregará ceros al final del valor (micros = millis * 1000)

Dejó esta respuesta aquí como una “señal de advertencia” en caso de que alguien más piense en nanoTime 🙂

Java admite microsegundos a través de TimeUnit enum.

Aquí está el documento de Java: Enum TimeUnit

Puedes obtener microsegundos en Java de esta manera:

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

También puede convertir microsegundos en otras unidades de tiempo, por ejemplo:

 long seconds = TimeUnit.MICROSECONDS.toSeconds(microsenconds); 

Si tiene la intención de usarlo para el sistema en tiempo real, quizás java no sea la mejor opción para obtener la marca de tiempo. Pero si va a utilizar si es para una clave única, entonces la respuesta de Jason Smith hará lo suficiente. Pero por si acaso, para anticipar que 2 elementos terminan obteniendo la misma marca de tiempo (es posible si esos 2 se procesaron casi simultáneamente), puede repetir hasta que la última marca de tiempo no sea igual a la marca de tiempo actual.

 String timestamp = new String(); do { timestamp = String.valueOf(MicroTimestamp.INSTANCE.get()); item.setTimestamp(timestamp); } while(lasttimestamp.equals(timestamp)); lasttimestamp = item.getTimestamp(); 

Tal vez pueda crear un componente que determine el desfase entre System.nanoTime () y System.currentTimeMillis () y obtenga efectivamente nanosegundos desde época.

 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(); } } 

La siguiente prueba produce resultados bastante buenos en mi máquina.

  final Timer timer = new TimerImpl(); while (true) { System.out.println(timer.nowNano()); System.out.println(timer.nowMilli()); } 

La diferencia parece oscilar en un rango de + -3ms. Creo que uno podría modificar el cálculo de compensación un poco más.

 1495065607202174413 1495065607203 1495065607202177574 1495065607203 ... 1495065607372205730 1495065607370 1495065607372208890 1495065607370 ... 

Aquí hay un ejemplo de cómo crear una Marca de tiempo actual UnsignedLong:

 UnsignedLong current = new UnsignedLong(new Timestamp(new Date().getTime()).getTime());