Forza il fuso orario di Java come GMT / UTC


95

Devo forzare qualsiasi operazione relativa all'ora su GMT / UTC, indipendentemente dal fuso orario impostato sulla macchina. Qualche modo conveniente per farlo nel codice?

Per chiarire, sto usando l'ora del server DB per tutte le operazioni, ma risulta formattata in base al fuso orario locale.

Grazie!


In realtà, il suo problema è un mio sottoinsieme, ma ho trovato una soluzione.
SyBer

Guarda la domanda duplicata e cerca "Joda" e "DateTimeZone".
Basil Bourque

Risposte:


124

L'OP ha risposto a questa domanda per modificare il fuso orario predefinito per una singola istanza di una JVM in esecuzione, impostare la user.timezoneproprietà di sistema:

java -Duser.timezone=GMT ... <main-class>

Se è necessario impostare fusi orari specifici quando si recuperano oggetti Data / Ora / Timestamp da un database ResultSet, utilizzare la seconda forma dei getXXXmetodi che accettano un Calendaroggetto:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
ResultSet rs = ...;
while (rs.next()) {
    Date dateValue = rs.getDate("DateColumn", tzCal);
    // Other fields and calculations
}

Oppure, impostando la data in un PreparedStatement:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
PreparedStatement ps = conn.createPreparedStatement("update ...");
ps.setDate("DateColumn", dateValue, tzCal);
// Other assignments
ps.executeUpdate();

Ciò garantirà che il valore memorizzato nel database sia coerente quando la colonna del database non conserva le informazioni sul fuso orario.

Le classi java.util.Datee java.sql.Datememorizzano l'ora effettiva (millisecondi) in UTC. Per formattarli in uscita su un altro fuso orario, utilizzare SimpleDateFormat. Puoi anche associare un fuso orario al valore utilizzando un oggetto Calendar:

TimeZone tz = TimeZone.getTimeZone("<local-time-zone>");
//...
Date dateValue = rs.getDate("DateColumn");
Calendar calValue = Calendar.getInstance(tz);
calValue.setTime(dateValue);

Riferimento utile

https://docs.oracle.com/javase/9/troubleshoot/time-zone-settings-jre.htm#JSTGD377

https://confluence.atlassian.com/kb/setting-the-timezone-for-the-java-environment-841187402.html


Una cosa da notare sull'impostazione del fuso orario per l'intera JVM è che influisce su tutto, comprese cose come la registrazione. Solo qualcosa da tenere a mente se questo è l'effetto desiderato.
Hermann Hans

Sì, va bene così. Solo un punto da menzionare, che in realtà ho impostato user.timezone direttamente nel codice, piuttosto che tramite il parametro -D.
SyBer

6
@SyBer: funziona ma devi assicurarti di impostarlo prima che qualsiasi metodo chiami il metodo TimeZone.getDefault (). In caso contrario, avrai un po 'di confusione poiché l'impostazione predefinita viene memorizzata nella cache dopo la prima esecuzione. Ciò significa anche che potrebbe essere un problema se lo fai all'interno di un'API / libreria (nascosta alla vista normale): assicurati di documentare pesantemente ciò che stai facendo.
Kevin Brock

23

Anche se puoi impostare il fuso orario JVM in questo modo

System.setProperty("user.timezone", "EST");

o -Duser.timezone=GMTnegli argomenti JVM.


System.setProperty("user.timezone" ...)non funziona.
Wilmol


9

È possibile modificare il fuso orario utilizzando TimeZone.setDefault () :

TimeZone.setDefault(TimeZone.getTimeZone("GMT"))

Senza offesa, ma modificare temporaneamente uno stato statico globale suona come una pessima idea ...
G. Demecki

Potresti, ma non dovresti. Questo è un consiglio straordinariamente pessimo. L'intera JVM ha il suo fuso orario cambiato.
1919

1
A volte è esattamente quello che vuoi ottenere. Per esempio. Ho visto microservizi basati su Java in esecuzione sempre con UTC per evitare problemi di fuso orario. In questi sistemi il backend del database funziona anche con UTC, quindi è naturale "forzare" anche la JVM su UTC. Ciò che è importante: devi sapere cosa stai facendo e quali sono le conseguenze ...
snorbi

assolutamente no. Se vuoi l'intero sistema in UTC (un'idea molto buona), imposta il fuso orario di sistema su UTC e lascia solo il fuso orario di Java.
1919

3
Tranne se hai più JVM con requisiti diversi. Possiamo litigare all'infinito ma ogni caso è unico: a volte è necessario impostare il fuso orario dell'intero sistema, a volte si imposta solo una JVM. Siamo felici che i sistemi di oggi siano così flessibili da poter fare entrambe le cose 😉
snorbi

8

per me, solo veloce SimpleDateFormat,

  private static final SimpleDateFormat GMT = new SimpleDateFormat("yyyy-MM-dd");
  private static final SimpleDateFormat SYD = new SimpleDateFormat("yyyy-MM-dd");
  static {
      GMT.setTimeZone(TimeZone.getTimeZone("GMT"));
    SYD.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
  }

quindi formatta la data con un fuso orario diverso.


6

Recupererei l'ora dal DB in una forma non elaborata (timestamp lungo o data di java), quindi utilizzerei SimpleDateFormat per formattarlo o Calendar per manipolarlo. In entrambi i casi è necessario impostare il fuso orario degli oggetti prima di utilizzarlo.

Vedi SimpleDateFormat.setTimeZone(..)e Calendar.setTimeZone(..)per i dettagli


6

tl; dr

String sql = "SELECT CURRENT_TIMESTAMP ;

OffsetDateTime odt = myResultSet.getObject( 1 , OffsetDateTime.class ) ;

Evita di dipendere dal sistema operativo host o dalla JVM per il fuso orario predefinito

Ti consiglio di scrivere tutto il tuo codice per indicare esplicitamente il fuso orario desiderato / previsto. Non è necessario dipendere dall'attuale fuso orario predefinito della JVM. E tieni presente che l'attuale fuso orario predefinito della JVM può cambiare in qualsiasi momento durante il runtime, con qualsiasi codice in qualsiasi thread di qualsiasi chiamata di app TimeZone.setDefault. Tale chiamata influisce immediatamente su tutte le app all'interno di quella JVM.

java.time

Alcune delle altre risposte erano corrette, ma ora sono antiquate. Le terribili classi data-ora in bundle con le prime versioni di Java erano difettose, scritte da persone che non capivano le complessità e le sottigliezze della gestione data-ora.

Le classi data-ora precedenti sono state soppiantate dalle classi java.time definite in JSR 310.

Per rappresentare un fuso orario, utilizzare ZoneId. Per rappresentare un offset da UTC, utilizzare ZoneOffset. Un offset è semplicemente un numero di ore-minuti-secondi avanti o indietro rispetto al primo meridiano. Un fuso orario è molto di più. Un fuso orario è una storia delle modifiche passate, presenti e future all'offset utilizzato dalle persone di una determinata regione.

Devo forzare qualsiasi operazione relativa all'ora su GMT / UTC

Per un offset di zero ore-minuti-secondi, usa la costante ZoneOffset.UTC.

Instant

Per catturare il momento corrente in UTC, usa un file Instant. Questa classe rappresenta un momento in UTC, sempre in UTC per definizione.

Instant instant = Instant.now() ;  // Capture current moment in UTC.

ZonedDateTime

Per vedere quello stesso momento attraverso l'ora dell'orologio da parete utilizzata dalle persone di una particolare regione, regola un fuso orario. Stesso momento, stesso punto sulla timeline, diverso tempo dell'orologio da parete.

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Banca dati

Parli di un database.

Per recuperare un momento dal database, la colonna dovrebbe essere di un tipo di dati simile allo standard SQL TIMESTAMP WITH TIME ZONE. Recupera un oggetto anziché una stringa. In JDBC 4.2 e versioni successive, possiamo scambiare oggetti java.time con il database. Il OffsetDateTimeè richiesto da JDBC, mentre Instante ZonedDateTimesono opzionali.

OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;

Nella maggior parte dei database e dei driver, immagino che otterrai il momento come visto in UTC. In caso contrario, puoi effettuare la regolazione in uno dei due modi:

  • Estrai un Instant: odt.toInstant()
  • Regola dall'offset dato a uno zero: OffsetDateTime odtUtc = odt.withOffsetSameInstant (ZoneOffset.UTC); `.

Tabella dei tipi di data e ora in Java (sia legacy che moderno) e in SQL standard


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.

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à di manutenzione , consiglia la migrazione alle classi java.time .

Puoi scambiare oggetti java.time direttamente con il tuo database. Utilizza un driver JDBC conforme a JDBC 4.2 o successivo. Non c'è bisogno di stringhe, non c'è bisogno di java.sql.*classi.

Dove ottenere le classi java.time?


1

creare una coppia client / server, in modo che dopo l'esecuzione, client server invii l'ora e la data corrette. Quindi, il client chiede al server pm GMT e il server restituisce la risposta giusta.


1

Usa proprietà di sistema:

-Duser.timezone=UTC

5
Perché dovresti usarlo? Per favore aggiungi qualche spiegazione alla tua risposta in modo che altri possano imparare da essa
Nico Haase

1

Esegui questa riga in MySQL per reimpostare il fuso orario:

SET @@global.time_zone = '+00:00';

0

Wow. So che questo è un thread antico, ma tutto quello che posso dire è di non chiamare TimeZone.setDefault () in nessun codice a livello utente. Questo imposta sempre il fuso orario per l'intera JVM ed è quasi sempre una pessima idea. Impara a usare la libreria joda.time o la nuova classe DateTime in Java 8 che è molto simile alla libreria joda.time.


-6

Se desideri ottenere l'ora GMT solo con intiger: var currentTime = new Date (); var currentYear = "2010" var currentMonth = 10; var currentDay = '30 'var currentHours = '20' var currentMinutes = '20 'var currentSeconds = '00' var currentMilliseconds = '00 '

currentTime.setFullYear(currentYear);
currentTime.setMonth((currentMonth-1)); //0is January
currentTime.setDate(currentDay);  
currentTime.setHours(currentHours);
currentTime.setMinutes(currentMinutes);
currentTime.setSeconds(currentSeconds);
currentTime.setMilliseconds(currentMilliseconds);

var currentTimezone = currentTime.getTimezoneOffset();
currentTimezone = (currentTimezone/60) * -1;
var gmt ="";
if (currentTimezone !== 0) {
  gmt += currentTimezone > 0 ? ' +' : ' ';
  gmt += currentTimezone;
}
alert(gmt)

5
a me sembra JavaScript (! = Java).
Phil
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.