En un sistema Unix, ¿hay alguna manera de obtener una marca de tiempo con una precisión de microsegundos en Java? Algo parecido a la gettimeofdayfunción de C.
Tenga en cuenta que los relojes de las computadoras no están configurados en ningún lugar cercano a ese nivel de precisión; dos relojes en diferentes computadoras generalmente diferirán en al menos unos pocos milisegundos, a menos que haya realizado un esfuerzo para configurar un procedimiento de sincronización de alta precisión (cuando tal cosa es incluso físicamente posible). No puedo imaginar qué sentido tendría conocer el tiempo de la computadora al microsegundo. (Si está tratando de medir un intervalo con precisión en una computadora, entonces claro, eso es perfectamente razonable, pero no necesita la marca de tiempo completa.)
David Z
2
Además, algunas versiones de Unix / Linux solo devuelven una granularidad de 1 milisegundo o 10 milisegundos en el campo de microsegundos.
Stephen C
Una forma indirecta es a través de JDBC , si está conectado a una base de datos como Postgres que captura la hora actual en microsegundos.
Basil Bourque
2
Java 9 y posterior:Instant.now()
Basil Bourque
Utilice Instant para calcular microsegundos desde Epoch: val instant = Instant.now();val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Michael M.
Respuestas:
148
No, Java no tiene esa capacidad.
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 una precisión de nanosegundos (o más).
Tenga en cuenta que JavaDoc dice que si bien esto proporciona precisión de nanosegundos, eso no significa precisión de nanosegundos. Así que tome un módulo suficientemente grande del valor de retorno.
Uno podría conjeturar que las razones por las que Java no tiene getTimeInMicroseconds () incluyen 1) la precisión no está disponible en muchas plataformas, 2) devolver una precisión de milisegundos en una llamada de microsegundos conduce a problemas de portabilidad de aplicaciones.
Stephen C
9
En Linux, System.nanoTime () llama a clock_gettime (CLOCK_MONOTONIC, _). Brian Oxley buscó en el código fuente de Java para encontrar esta pepita.
David Weber
7
Esta respuesta ahora está desactualizada . Las implementaciones OpenJDK y Oracle de Java 9 vienen con una nueva implementación Clockque permite capturar el momento actual con una resolución más fina que milisegundos. En una MacBook Pro Retina obtengo la hora actual en microsegundos (seis dígitos de fracción decimal). Los resultados reales y la precisión dependen del hardware de reloj subyacente de la computadora host.
Basil Bourque
1
@BasilBourque muchos sistemas aún se ejecutan en Java 8 o incluso antes, ya que no es necesario migrarlos. Si bien la respuesta está desactualizada, sigue siendo útil.
Dragas
1
@Dragas En realidad, sería necesario migrarlos ... para obtener la hora actual en microsegundos como lo pide esta pregunta.
Basil Bourque
78
tl; dr
Java 9 y posterior: resolución de hasta nanosegundos al capturar el momento actual. Eso es 9 dígitos de fracción decimal.
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
En la práctica, verá solo microsegundos capturados con, .nowya que los relojes de hardware de computadora convencionales contemporáneos no son precisos en nanosegundos .
Detalles
Las otras Respuestas están algo desactualizadas a partir de Java 8.
java.time
Java 8 y versiones posteriores vienen con el marco java.time . Estas nuevas clases suplantan las problemáticas y defectuosas clases de fecha y hora incluidas en 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 , ampliado por el proyecto ThreeTen-Extra.
Las clases en java.time se resuelven en nanosegundos , mucho más fino que los milisegundos utilizados por las antiguas clases de fecha y hora y por Joda-Time. Y más fino que los microsegundos que se preguntan en la Pregunta.
Clock Implementación
Si bien las clases java.time admiten datos que representan valores en nanosegundos, las clases aún no generan valores en nanosegundos. Los now()métodos utilizan la misma aplicación de reloj antiguo como las clases de fecha y hora de edad, System.currentTimeMillis(). Tenemos la nueva Clockinterfaz en java.time, pero la implementación de esa interfaz es el mismo reloj de milisegundos.
Por lo tanto, 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 Clockimplementación predeterminada con una granularidad más fina, hasta la capacidad completa de nanosegundos de las clases java.time.
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 Clockimplementación más fina , sus resultados pueden variar según la computadora. Java depende del reloj del hardware de la computadora subyacente 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 granularidad de , cualquier valor de fecha y hora generado tendrá solo seis dígitos de una fracción de segundo y los últimos tres dígitos serán ceros.
La precisión de los relojes de hardware varía ampliamente. Solo porque un reloj genera 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 se podría leer en un reloj atómico . En otras palabras, el hecho de que vea un montón de dígitos a la derecha de la marca decimal no significa que pueda confiar en que el tiempo transcurrido entre tales lecturas sea fiel a ese minuto.
Pueden resolverse en nanosegundos, pero todavía se basan en System.currentTimeMillis, por lo que solo agregan un montón de ceros al final. No ayuda en absoluto si está tratando de obtener tiempo en micro / nano segundos, el usuario podría simplemente agregar 0s al tiempo de milisegundos manualmente.
annedroiid
@annedroiid Cubrí eso en mi Respuesta. En Java 8 puede almacenar momentos con una resolución de nanosegundos, pero capturar el momento actual es solo en milisegundos. Se solucionó en Java 9 con una nueva implementación de Clock. Aun así, en Java 8 las clases java.time son útiles para mantener valores capturados por otras fuentes como microsegundos en la base de datos de Postgres. Pero tenga cuidado con la inexactitud de los valores en el rango de microsegundos y nanosegundos; Es posible que el hardware de computadora común no lleve un tiempo de seguimiento de reloj de hardware con tanta precisión. Un valor con seis o nueve dígitos de una fracción de segundo puede no ser cierto.
@Roland Sí, ahora arreglado, gracias. Para su información, en Stack Overflow se le invita a editar directamente una Respuesta para corregir dicho error.
long start =System.nanoTime();// do stufflong end =System.nanoTime();long microseconds =(end - start)/1000;
para obtener el tiempo en nanosegundos, pero es una medida estrictamente relativa. No tiene un significado absoluto. Solo es útil para comparar con otros tiempos nano para medir cuánto tiempo tomó hacer algo.
Como ya indicaron otros carteles; El reloj de su sistema probablemente no esté sincronizado hasta microsegundos con la hora mundial real. No obstante, las marcas de tiempo de precisión de microsegundos son útiles como un híbrido tanto para indicar el tiempo de pared actual como para medir / perfilar la duración de las cosas.
Yo 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 cuándo sucedió (tiempo de "pared") y también se pueden usar para medir la duración entre este y el siguiente evento en el archivo de registro (diferencia relativa en microsegundos).
Para lograr esto, necesita vincular System.currentTimeMillis () con System.nanoTime () y trabajar exclusivamente con System.nanoTime () desde ese momento en adelante. Código de ejemplo:
/**
* Class to generate timestamps with microsecond precision
* For example: MicroTimestamp.INSTANCE.get() = "2012-10-21 19:13:45.267128"
*/publicenumMicroTimestamp{ INSTANCE ;privatelong startDate ;privatelong startNanoseconds ;privateSimpleDateFormat dateFormat ;privateMicroTimestamp(){this.startDate =System.currentTimeMillis();this.startNanoseconds =System.nanoTime();this.dateFormat =newSimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");}publicString get(){long microSeconds =(System.nanoTime()-this.startNanoseconds)/1000;long date =this.startDate +(microSeconds/1000);returnthis.dateFormat.format(date)+String.format("%03d", microSeconds %1000);}}
La idea es buena, pero debes volver a sincronizar de vez en cuando. La hora del sistema (currentTime) y el reloj de la CPU (nanoTime) NO están sincronizados, ya que a menudo se basan en diferentes relojes de hardware. Además, el servidor de hora de su sistema operativo vuelve a sincronizar el reloj del sistema con una fuente de hora externa, si está disponible. Por lo tanto, su clase aparentemente muy precisa producirá marcas de tiempo que podrían estar muy lejos.
h2stein
3
Ese código no parece ser seguro para subprocesos. Dos llamadas simultáneas a MicroTimestamp.INSTANCE.get()podrían ser problemáticas.
Ahmed
@Ahmed ¿Por qué crees que el código no es seguro para subprocesos? No hay nada en el get()método que actualice las variables miembro; solo usa variables locales temporales.
Jason Smith
6
Tal vez podría crear un componente que determine el desplazamiento entre System.nanoTime () y System.currentTimeMillis () y obtener efectivamente nanosegundos desde epoch.
Si está interesado en Linux: si extrae el código fuente de "currentTimeMillis ()", verá que, en Linux, si llama a este método, retrocede un microsegundo. Sin embargo, Java luego 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 era un gran no-no en el pasado (¿recuerdas ese soporte de enlaces blandos desde 1.6 hacia atrás?). También se debe a que, si bien el reloj puede devolverle microsegundos en Linux, eso no significa necesariamente que sea bueno para verificar la hora. A niveles de microsegundos, debe saber que NTP no está realineando su tiempo y que su reloj no se ha desviado demasiado durante las llamadas a métodos.
Esto significa que, en teoría, en Linux, podría escribir un contenedor JNI que sea el mismo que el del paquete System, pero sin 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 que funcione con milisegundos o en algunos lugares use:
El documento dice explícitamente que no se use System.nanoTimepara el tiempo de reloj de pared: "Este método solo se puede usar para medir el tiempo transcurrido y no está relacionado con ninguna otra noción de sistema o tiempo de reloj de pared".
Basil Bourque
1
@BasilBourque tienes razón, después de escribir esto eventualmente descubrí y cambié mi código, pero olvidé actualizar aquí, ¡gracias por el comentario!
keisar
2
Soporte de Java microsegundos a través de TimeUnit enum.
Esto no es correcto, obtendrá el tiempo en resolución / longitud MICRO, pero el tiempo en sí será siempre solo con precisión MILI (lo que significa que los últimos 3 dígitos siempre serán 0).
Michalsx
0
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 usar if para una clave única, entonces la respuesta de Jason Smith será 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 realizar un ciclo hasta que la última marca de tiempo no sea igual a la marca de tiempo actual.
Respuesta incorrecta. La clase java.util.Date tiene una resolución de milisegundos, no microsegundos especificada en la Pregunta. Hacer un java.sql.Timestamp no extrae datos adicionales del aire.
Instant.now()
val instant = Instant.now();
val currentTimeMicros = instant.getEpochSecond() * 1000_000 + instant.getNano() / 1000;
Respuestas:
No, Java no tiene esa capacidad.
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 una precisión de nanosegundos (o más).
Tenga en cuenta que JavaDoc dice que si bien esto proporciona precisión de nanosegundos, eso no significa precisión de nanosegundos. Así que tome un módulo suficientemente grande del valor de retorno.
fuente
Clock
que permite capturar el momento actual con una resolución más fina que milisegundos. En una MacBook Pro Retina obtengo la hora actual en microsegundos (seis dígitos de fracción decimal). Los resultados reales y la precisión dependen del hardware de reloj subyacente de la computadora host.tl; dr
Java 9 y posterior: resolución de hasta nanosegundos al capturar el momento actual. Eso es 9 dígitos de fracción decimal.
Para limitar a microsegundos , truncar .
En la práctica, verá solo microsegundos capturados con,
.now
ya que los relojes de hardware de computadora convencionales contemporáneos no son precisos en nanosegundos .Detalles
Las otras Respuestas están algo desactualizadas a partir de Java 8.
java.time
Java 8 y versiones posteriores vienen con el marco java.time . Estas nuevas clases suplantan las problemáticas y defectuosas clases de fecha y hora incluidas en 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 , ampliado por el proyecto ThreeTen-Extra.
Las clases en java.time se resuelven en nanosegundos , mucho más fino que los milisegundos utilizados por las antiguas clases de fecha y hora y por Joda-Time. Y más fino que los microsegundos que se preguntan en la Pregunta.
Clock
ImplementaciónSi bien las clases java.time admiten datos que representan valores en nanosegundos, las clases aún no generan valores en nanosegundos. Los
now()
métodos utilizan la misma aplicación de reloj antiguo como las clases de fecha y hora de edad,System.currentTimeMillis()
. Tenemos la nuevaClock
interfaz en java.time, pero la implementación de esa interfaz es el mismo reloj de milisegundos.Por lo tanto, 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:Nuevo reloj en Java 9
Las implementaciones OpenJDK y Oracle de Java 9 tienen una nueva
Clock
implementación predeterminada con una granularidad más fina, hasta la capacidad completa de nanosegundos de las clases java.time.Consulte el problema de OpenJDK, Aumente la precisión de la implementación de java.time.Clock.systemUTC () . Ese problema se ha implementado con éxito.
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).
Reloj de hardware
Recuerde que incluso con una nueva
Clock
implementación más fina , sus resultados pueden variar según la computadora. Java depende del reloj del hardware de la computadora subyacente para conocer el momento actual.fuente
Clock
. Aun así, en Java 8 las clases java.time son útiles para mantener valores capturados por otras fuentes como microsegundos en la base de datos de Postgres. Pero tenga cuidado con la inexactitud de los valores en el rango de microsegundos y nanosegundos; Es posible que el hardware de computadora común no lleve un tiempo de seguimiento de reloj de hardware con tanta precisión. Un valor con seis o nueve dígitos de una fracción de segundo puede no ser cierto.Puede utilizar
System.nanoTime()
:para obtener el tiempo en nanosegundos, pero es una medida estrictamente relativa. No tiene un significado absoluto. Solo es útil para comparar con otros tiempos nano para medir cuánto tiempo tomó hacer algo.
fuente
Como ya indicaron otros carteles; El reloj de su sistema probablemente no esté sincronizado hasta microsegundos con la hora mundial real. No obstante, las marcas de tiempo de precisión de microsegundos son útiles como un híbrido tanto para indicar el tiempo de pared actual como para medir / perfilar la duración de las cosas.
Yo 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 cuándo sucedió (tiempo de "pared") y también se pueden usar para medir la duración entre este y el siguiente evento en el archivo de registro (diferencia relativa en microsegundos).
Para lograr esto, necesita vincular System.currentTimeMillis () con System.nanoTime () y trabajar exclusivamente con System.nanoTime () desde ese momento en adelante. Código de ejemplo:
fuente
MicroTimestamp.INSTANCE.get()
podrían ser problemáticas.get()
método que actualice las variables miembro; solo usa variables locales temporales.Tal vez podría crear un componente que determine el desplazamiento entre System.nanoTime () y System.currentTimeMillis () y obtener efectivamente nanosegundos desde epoch.
La siguiente prueba produce resultados bastante buenos en mi máquina.
La diferencia parece oscilar en un rango de + -3ms. Supongo que se podría modificar un poco más el cálculo de compensación.
fuente
Si está interesado en Linux: si extrae el código fuente de "currentTimeMillis ()", verá que, en Linux, si llama a este método, retrocede un microsegundo. Sin embargo, Java luego 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 era un gran no-no en el pasado (¿recuerdas ese soporte de enlaces blandos desde 1.6 hacia atrás?). También se debe a que, si bien el reloj puede devolverle microsegundos en Linux, eso no significa necesariamente que sea bueno para verificar la hora. A niveles de microsegundos, debe saber que NTP no está realineando su tiempo y que su reloj no se ha desviado demasiado durante las llamadas a métodos.
Esto significa que, en teoría, en Linux, podría escribir un contenedor JNI que sea el mismo que el del paquete System, pero sin truncar los microsegundos.
fuente
una solución "rápida y sucia" con la que finalmente fui:
ACTUALIZAR:
Originalmente fui con System.nanoTime pero luego descubrí que solo debería usarse durante el tiempo transcurrido, finalmente cambié mi código para que funcione con milisegundos o en algunos lugares use:
pero esto solo agregará ceros al final del valor (micros = milis * 1000)
Dejó esta respuesta aquí como una "señal de advertencia" en caso de que alguien más piense en nanoTime :)
fuente
System.nanoTime
para el tiempo de reloj de pared: "Este método solo se puede usar para medir el tiempo transcurrido y no está relacionado con ninguna otra noción de sistema o tiempo de reloj de pared".Soporte de Java microsegundos a través de
TimeUnit
enum.Aquí está el documento de Java: Enum TimeUnit
Puede obtener microsegundos en java de esta manera:
También puede convertir microsegundos a otras unidades de tiempo, por ejemplo:
fuente
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 usar if para una clave única, entonces la respuesta de Jason Smith será 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 realizar un ciclo hasta que la última marca de tiempo no sea igual a la marca de tiempo actual.
fuente
Utilice Instant para calcular microsegundos desde Epoch:
fuente
fuente
A continuación, se muestra un ejemplo de cómo crear una marca de tiempo actual UnsignedLong:
fuente