Java-Zeitzone als GMT / UTC erzwingen

94

Ich muss alle zeitbezogenen Vorgänge auf GMT / UTC erzwingen, unabhängig von der auf der Maschine eingestellten Zeitzone. Gibt es eine bequeme Möglichkeit, dies im Code zu tun?

Zur Verdeutlichung verwende ich die DB-Serverzeit für alle Vorgänge, sie wird jedoch entsprechend der lokalen Zeitzone formatiert.

Vielen Dank!

SyBer
quelle
Eigentlich ist sein Problem eine Teilmenge von mir, aber ich habe eine Lösung gefunden.
SyBer
Schauen Sie sich die doppelte Frage an und suchen Sie nach "Joda" und "DateTimeZone".
Basil Bourque

Antworten:

123

Das OP beantwortete diese Frage, um die Standardzeitzone für eine einzelne Instanz einer laufenden JVM zu ändern. Legen Sie die user.timezoneSystemeigenschaft fest:

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

Wenn Sie beim Abrufen von Datums- / Zeit- / Zeitstempelobjekten aus einer Datenbank bestimmte Zeitzonen festlegen müssen ResultSet, verwenden Sie die zweite Form der getXXXMethoden, die ein CalendarObjekt annehmen:

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

Oder legen Sie das Datum in einem PreparedStatement fest:

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

Dadurch wird sichergestellt, dass der in der Datenbank gespeicherte Wert konsistent ist, wenn die Datenbankspalte keine Zeitzoneninformationen enthält.

Die Klassen java.util.Dateund java.sql.Datespeichern die tatsächliche Zeit (Millisekunden) in UTC. Verwenden Sie diese Option, um diese bei der Ausgabe in eine andere Zeitzone zu formatieren SimpleDateFormat. Sie können dem Wert auch eine Zeitzone mithilfe eines Kalenderobjekts zuordnen:

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

Nützliche Referenz

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

Kevin Brock
quelle
Beim Festlegen der Zeitzone für die gesamte JVM ist zu beachten, dass sie sich auf alles auswirkt, einschließlich der Protokollierung. Nur etwas zu beachten, wenn dies der gewünschte Effekt ist.
Hermann Hans
Ja, das ist gut. Nur ein Punkt zu erwähnen, dass ich die user.timezone tatsächlich direkt im Code und nicht über den Parameter -D gesetzt habe.
SyBer
6
@SyBer: Das funktioniert, aber Sie müssen sicherstellen, dass Sie dies festlegen, bevor eine Methode die TimeZone.getDefault () -Methode aufruft. Wenn nicht, werden Sie einige Verwirrung haben, da der Standard nach der ersten Ausführung zwischengespeichert wird. Dies bedeutet auch, dass es ein Problem sein kann, wenn Sie dies in einer API / Bibliothek tun (nicht sichtbar). Stellen Sie sicher, dass Sie genau dokumentieren, was Sie tun.
Kevin Brock
23

Auch wenn Sie die JVM-Zeitzone auf diese Weise einstellen können

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

oder -Duser.timezone=GMTin den JVM-Argumenten.

MG Entwickler
quelle
System.setProperty("user.timezone" ...)funktioniert nicht
Wilmol
9

Sie können die Zeitzone mit TimeZone.setDefault () ändern :

TimeZone.setDefault(TimeZone.getTimeZone("GMT"))
Snorbi
quelle
Nichts für ungut, aber vorübergehend einen globalen statischen Zustand
G. Demecki
Sie könnten, aber Sie sollten nicht. Dies ist ein außerordentlich schlechter Rat. Die Zeitzone der gesamten JVM wurde geändert.
Scot
1
Manchmal ist es genau das, was Sie erreichen wollen. Z.B. Ich habe gesehen, dass Java-basierte Mikrodienste immer mit UTC ausgeführt werden, um Zeitzonenprobleme zu vermeiden. In diesen Systemen wird das Datenbank-Backend auch mit UTC ausgeführt, daher ist es natürlich, die JVM auch auf UTC zu "zwingen". Was ist wichtig: Sie müssen wissen, was Sie tun und was die Konsequenzen sind ...
Snorbi
absolut nicht. Wenn Sie Ihr gesamtes System in UTC haben möchten (eine sehr gute Idee), setzen Sie die Systemzeitzone auf UTC und lassen Sie die Java-Zeitzone in Ruhe.
Scot
3
Außer wenn Sie mehrere JVMs mit unterschiedlichen Anforderungen haben. Wir können für immer streiten, aber jeder Fall ist einzigartig: Manchmal müssen Sie die Zeitzone des gesamten Systems festlegen, manchmal müssen Sie nur eine JVM festlegen. Seien wir froh, dass die heutigen Systeme so flexibel sind, dass wir beides können sn
snorbi
8

für mich nur schnell 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"));
  }

Formatieren Sie dann das Datum mit einer anderen Zeitzone.

lwpro2
quelle
6

Ich würde die Zeit in einer Rohform (langer Zeitstempel oder Java-Datum) aus der Datenbank abrufen und sie dann mit SimpleDateFormat formatieren oder mit Calendar bearbeiten. In beiden Fällen sollten Sie die Zeitzone der Objekte festlegen, bevor Sie sie verwenden.

Siehe SimpleDateFormat.setTimeZone(..)und Calendar.setTimeZone(..)für Details

Eyal Schneider
quelle
6

tl; dr

String sql = "SELECT CURRENT_TIMESTAMP ;

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

Vermeiden Sie je nach Host-Betriebssystem oder JVM die Standardzeitzone

Ich empfehle Ihnen, Ihren gesamten Code zu schreiben, um die gewünschte / erwartete Zeitzone explizit anzugeben. Sie müssen nicht von der aktuellen Standardzeitzone der JVM abhängig sein. Beachten Sie außerdem, dass sich die aktuelle Standardzeitzone der JVM jederzeit zur Laufzeit ändern kann, wobei jeder Code in einem beliebigen Thread einer App aufgerufen wird TimeZone.setDefault. Ein solcher Aufruf wirkt sich sofort auf alle Apps in dieser JVM aus.

java.time

Einige der anderen Antworten waren korrekt, aber jetzt veraltet. Die schrecklichen Datums- / Uhrzeitklassen, die mit den frühesten Versionen von Java gebündelt wurden, waren fehlerhaft und wurden von Personen geschrieben, die die Komplexität und Feinheiten der Datums- / Uhrzeitbehandlung nicht verstanden hatten.

Die alten Datums- und Uhrzeitklassen wurden durch die ersetzt alten Datums- / Uhrzeitklassen wurden in JSR 310 definierten java.time- Klassen ersetzt.

Verwenden Sie, um eine Zeitzone darzustellen ZoneId. Verwenden Sie, um einen Versatz von UTC darzustellenZoneOffset . Ein Versatz ist lediglich eine Anzahl von Stunden-Minuten-Sekunden vor oder hinter dem Nullmeridian. Eine Zeitzone ist viel mehr. Eine Zeitzone ist eine Geschichte der vergangenen, gegenwärtigen und zukünftigen Änderungen des Versatzes, den die Menschen einer bestimmten Region verwenden.

Ich muss alle zeitbezogenen Operationen zu GMT / UTC erzwingen

Verwenden Sie für einen Versatz von null Stunden-Minuten-Sekunden die Konstante ZoneOffset.UTC.

Instant

Verwenden Sie eine, um den aktuellen Moment in UTC zu erfassen Instant. Diese Klasse repräsentiert einen Moment in UTC, per Definition immer in UTC.

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

ZonedDateTime

Stellen Sie sich auf eine Zeitzone ein, um denselben Moment durch die Wanduhrzeit zu sehen, die von den Menschen einer bestimmten Region verwendet wird. Gleicher Moment, gleicher Punkt auf der Zeitachse, andere Wanduhrzeit.

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

Datenbank

Sie erwähnen eine Datenbank.

Um einen Moment aus der Datenbank abzurufen, sollte Ihre Spalte einen Datentyp haben, der dem SQL-Standard ähnelt TIMESTAMP WITH TIME ZONE. Rufen Sie ein Objekt anstelle einer Zeichenfolge ab. In JDBC 4.2 und höher können wir java.time- Objekte mit der Datenbank austauschen . Das OffsetDateTimewird von JDBC benötigt, während Instant& ZonedDateTimeoptional sind.

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

In den meisten Datenbanken und Treibern würde ich vermuten, dass Sie den Moment wie in UTC sehen werden. Wenn nicht, können Sie auf zwei Arten anpassen:

  • Auszug a Instant: odt.toInstant()
  • Passen Sie den angegebenen Offset auf einen Offset von Null an: OffsetDateTime odtUtc = odt.withOffsetSameInstant (ZoneOffset.UTC); `.

Tabelle der Datums- und Uhrzeittypen in Java (sowohl Legacy als auch Modern) und in Standard-SQL


Über java.time

Das java.time- Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie java.util.Date, Calendar, & SimpleDateFormat.

Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .

Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .

Sie können java.time- Objekte direkt mit Ihrer Datenbank austauschen . Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist . Keine Notwendigkeit für Strings, keine Notwendigkeit für java.sql.*Klassen.

Woher bekomme ich die java.time-Klassen?

Basil Bourque
quelle
1

Erstellen Sie ein Client / Server-Paar, damit der Client-Server nach der Ausführung die richtige Uhrzeit und das richtige Datum sendet. Dann fragt der Client den Server nach GMT und der Server sendet die Antwort richtig zurück.

Bertan
quelle
1

Verwenden Sie die Systemeigenschaft:

-Duser.timezone=UTC
Dawid Stępień
quelle
5
Warum sollte man das benutzen? Bitte fügen Sie Ihrer Antwort eine Erklärung hinzu, damit andere daraus lernen können
Nico Haase
1

Führen Sie diese Zeile in MySQL aus, um Ihre Zeitzone zurückzusetzen:

SET @@global.time_zone = '+00:00';
Saeed
quelle
0

Beeindruckend. Ich weiß, dass dies ein alter Thread ist, aber alles, was ich sagen kann, ist, TimeZone.setDefault () in keinem Code auf Benutzerebene aufzurufen. Dies legt immer die Zeitzone für die gesamte JVM fest und ist fast immer eine sehr schlechte Idee. Erfahren Sie, wie Sie die Bibliothek joda.time oder die neue DateTime-Klasse in Java 8 verwenden, die der Bibliothek joda.time sehr ähnlich ist.

Schotte
quelle
-6

Wenn Sie GMT-Zeit nur mit intiger erhalten möchten: 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)
Incmos
quelle
5
das sieht für mich nach JavaScript (! = Java) aus.
Phil