2011-04-30 29 views
6

java.sql.Timestamp constructor de ir como esto:java.sql.Timestamp forma de almacenar nanosegundos

public Timestamp(long time) { 
    super((time/1000)*1000); 
    nanos = (int)((time%1000) * 1000000); 
    if (nanos < 0) { 
     nanos = 1000000000 + nanos;  
     super.setTime(((time/1000)-1)*1000); 
    } 
} 

Básicamente acepta el tiempo en milisegundos y luego extrae los últimos 3 dígitos y lo hace nanos. Entonces, para un valor de milisegundo de 1304135631 , obtengo Timestamp.getnanos() como . Este es un cálculo simple (agregando 6 ceros al final) ... no parece ser óptimo.

Una mejor manera podría haber sido el constructor Timestamp que acepta tiempo en nanosegundos y luego calcula el valor de nanosegundos a partir de eso.

Si ejecuta el siguiente programa, verá la diferencia entre nanosegundos reales y el que devuelve Timestamp forma de calcular nanosecodos.

long a = System.currentTimeMillis(); 
    for(;;){ 
     long b = System.currentTimeMillis(); 
     Timestamp tm = new Timestamp(System.currentTimeMillis()); 
     System.out.println(tm.getTime()); 
     System.out.println(tm.getNanos()); 
     System.out.println("This is actual nanos" + System.nanoTime()%1000000000); 
     System.out.println("--------------------------"); 
     if(b-a >= 1) 
      break; 
    } 

Así que toda la discusión acerca de marca de fecha que dice que almacena el tiempo hasta nanosegundos, no parece ser tan correcto .. ¿No?

Respuesta

6

El tiempo en millis no representa el tiempo en nanos. Más preciso, simplemente no puede ser. Se supone que debes usar Timestamp#setNanos() para establecer los nanos reales.

long timeInMillis = System.currentTimeMillis(); 
long timeInNanos = System.nanoTime(); 

Timestamp timestamp = new Timestamp(timeInMillis); 
timestamp.setNanos((int) (timeInNanos % 1000000000)); 

// ... 
+1

Sí .. Esto sin duda funcionará. Entonces, para hacer que Timestamp realmente almacene nanos, debe ser un proceso de dos pasos. Un poco incómodo, en cambio, un Constructor que acepta nanos (desde el 1 de enero de 1970) hubiera sido una mejor solución. – Vicky

+1

¡Esto no es seguro! ¡Se envuelve! El problema es que 'currentTimeMillis' y' nanoTime' pueden no coincidir en la resolución más grande. p.ej. 'nanoTime' devuelve los valores 12: 06: 30.9999, 12:06: ** 31 ** .1111 pero' currentTimeMillis' devuelve 12: 06: 30.666 12:06: ** 30 ** .777, luego usa el código anterior inicializar la marca de tiempo daría como resultado marcas de tiempo 12: 06: 30.9999, 12:06: ** 30 ** .1111. Por separado, como comentario de @Vicky, ¿cómo inicializaría una marca de tiempo antes de 1970? – Luciano

+0

Es cierto que la configuración de nano segundos debe configurarse por separado, pero el uso de 'System # nanoTime()' como este no es correcto. La documentación de la API para 'System # nanoTime()' dice: "Este método solo se puede usar para medir el tiempo transcurrido y no está relacionado con ninguna otra noción del sistema o la hora del reloj de pared.El valor devuelto representa nanosegundos desde algún tiempo fijo pero arbitrario (tal vez en el futuro, por lo que los valores pueden ser negativos). "(Ver http://download.oracle.com/javase/6/docs/api/java/lang/System .html # nanoTime% 28% 29) –

0

Aunque es un antiguo puesto, me gustaría añadir que los documentos de marca de hora sí afirma que "tiene fracciones de segundo, permitiendo la especificación de fracciones de segundo con una precisión de nanaoseconds". La parte confusa es "mantener". Esto parece confuso al principio, pero si se entiende correctamente, en realidad no indica que contenga nanaoseconds valor. Dice que "contiene" valor fraccionario y le permite ser una "precisión" de nanosegundos. La precisión se debe entender en términos de representación del número total de dígitos. Entonces, esencialmente significa que la parte es en realidad fraccional (todavía milisegundos) pero se multiplica por 1000000 para representarla en nanosegundos.

La respuesta aceptada (por siempre útil BaluC) lo resume muy bien.

0

Me gusta la implementación de OpenJPA de TimestampHelper. Utiliza los inicializadores estáticos para realizar un seguimiento de los nanosegundos transcurridos entre las llamadas para crear una marca de tiempo.

1

Desde la introducción de java.time.*, existe un nuevo método de fábrica en java.sql.Timestamp: Timestamp.from(Instant.now()) hará el trabajo (con precisión de nanosegundos). También hay Timestamp.toInstant() para convertirlo al revés.

+0

Java 8 ofrece ['LocalDateTime.now()'] (https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html#now -) ... O si <8, use 'System.nanoTime()' para obtener la marca de tiempo actual .... – KarelG

Cuestiones relacionadas