tl; dr
Instant
e LocalDateTime
sono due animali completamente diversi: uno rappresenta un momento, l'altro no.
Instant
rappresenta un momento, un punto specifico nella sequenza temporale.
LocalDateTime
rappresenta una data e un'ora del giorno. Ma mancando di un fuso orario o offset da UTC, questa classe non può rappresentare un momento . Rappresenta potenziali momenti lungo un intervallo di circa 26-27 ore, l'intervallo di tutti i fusi orari in tutto il mondo.
Presunzione errata
LocalDateTime
è piuttosto una rappresentazione di data / orologio compresi i fusi orari per l'uomo.
La tua affermazione non è corretta: A nonLocalDateTime
ha fuso orario . Non avere il fuso orario è l'intero punto di quella classe.
Per citare il documento di quella classe:
Questa classe non memorizza o rappresenta un fuso orario. Invece, è una descrizione della data, utilizzata per i compleanni, combinata con l'ora locale come si vede su un orologio da parete. Non può rappresentare un istante sulla linea temporale senza informazioni aggiuntive come un offset o un fuso orario.
Quindi Local…
significa "non suddiviso in zone, nessun offset".
Instant
An Instant
è un momento sulla linea temporale in UTC , un conteggio di nanosecondi dall'epoca del primo momento del 1970 UTC (in pratica, vedi documento di classe per dettagli nitidi). Poiché la maggior parte della logica aziendale, dell'archiviazione e dello scambio di dati dovrebbe essere in UTC, questa è una classe utile da usare spesso.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
OffsetDateTime
La classe OffsetDateTime
class rappresenta un momento come data e ora con un contesto di un numero di ore-minuti-secondi prima o dietro UTC. La quantità di offset, il numero di ore-minuti-secondi, è rappresentata dalla ZoneOffset
classe.
Se il numero di ore-minuti-secondi è zero, un OffsetDateTime
rappresenta un momento in UTC uguale a un Instant
.
ZoneOffset
La ZoneOffset
classe rappresenta un offset da UTC , un numero di ore-minuti-secondi avanti rispetto a UTC o dietro UTC.
A ZoneOffset
è semplicemente un numero di ore-minuti-secondi, niente di più. Una zona è molto di più, con un nome e una cronologia delle modifiche da compensare. Pertanto, è sempre preferibile utilizzare una zona rispetto a un semplice offset.
ZoneId
Un fuso orario è rappresentato dalla ZoneId
classe.
Un nuovo giorno nasce prima a Parigi che a Montreal , per esempio. Quindi abbiamo bisogno di muovere le lancette dell'orologio per riflettere meglio il mezzogiorno (quando il Sole è direttamente sopra la testa) per una data regione. Quanto più a est / ovest della linea UTC in Europa occidentale / Africa tanto maggiore è l'offset.
Un fuso orario è un insieme di regole per la gestione degli aggiustamenti e delle anomalie praticate da una comunità o regione locale. L'anomalia più comune è la pazzia fin troppo popolare nota come ora legale (DST) .
Un fuso orario ha la storia delle regole passate, delle regole presenti e delle regole confermate per il prossimo futuro.
Queste regole cambiano più spesso di quanto ti aspetti. Assicurati di mantenere aggiornate le regole della tua libreria data-ora, di solito una copia del database 'tz' . Aggiornarsi è più semplice che mai in Java 8 con Oracle che rilascia uno strumento di aggiornamento del fuso orario .
Specificare un nome proprio fuso orario nel formato Continent/Region
, come ad esempio America/Montreal
, Africa/Casablanca
o Pacific/Auckland
. Non usare mai il 2-4 lettera sigla come ad esempio EST
o IST
come sono non fusi orari veri e propri, non standardizzati, e nemmeno unico (!).
Fuso orario = Offset + Regole di regolazione
ZoneId z = ZoneId.of( “Africa/Tunis” ) ;
ZonedDateTime
Pensa ZonedDateTime
concettualmente come Instant
con un assegnato ZoneId
.
ZonedDateTime = (Instant + ZoneId)
Per catturare il momento attuale visto nell'orologio dell'orologio da parete usato dalle persone di una particolare regione (un fuso orario):
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Pass a `ZoneId` object such as `ZoneId.of( "Europe/Paris" )`.
Quasi tutti i tuoi back-end, database, business logic, persistenza dei dati, scambio di dati dovrebbero essere tutti in UTC. Ma per la presentazione agli utenti è necessario adeguarsi al fuso orario previsto dall'utente. Questo è lo scopo della ZonedDateTime
classe e delle classi di formattazione utilizzate per generare rappresentazioni String di quei valori data-ora.
ZonedDateTime zdt = instant.atZone( z ) ;
String output = zdt.toString() ; // Standard ISO 8601 format.
È possibile generare testo in formato localizzato utilizzando DateTimeFormatter
.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
String outputFormatted = zdt.format( f ) ;
martedì 30 aprile 2019 a 23 h 22 min 55 s heure de l'Inde
LocalDate
, LocalTime
,LocalDateTime
Le classi a tempo data "locali", LocalDateTime
, LocalDate
, LocalTime
, sono un diverso tipo di creatura. Non sono legati a nessuna località o fuso orario. Non sono legati alla linea temporale. Non hanno alcun significato reale fino a quando non vengono applicati a una località per trovare un punto nella sequenza temporale.
La parola "Local" in questi nomi di classe può essere controintuitiva per chi non lo sapesse. La parola significa qualsiasi località, o ogni località, ma non una località particolare.
Pertanto, per le app aziendali, i tipi "locali" non vengono spesso utilizzati in quanto rappresentano solo l'idea generale di una possibile data o ora, non di un momento specifico nella sequenza temporale. Le app aziendali tendono a preoccuparsi del momento esatto in cui è arrivata una fattura, un prodotto spedito per il trasporto, un dipendente è stato assunto o il taxi ha lasciato il garage. Quindi gli sviluppatori di app aziendali usano Instant
e le ZonedDateTime
classi più comunemente.
Quindi quando dovremmo usare LocalDateTime
? In tre situazioni: in cui vogliamo applicare una determinata data e ora del giorno in più località, in cui prenotiamo appuntamenti o in cui abbiamo un fuso orario previsto ma non definito. Si noti che nessuno di questi tre casi è un singolo punto specifico nella sequenza temporale, nessuno di questi è un momento.
Un'ora del giorno, più momenti
A volte vogliamo rappresentare un determinato momento del giorno in una determinata data, ma vogliamo applicarlo in più località attraverso i fusi orari.
Ad esempio, "Natale inizia a mezzanotte del 25 dicembre 2015" è un LocalDateTime
. La mezzanotte colpisce in momenti diversi a Parigi rispetto a Montréal, e di nuovo diversi a Seattle e ad Auckland .
LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ; // 00:00:00
LocalTime ldt = LocalDateTime.of( ld , lt ) ; // Xmas morning anywhere.
Un altro esempio, "Acme Company ha una politica secondo cui l'ora di pranzo inizia alle 12:30 PM in ciascuna delle sue fabbriche in tutto il mondo" è un LocalTime
. Per avere un significato reale è necessario applicarlo alla cronologia per capire il momento delle 12:30 presso lo stabilimento di Stoccarda o le 12:30 presso lo stabilimento di Rabat o le 12:30 presso lo stabilimento di Sydney .
Prenotazione appuntamenti
Un'altra situazione da utilizzare LocalDateTime
è la prenotazione di eventi futuri (es: appuntamenti dal dentista). Questi appuntamenti potrebbero essere abbastanza lontani in futuro da rischiare che i politici ridefiniscano il fuso orario. I politici spesso prestano poca attenzione o addirittura nessun avvertimento. Se intendi "15:00 il prossimo 23 gennaio", indipendentemente da come i politici possano giocare con l'orologio, allora non puoi registrare un momento - ciò vedrebbe le 15:00 trasformarsi in 14:00 o 16:00 se quella regione adottasse o abbandonasse l'ora legale, per esempio.
Per gli appuntamenti, conservare a LocalDateTime
e a ZoneId
, conservati separatamente. Successivamente, durante la generazione di una pianificazione, determinare al volo un momento chiamando LocalDateTime::atZone( ZoneId )
per generare un ZonedDateTime
oggetto.
ZonedDateTime zdt = ldt.atZone( z ) ; // Given a date, a time-of-day, and a time zone, determine a moment, a point on the timeline.
Se necessario, è possibile regolare su UTC. Estrai un Instant
da ZonedDateTime
.
Instant instant = zdt.toInstant() ; // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.
Zona sconosciuta
Alcune persone potrebbero utilizzare LocalDateTime
in una situazione in cui il fuso orario o l'offset non sono noti.
Ritengo questo caso inappropriato e poco saggio. Se una zona o un offset sono previsti ma indeterminati, si hanno dati errati. Sarebbe come conservare un prezzo di un prodotto senza conoscere la valuta prevista. Non è una buona idea.
Tutti i tipi di data e ora
Per completezza, ecco una tabella di tutti i possibili tipi di data e ora, sia moderni che legacy in Java, oltre a quelli definiti dallo standard SQL. Questo potrebbe aiutare a collocare le classi Instant
& LocalDateTime
in un contesto più ampio.
Notare le strane scelte fatte dal team Java nella progettazione di JDBC 4.2. Hanno scelto di supportare tutti i tempi di java.time ... ad eccezione delle due classi più comunemente usate: Instant
& ZonedDateTime
.
Ma non preoccuparti. Possiamo facilmente convertire avanti e indietro.
Conversione Instant
.
// Storing
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
Conversione ZonedDateTime
.
// Storing
OffsetDateTime odt = zdt.toOffsetDateTime() ;
myPreparedStatement.setObject( … , odt ) ;
// Retrieving
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;
Informazioni su java.time
Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantare la vecchia fastidiosi legacy classi data-time come java.util.Date
, Calendar
, e SimpleDateFormat
.
Il progetto Joda-Time , ora in modalità manutenzione , consiglia la migrazione alle classi java.time .
Per saperne di più, consulta il tutorial Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .
Puoi scambiare oggetti java.time direttamente con il tuo database. Utilizzare un driver JDBC conforme a JDBC 4.2 o successivo. Nessuna necessità di stringhe, nessuna necessità di java.sql.*
classi.
Dove ottenere le classi java.time?
Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un banco di prova per possibili aggiunte future a java.time. Si possono trovare alcune classi utili, come per esempio Interval
, YearWeek
, YearQuarter
e altro .