C'è un modo per convertire ZoneId in ZoneOffset in Java 8?


89

Ho un epoch second e un zoneId, per method1.Può essere convertito in LocalDateTime con zoneId predefinito di sistema, ma non trovo il modo per convertire epoch second in LocalDateTime con il metodo2, perché non c'è ZoneOffset.systemDefault. Penso che sia oscuro.

import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}

val epochSecond = System.currentTimeMillis() / 1000

LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault())//method1
LocalDateTime.ofEpochSecond(epochSecond, 0, ZoneOffset.MAX)//method2

Quale lingua / dialetto stai usando per far funzionare l'importazione di massa import java.time.{Instant, LocalDateTime, ZoneId, ZoneOffset}? È unexpected tokenper me in Java 11.
anddero

1
Può essere Scala, ma non è molto importante qui
donatas M

1
Ho discusso a lungo la teoria java.timealla base qui: stackoverflow.com/a/56508200/145989
Ondra Žižka

Risposte:


113

Ecco come puoi ottenere ZoneOffsetda ZoneId:

Instant instant = Instant.now(); //can be LocalDateTime
ZoneId systemZone = ZoneId.systemDefault(); // my timezone
ZoneOffset currentOffsetForMyZone = systemZone.getRules().getOffset(instant);

NB: ZoneIdpuò avere offset diversi a seconda del momento e della storia del luogo particolare. Quindi la scelta di istanti diversi comporterebbe offset diversi.

NB2: ZoneId.of()può restituire a ZoneOffsetinvece di ZoneIdse UTC+3/ GMT+2/ etc viene passato al contrario di un fuso orario come Africa/Cairo. Quindi, se vengono trasmessi offset UTC / GMT, le informazioni storiche / geografiche / ora legale di Instantnon verranno prese in considerazione: lavorerai semplicemente con l'offset specificato.


Questo fornisce un valore errato se l'istante corrente è in DST, ma al momento del calcolo era senza DST
msangel

@msangel, puoi ricontrollarlo? Forse stai usando ZoneId.systemDefault()nel tuo codice e restituisce fusi orari diversi su macchine diverse?
Stanislav Bashkyrtsev

L'ho controllato e funziona a seconda di un'altra condizione. Risposta aggiornata con quello.
msangel

43

Non esiste una mappatura uno a uno. Uno ZoneId definisce un'estensione geografica in cui un insieme di diversi ZoneOffset viene utilizzato nel tempo. Se il fuso orario utilizza l'ora legale, il suo ZoneOffset sarà diverso tra estate e inverno.

Inoltre, le regole dell'ora legale potrebbero essere cambiate nel tempo, quindi lo ZoneOffset potrebbe essere diverso per es. 13/10/2015 rispetto al 13/10/1980.

Quindi puoi trovare lo ZoneOffset per uno ZoneId solo su un particolare Instant.

Vedi anche https://en.wikipedia.org/wiki/Tz_database


10
Lo so, ma come si fa? Se conosco LocaDate e ho uno ZoneId, come posso convertirlo in uno ZoneOffset. Il mio caso d'uso è una stringa che contiene un'ora e una zona. Voglio analizzare la stringa in un OffsetTime, senza eliminare le informazioni sulla zona.
Kai Moritz

35

tl; dr

ZonedDateTime.now( 
    ZoneId.of( "America/Montreal" ) 
)

... del fuso orario predefinito corrente ...

ZonedDateTime.now( 
    ZoneId.systemDefault() 
)

Dettagli

La risposta di Stanislav Bshkyrtsev risponde correttamente e direttamente alla tua domanda.

Ma ci sono problemi più grandi coinvolti, come suggerito nella risposta di Jon Skeet .

LocalDateTime

Non trovo il modo per convertire epoch second in LocalDateTime

LocalDateTimeintenzionalmente non ha il concetto di fuso orario o offset da UTC. Probabilmente non è quello che vuoi. La Local…significa qualsiasi frazione, non una qualsiasi località particolare. Questa classe lo fa non rappresenta un momento, ma solo potenziali momenti lungo un intervallo di circa 26-27 ore (l'intervallo di fusi orari in tutto il mondo).

Instant

Non è necessario iniziare con epoche secondi se stai cercando di ottenere l'ora corrente. Ottieni la corrente Instant. La Instantclasse rappresenta un momento sulla sequenza temporale in UTC con una risoluzione di nanosecondi (fino a nove (9) cifre di una frazione decimale).

Instant instant = Instant.now();

All'interno di quello Instant c'è un conteggio di nanosecondi , dall'epoca. Ma non ci interessa davvero.

ZonedDateTime

Se vuoi vedere quel momento attraverso la lente dell'orologio da parete di una particolare regione, applica un ZoneId per ottenere un ZonedDateTime.

ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdt = instant.atZone( z );

Come scorciatoia, puoi fare direttamente al file ZonedDateTime .

ZonedDateTime zdt = ZonedDateTime.now( z );  

A ZonedDateTimeha un al Instantsuo interno. Chiama zdt.toInstant()per ottenere lo stesso momento nel tempo come valore di base in UTC . Stesso numero di nanosecondi dall'epoca in entrambi i casi, come ZonedDateTimeao come a Instant.

Secondi dall'epoca dati

Se ti viene dato un conteggio dei secondi dall'epoca e l'epoca è il primo momento del 1970 in UTC ( 1970-01-01T00:00:00Z), inserisci quel numero a Instant.

long secondsSinceEpoch = 1_484_063_246L ;
Instant instant = Instant.ofEpochSecond( secondsSinceEpoch ) ;

Tabella dei tipi di data e ora in Java, sia moderni che legacy.


Di java.time

Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantano le fastidiose vecchie classi data-ora legacy come java.util.Date,Calendar , e SimpleDateFormat.

Per saperne di più, vedere il tutorial Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .

Il progetto Joda-Time , ora in modalità manutenzione , consiglia la migrazione alle classi java.time .

Puoi scambiare oggetti java.time direttamente con il tuo database. Utilizza un driver JDBC compatibile con JDBC 4.2 o successivo. Non c'è bisogno di stringhe, non c'è bisogno 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 future aggiunte a java.time. Si possono trovare alcune classi utili, come per esempio Interval, YearWeek, YearQuartere altro .


10

Come dice la documentazione , "Questo è inteso principalmente per conversioni di basso livello piuttosto che per l'utilizzo generale dell'applicazione".

Andare via Instantha perfettamente senso per me: la tua epoca secondo è effettivamente una rappresentazione diversa di un Instant, quindi convertilo in un Instante poi convertilo in un particolare fuso orario.


9

Spero che le prime due righe della mia soluzione di seguito siano utili. Il mio problema era che avevo un LocalDateTimee il nome di un fuso orario, e ne avevo bisogno in instantmodo da poterlo costruire java.util.Date, perché era quello che voleva MongoDB. Il mio codice è Scala, ma è così vicino a Java qui penso che non dovrebbero esserci problemi a capirlo:

val zid = ZoneId.of(tzName)                                // "America/Los_Angeles"
val zo: ZoneOffset = zid.getRules.getOffset(localDateTime) // ⇒ -07:00
                                         // 2017-03-16T18:03

val odt = OffsetDateTime.of(localDateTime, zo) // ⇒ 2017-03-16T18:03:00-07:00
val instant = odt.toInstant                    // ⇒ 2017-03-17T01:03:00Z
val issued = Date.from(instant)

1
Ho pubblicato questa risposta qui perché questa era la pagina che è venuta fuori quando stavo cercando un modo per fare quello che alla fine ho capito.
gknauth

2

Quanto segue restituisce la quantità di tempo in millisecondi da aggiungere a UTC per ottenere l'ora standard in questo fuso orario:

TimeZone.getTimeZone(ZoneId.of("Europe/Amsterdam")).getRawOffset()

0

Ho un Epoch Second e un zoneId. C'è un modo per convertire ZoneId in ZoneOffset in Java 8?

  1. Ottenere ZonedDateTime da Epoch Second e Zone Id
  2. Ottieni ZoneOffsetdaZonedDateTime

Demo:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        // Get ZonedDateTime from epoch second and Zone Id
        ZonedDateTime zdt = Instant.ofEpochSecond(1597615462L).atZone(ZoneId.of("Europe/London"));

        // Get ZoneOffset from ZonedDateTime
        ZoneOffset offset = zdt.getOffset();

        System.out.println(offset);
    }
}

Produzione:

+01:00
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.