tl; dr
Existe uma maneira, no código ou com argumentos da JVM, de substituir o horário atual, conforme apresentado por System.currentTimeMillis, além de alterar manualmente o relógio do sistema na máquina host?
Sim.
Instant.now(
Clock.fixed(
Instant.parse( "2016-01-23T12:34:56Z"), ZoneOffset.UTC
)
)
Clock
No java.time
Temos uma nova solução para o problema de uma substituição de relógio conectável para facilitar o teste com valores falsos de data e hora. O pacote java.time no Java 8 inclui uma classe abstrata java.time.Clock
, com um propósito explícito:
para permitir que relógios alternativos sejam conectados como e quando necessário
Você pode conectar sua própria implementação de Clock
, embora provavelmente encontre uma já feita para atender às suas necessidades. Para sua conveniência, o java.time inclui métodos estáticos para gerar implementações especiais. Essas implementações alternativas podem ser valiosas durante o teste.
Cadência alterada
Os vários tick…
métodos produzem relógios que incrementam o momento atual com uma cadência diferente.
O padrão Clock
relata um horário atualizado com a frequência de milissegundos no Java 8 e no Java 9 tão bom quanto os nanossegundos (dependendo do seu hardware). Você pode solicitar que o verdadeiro momento atual seja relatado com uma granularidade diferente.
Relógios falsos
Alguns relógios podem mentir, produzindo um resultado diferente do relógio do hardware do sistema operacional host.
fixed
- Relata um único momento imutável (sem incremento) como o momento atual.
offset
- Relata o momento atual, mas mudou com o Duration
argumento passado .
Por exemplo, prenda o primeiro momento do Natal mais cedo deste ano. em outras palavras, quando Papai Noel e suas renas fazem sua primeira parada . O fuso horário mais antigo atualmente parece estar Pacific/Kiritimati
em +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 esse relógio fixo especial para sempre retornar o mesmo momento. Chegamos ao primeiro momento do dia de Natal em Kiritimati , com o UTC mostrando um relógio de parede de catorze horas antes, às 10h da data anterior de 24 de dezembro.
Instant instant = Instant.now( clockEarliestXmasThisYear );
ZonedDateTime zdt = ZonedDateTime.now( clockEarliestXmasThisYear );
instant.toString (): 2016-12-24T10: 00: 00Z
zdt.toString (): 25-12-2016T00: 00 + 14: 00 [Pacific / Kiritimati]
Veja o código ao vivo em IdeOne.com .
Hora verdadeira, fuso horário diferente
Você pode controlar qual fuso horário é atribuído pela Clock
implementação. Isso pode ser útil em alguns testes. Mas eu não recomendo isso no código de produção, onde você sempre deve especificar explicitamente o opcional ZoneId
ou ZoneOffset
argumentos.
Você pode especificar que o UTC seja a zona padrão.
ZonedDateTime zdtClockSystemUTC = ZonedDateTime.now ( Clock.systemUTC () );
Você pode especificar qualquer fuso horário específico. Especifique um nome próprio fuso horário no formato continent/region
, como America/Montreal
, Africa/Casablanca
, ou Pacific/Auckland
. Nunca utilize o 3-4 letras, como EST
ou IST
como eles são não zonas verdadeiros tempo, não padronizados, e nem mesmo única (!).
ZonedDateTime zdtClockSystem = ZonedDateTime.now ( Clock.system ( ZoneId.of ( "America/Montreal" ) ) );
É possível especificar o fuso horário padrão atual da JVM deve ser o padrão para um Clock
objeto específico .
ZonedDateTime zdtClockSystemDefaultZone = ZonedDateTime.now ( Clock.systemDefaultZone () );
Execute este código para comparar. Observe que todos relatam o mesmo momento, o mesmo ponto na linha do tempo. Eles diferem apenas no tempo do relógio de parede ; em outras palavras, três maneiras de dizer a mesma coisa, três maneiras de exibir o mesmo momento.
System.out.println ( "zdtClockSystemUTC.toString(): " + zdtClockSystemUTC );
System.out.println ( "zdtClockSystem.toString(): " + zdtClockSystem );
System.out.println ( "zdtClockSystemDefaultZone.toString(): " + zdtClockSystemDefaultZone );
America/Los_Angeles
era a zona padrão atual da JVM no computador que executou esse código.
zdtClockSystemUTC.toString (): 2016-12-31T20: 52: 39.688Z
zdtClockSystem.toString (): 2016-12-31T15: 52: 39.750-05: 00 [America / Montreal]
zdtClockSystemDefaultZone.toString (): 2016-12-31T12: 52: 39.762-08: 00 [America / Los_Angeles]
A Instant
classe está sempre no UTC, por definição. Portanto, esses três Clock
usos relacionados à zona têm exatamente o mesmo efeito.
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
Relógio padrão
A implementação usada por padrão para Instant.now
é a retornada por Clock.systemUTC()
. Esta é a implementação usada quando você não especifica a Clock
. Veja você mesmo no código-fonte Java 9 de pré-lançamento paraInstant.now
.
public static Instant now() {
return Clock.systemUTC().instant();
}
O padrão Clock
para OffsetDateTime.now
e ZonedDateTime.now
é Clock.systemDefaultZone()
. Veja o código fonte .
public static ZonedDateTime now() {
return now(Clock.systemDefaultZone());
}
O comportamento das implementações padrão mudou entre o Java 8 e o Java 9. No Java 8, o momento atual é capturado com uma resolução apenas em milissegundos, apesar da capacidade das classes de armazenar uma resolução de nanossegundos . O Java 9 traz uma nova implementação capaz de capturar o momento atual com uma resolução de nanossegundos - dependendo, é claro, da capacidade do relógio do hardware do computador.
Sobre java.time
A estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, como java.util.Date
, Calendar
, e SimpleDateFormat
.
Para saber mais, consulte o Tutorial do Oracle . E procure Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .
O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .
Você pode trocar objetos java.time diretamente com seu banco de dados. Use um driver JDBC compatível com JDBC 4.2 ou posterior. Não há necessidade de strings, não há necessidade de java.sql.*
classes. O Hibernate 5 e o JPA 2.2 suportam java.time .
Onde obter as classes java.time?