tl; dr
¿Hay alguna manera, ya sea en código o con argumentos JVM, para anular la hora actual, tal como se presenta a través de System.currentTimeMillis, que no sea cambiar manualmente el reloj del sistema en la máquina host?
Si.
Instant.now(
Clock.fixed(
Instant.parse( "2016-01-23T12:34:56Z"), ZoneOffset.UTC
)
)
Clock
En java.time
Tenemos una nueva solución al problema de un reemplazo de reloj conectable para facilitar la prueba con valores falsos de fecha y hora. El paquete java.time en Java 8 incluye una clase abstracta java.time.Clock
, con un propósito explícito:
para permitir que se conecten relojes alternativos cuando sea necesario
Puede conectar su propia implementación de Clock
, aunque es probable que pueda encontrar una ya hecha para satisfacer sus necesidades. Para su conveniencia, java.time incluye métodos estáticos para producir implementaciones especiales. Estas implementaciones alternativas pueden ser valiosas durante las pruebas.
Cadencia alterada
Los diversos tick…
métodos producen relojes que incrementan el momento actual con una cadencia diferente.
El valor predeterminado Clock
informa un tiempo actualizado con tanta frecuencia como milisegundos en Java 8 y en Java 9 tan fino como nanosegundos (dependiendo de su hardware). Puede solicitar que se informe el momento actual real con una granularidad diferente.
Relojes falsos
Algunos relojes pueden mentir, produciendo un resultado diferente al del reloj de hardware del sistema operativo host.
fixed
- Informa un momento único que no cambia (sin incremento) como el momento actual.
offset
- Informa el momento actual, pero cambiado por el Duration
argumento pasado .
Por ejemplo, asegure el primer momento de la primera Navidad de este año. en otras palabras, cuando Santa y sus renos hacen su primera parada . La zona horaria más temprana hoy en día parece estar Pacific/Kiritimati
en +14:00
.
LocalDate ld = LocalDate.now( ZoneId.of( "America/Montreal" ) );
LocalDate xmasThisYear = MonthDay.of( Month.DECEMBER , 25 ).atYear( ld.getYear() );
ZoneId earliestXmasZone = ZoneId.of( "Pacific/Kiritimati" ) ;
ZonedDateTime zdtEarliestXmasThisYear = xmasThisYear.atStartOfDay( earliestXmasZone );
Instant instantEarliestXmasThisYear = zdtEarliestXmasThisYear.toInstant();
Clock clockEarliestXmasThisYear = Clock.fixed( instantEarliestXmasThisYear , earliestXmasZone );
Use ese reloj fijo especial para regresar siempre el mismo momento. Tenemos el primer momento del día de Navidad en Kiritimati , con UTC mostrando un reloj de pared de catorce horas antes, las 10 de la mañana de la fecha anterior del 24 de diciembre.
Instant instant = Instant.now( clockEarliestXmasThisYear );
ZonedDateTime zdt = ZonedDateTime.now( clockEarliestXmasThisYear );
instant.toString (): 2016-12-24T10: 00: 00Z
zdt.toString (): 2016-12-25T00: 00 + 14: 00 [Pacífico / Kiritimati]
Ver código en vivo en IdeOne.com .
Hora verdadera, zona horaria diferente
Puede controlar qué zona horaria asigna la Clock
implementación. Esto podría ser útil en algunas pruebas. Pero no lo recomiendo en el código de producción, donde siempre debe especificar explícitamente los opcionales ZoneId
o los ZoneOffset
argumentos.
Puede especificar que UTC sea la zona predeterminada.
ZonedDateTime zdtClockSystemUTC = ZonedDateTime.now ( Clock.systemUTC () );
Puede especificar cualquier zona horaria en particular. Especificar un nombre de zona horaria correcta en el formato de continent/region
, por ejemplo America/Montreal
, Africa/Casablanca
o Pacific/Auckland
. Nunca use el 3-4 abreviatura de letras tales como EST
o IST
, ya que son no verdaderas zonas de tiempo, no estandarizados, y ni siquiera único (!).
ZonedDateTime zdtClockSystem = ZonedDateTime.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Puede especificar que la zona horaria predeterminada actual de la JVM sea la predeterminada para un Clock
objeto en particular .
ZonedDateTime zdtClockSystemDefaultZone = ZonedDateTime.now ( Clock.systemDefaultZone () );
Ejecute este código para comparar. Tenga en cuenta que todos informan el mismo momento, el mismo punto en la línea de tiempo. Solo difieren en la hora del reloj de pared ; en otras palabras, tres formas de decir lo mismo, tres formas de mostrar el mismo momento.
System.out.println ( "zdtClockSystemUTC.toString(): " + zdtClockSystemUTC );
System.out.println ( "zdtClockSystem.toString(): " + zdtClockSystem );
System.out.println ( "zdtClockSystemDefaultZone.toString(): " + zdtClockSystemDefaultZone );
America/Los_Angeles
era la zona predeterminada actual de JVM en la computadora que ejecutó este código.
zdtClockSystemUTC.toString (): 2016-12-31T20: 52: 39.688Z
zdtClockSystem.toString (): 2016-12-31T15: 52: 39.750-05: 00 [América / Montreal]
zdtClockSystemDefaultZone.toString (): 2016-12-31T12: 52: 39.762-08: 00 [América / Los_Angeles]
La Instant
clase siempre está en UTC por definición. Entonces, estos tres Clock
usos relacionados con la zona tienen exactamente el mismo efecto.
Instant instantClockSystemUTC = Instant.now ( Clock.systemUTC () );
Instant instantClockSystem = Instant.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
Instant instantClockSystemDefaultZone = Instant.now ( Clock.systemDefaultZone () );
instantClockSystemUTC.toString (): 2016-12-31T20: 52: 39.763Z
instantClockSystem.toString (): 2016-12-31T20: 52: 39.763Z
instantClockSystemDefaultZone.toString (): 2016-12-31T20: 52: 39.763Z
Reloj predeterminado
La implementación utilizada por defecto para Instant.now
es la que devuelve Clock.systemUTC()
. Esta es la implementación utilizada cuando no especificas a Clock
. Compruébelo usted mismo en el código fuente de Java 9 previo al lanzamiento deInstant.now
.
public static Instant now() {
return Clock.systemUTC().instant();
}
El valor predeterminado Clock
para OffsetDateTime.now
y ZonedDateTime.now
es Clock.systemDefaultZone()
. Ver código fuente .
public static ZonedDateTime now() {
return now(Clock.systemDefaultZone());
}
El comportamiento de las implementaciones predeterminadas cambió entre Java 8 y Java 9. En Java 8, el momento actual se captura con una resolución solo en milisegundos a pesar de la capacidad de las clases para almacenar una resolución de nanosegundos . Java 9 trae una nueva implementación capaz de capturar el momento actual con una resolución de nanosegundos, dependiendo, por supuesto, de la capacidad del reloj de hardware de su computadora.
Sobre java.time
El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como java.util.Date
, Calendar
, y SimpleDateFormat
.
Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .
El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .
Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No hay necesidad de cadenas, no hay necesidad de java.sql.*
clases. Hibernate 5 y JPA 2.2 admiten java.time .
¿Dónde obtener las clases java.time?