tl; dr
LocalDate // Represents an entire day, without time-of-day and without time zone.
.now( // Capture the current date.
ZoneId.of( "Asia/Tokyo" ) // Returns a `ZoneId` object.
) // Returns a `LocalDate` object.
.atStartOfDay( // Determines the first moment of the day as seen on that date in that time zone. Not all days start at 00:00!
ZoneId.of( "Asia/Tokyo" )
) // Returns a `ZonedDateTime` object.
Início do dia
Obtenha o comprimento total do hoje como visto em um fuso horário.
Utilizando a abordagem semi-aberta, onde o início é inclusivo e o final é exclusivo . Essa abordagem resolve a falha no seu código que falha em explicar o último segundo do dia.
ZoneId zoneId = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( zoneId ) ;
ZonedDateTime zdtStart = today.atStartOfDay( zoneId ) ;
ZonedDateTime zdtStop = today.plusDays( 1 ).atStartOfDay( zoneId ) ;
zdtStart.toString () = 2020-01-30T00: 00 + 01: 00 [África / Tunis]
zdtStop.toString () = 2020-01-31T00: 00 + 01: 00 [África / Tunis]
Veja os mesmos momentos no UTC.
Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;
start.toString () = 2020-01-29T23: 00: 00Z
stop.toString () = 2020-01-30T23: 00: 00Z
Se você deseja o dia inteiro de uma data como visto no UTC, e não no fuso horário, use OffsetDateTime
.
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
OffsetDateTime odtStart = today.atTime( OffsetTime.MIN ) ;
OffsetDateTime odtStop = today.plusDays( 1 ).atTime( OffsetTime.MIN ) ;
odtStart.toString () = 2020-01-30T00: 00 + 18: 00
odtStop.toString () = 2020-01-31T00: 00 + 18: 00
Esses OffsetDateTime
objetos já estarão no UTC, mas você pode chamar toInstant
se precisar desses objetos que estão sempre no UTC, por definição.
Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;
start.toString () = 2020-01-29T06: 00: 00Z
stop.toString () = 2020-01-30T06: 00: 00Z
Dica: você pode estar interessado em adicionar a biblioteca ThreeTen-Extra ao seu projeto para usar sua Interval
classe para representar esse par de Instant
objetos. Isto oferece classe métodos úteis para comparação, como abuts
, overlaps
, contains
e muito mais.
Interval interval = Interval.of( start , stop ) ;
interval.toString () = 2020-01-29T06: 00: 00Z / 2020-01-30T06: 00: 00Z
Meio aberto
A resposta do mprivat está correta. Seu argumento é não tentar obter o final de um dia, mas comparar com "antes do início do dia seguinte". Sua idéia é conhecida como a abordagem "semi-aberta", em que um período de tempo tem um começo inclusivo, enquanto o final é exclusivo .
- As estruturas atuais de data e hora do Java (java.util.Date/Calendar e Joda-Time ) usam milissegundos da época . Mas no Java 8, as novas classes JSR 310 java.time. * Usam resolução de nanossegundos. Qualquer código que você escreveu com base na imposição da contagem de milissegundos do último momento do dia estaria incorreto se alternado para as novas classes.
- A comparação de dados de outras fontes se torna defeituosa se empregar outras resoluções. Por exemplo, as bibliotecas Unix normalmente empregam segundos inteiros, e bancos de dados como o Postgres resolvem a data e hora em microssegundos.
- Algumas alterações no horário de verão acontecem à meia-noite, o que pode confundir ainda mais as coisas.
Joda-Time 2.3 oferece um método para este mesmo fim, para obter primeiro momento do dia: withTimeAtStartOfDay()
. Da mesma forma em java.time LocalDate::atStartOfDay
,.
Pesquise StackOverflow por "joda half-open" para ver mais discussões e exemplos.
Veja este post, Intervalos de tempo e outros intervalos devem estar semi-abertos , por Bill Schneider.
Evite classes de data e hora herdadas
As classes java.util.Date e .Calendar são notoriamente problemáticas. Evite-os.
Use as classes java.time . A estrutura java.time é o sucessor oficial da bem - sucedida biblioteca Joda-Time .
java.time
A estrutura java.time é integrada ao Java 8 e posterior. Portado para Java 6 e 7 no projeto ThreeTen-Backport , adaptado ao Android no projeto ThreeTenABP .
An Instant
é um momento na linha do tempo no UTC com uma resolução de nanossegundos .
Instant instant = Instant.now();
Aplique um fuso horário para obter a hora do relógio de parede em alguma localidade.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Para obter o primeiro momento do dia, leia a LocalDate
aula e seu atStartOfDay
método.
ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
Usando a abordagem semi-aberta, obtenha o primeiro momento do dia seguinte.
ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );
Atualmente, a estrutura java.time não possui uma Interval
classe, conforme descrito abaixo para o Joda-Time. No entanto, o projeto ThreeTen-Extra estende o java.time com classes adicionais. Este projeto é o campo de prova para possíveis adições futuras ao java.time. Entre suas classes é Interval
. Construa um Interval
passando um par de Instant
objetos. Podemos extrair um Instant
de nossos ZonedDateTime
objetos.
Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );
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?
Joda-Time
ATUALIZAÇÃO: O projeto Joda-Time agora está no modo de manutenção e aconselha a migração para as classes java.time . Estou deixando esta seção intacta para a história.
Joda-Time tem três classes para representar um espaço de tempo de várias maneiras: Interval
, Period
, e Duration
. Um Interval
tem um começo e um fim específicos na linha do tempo do Universo. Isso se encaixa em nossa necessidade de representar "um dia".
Chamamos o método em withTimeAtStartOfDay
vez de definir a hora do dia como zeros. Por causa do horário de verão e de outras anomalias, o primeiro momento do dia pode não ser 00:00:00
.
Exemplo de código usando o Joda-Time 2.3.
DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );
Se necessário, você pode converter para um java.util.Date.
java.util.Date date = todayStart.toDate();