Ich habe einen Zeitstempelwert, der aus meiner Anwendung stammt. Der Benutzer kann sich in einer bestimmten lokalen Zeitzone befinden.
Da dieses Datum für einen WebService verwendet wird, der davon ausgeht, dass die angegebene Zeit immer in GMT angegeben ist, muss der Parameter des Benutzers von say (EST) in (GMT) konvertiert werden. Hier ist der Kicker: Der Benutzer ist sich seiner TZ nicht bewusst. Er gibt das Erstellungsdatum ein, das er an das WS senden möchte. Ich brauche also Folgendes:
Benutzer gibt ein: 01.05.2008 18:12 Uhr (EST)
Der Parameter für das WS muss sein : 01.05.2008 18:12 Uhr (GMT)
Ich weiß, dass TimeStamps standardmäßig immer in GMT sein sollen, aber beim Senden des Parameters sind die Stunden immer ausgeschaltet, obwohl ich meinen Kalender aus dem TS erstellt habe (der in GMT sein soll), es sei denn, der Benutzer ist in GMT. Was vermisse ich?
Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
...
private static java.util.Calendar convertTimestampToJavaCalendar(Timestamp ts_) {
java.util.Calendar cal = java.util.Calendar.getInstance(
GMT_TIMEZONE, EN_US_LOCALE);
cal.setTimeInMillis(ts_.getTime());
return cal;
}
Mit dem vorherigen Code erhalte ich Folgendes (Kurzformat zum einfachen Lesen):
[1. Mai 2008, 23:12 Uhr]
Antworten:
Hier ist die Ausgabe, wenn ich die aktuelle Zeit ("12:09:05 EDT" von
Calendar.getInstance()
) in übergebe:12:09:05 GMT ist 8:09:05 EDT.
Der verwirrende Teil hier ist, dass
Calendar.getTime()
Sie eineDate
in Ihrer aktuellen Zeitzone zurückgeben und dass es keine Methode gibt, die Zeitzone eines Kalenders zu ändern und das zugrunde liegende Datum ebenfalls zu rollen. Abhängig davon, welche Art von Parameter Ihr Webdienst verwendet, möchten Sie möglicherweise nur den WS-Deal in Millisekunden ab der Epoche.quelle
offsetFromUTC
anstatt es zu addieren? Wenn in Ihrem Beispiel 12:09 GMT 8:09 EDT ist (was wahr ist) und der Benutzer "12:09 EDT" eingibt, sollte der Algorithmus meiner Meinung nach "16:09 GMT" ausgeben.Vielen Dank für Ihre Antwort. Nach einer weiteren Untersuchung kam ich zur richtigen Antwort. Wie von Skip Head erwähnt, wurde der Zeitstempel, den ich von meiner Anwendung erhielt, an die Zeitzone des Benutzers angepasst. Wenn der Benutzer also 18:12 Uhr (EST) eingibt, erhalte ich 14:12 Uhr (GMT). Was ich brauchte, war eine Möglichkeit, die Konvertierung rückgängig zu machen, sodass die vom Benutzer eingegebene Zeit die Zeit ist, die ich an die WebServer-Anforderung gesendet habe. So habe ich das erreicht:
Die Ausgabe des Codes lautet: (Benutzer eingegeben am 01.05.2008, 18:12 Uhr (EST)
Zeitzone des aktuellen Benutzers: EST Aktueller Versatz von GMT (in Stunden): - 4 (Normalerweise -5, außer DST angepasst)
TS von ACP: 2008-05-01 14: 12: 00.0
Kalenderdatum von TS mit GMT und US_EN-Gebietsschema konvertiert : 01.05.08 18:12 Uhr (GMT)
quelle
Sie sagen, dass das Datum in Verbindung mit Webdiensten verwendet wird, also gehe ich davon aus, dass es irgendwann zu einer Zeichenfolge serialisiert wird.
In diesem Fall sollten Sie sich die setTimeZone-Methode der DateFormat-Klasse ansehen. Dies bestimmt, welche Zeitzone beim Drucken des Zeitstempels verwendet wird.
Ein einfaches Beispiel:
quelle
Sie können es mit Joda Time lösen :
Java 8:
quelle
Es sieht so aus, als würde Ihr TimeStamp auf die Zeitzone des Ursprungssystems eingestellt.
Dies ist veraltet, aber es sollte funktionieren:
Der nicht veraltete Weg ist zu verwenden
Dies müsste jedoch auf der Client-Seite erfolgen, da dieses System weiß, in welcher Zeitzone es sich befindet.
quelle
Methode zum Konvertieren von einer Zeitzone in eine andere (wahrscheinlich funktioniert es :)).
quelle
Datums- und Zeitstempelobjekte sind zeitzonenunabhängig: Sie repräsentieren eine bestimmte Anzahl von Sekunden seit der Epoche, ohne sich auf eine bestimmte Interpretation dieses Augenblicks als Stunden und Tage festzulegen. Zeitzonen geben das Bild nur in GregorianCalendar (für diese Aufgabe nicht direkt erforderlich) und SimpleDateFormat ein , die einen Zeitzonenversatz benötigen, um zwischen separaten Feldern und Datumswerten (oder langen Werten) zu konvertieren .
Das Problem des OP liegt gleich zu Beginn seiner Verarbeitung: Der Benutzer gibt Stunden ein, die nicht eindeutig sind und in der lokalen Zeitzone ohne GMT interpretiert werden. Zu diesem Zeitpunkt ist der Wert "6:12 EST" , der leicht als "11.12 GMT" oder eine andere Zeitzone gedruckt werden kann, sich jedoch niemals in "6.12 GMT" ändert .
Es gibt keine Möglichkeit, das SimpleDateFormat , das "06:12" als "HH: MM" analysiert (standardmäßig die lokale Zeitzone), stattdessen auf UTC zu setzen. SimpleDateFormat ist ein bisschen zu schlau für sich.
Sie können jedoch jede SimpleDateFormat- Instanz davon überzeugen , die richtige Zeitzone zu verwenden, wenn Sie sie explizit in die Eingabe einfügen: Fügen Sie einfach eine feste Zeichenfolge an die empfangene (und ausreichend validierte) "06:12" an, um "06:12 GMT" als zu analysieren "HH: MM z" .
Es ist nicht erforderlich, GregorianCalendar- Felder explizit festzulegen oder Zeitzonen- und Sommerzeit-Offsets abzurufen und zu verwenden.
Das eigentliche Problem besteht darin, Eingaben zu trennen, die standardmäßig auf die lokale Zeitzone eingestellt sind, Eingaben, die standardmäßig auf UTC eingestellt sind, und Eingaben, für die eine explizite Zeitzonenangabe erforderlich ist.
quelle
In der Vergangenheit hat es für mich funktioniert, den Versatz (in Millisekunden) zwischen der Zeitzone des Benutzers und GMT zu bestimmen. Sobald Sie den Versatz haben, können Sie einfach addieren / subtrahieren (abhängig davon, in welche Richtung die Konvertierung verläuft), um die entsprechende Zeit in jeder Zeitzone zu erhalten. Normalerweise würde ich dies erreichen, indem ich das Millisekundenfeld eines Kalenderobjekts einstelle, aber ich bin sicher, dass Sie es leicht auf ein Zeitstempelobjekt anwenden können. Hier ist der Code, mit dem ich den Offset erhalte
timezoneId ist die ID der Zeitzone des Benutzers (z. B. EST).
quelle
java.time
Der moderne Ansatz verwendet die java.time- Klassen, die die problematischen älteren Datums- / Zeitklassen ersetzen, die mit den frühesten Versionen von Java gebündelt sind.
Die
java.sql.Timestamp
Klasse ist eine dieser Legacy-Klassen. Nicht mehr gebraucht. Verwenden Sie stattdessenInstant
oder andere java.time-Klassen direkt mit Ihrer Datenbank unter Verwendung von JDBC 4.2 und höher.Die
Instant
Klasse repräsentiert einen Moment auf der Zeitachse in UTC mit einer Auflösung von Nanosekunden (bis zu neun (9) Stellen eines Dezimalbruchs).Wenn Sie mit einer vorhandenen zusammenarbeiten müssen
Timestamp
, konvertieren Sie diese sofort in java.time über die neuen Konvertierungsmethoden, die den alten Klassen hinzugefügt wurden.Geben Sie zum Anpassen in eine andere Zeitzone die Zeitzone als
ZoneId
Objekt an. Geben Sie einen richtigen Zeitzonennamen im Formatcontinent/region
, wie zum BeispielAmerica/Montreal
,Africa/Casablanca
oderPacific/Auckland
. Verwenden Sie niemals Pseudozonen mit 3-4 Buchstaben, wie z. B.EST
oderIST
weil sie keine echten Zeitzonen sind, nicht standardisiert und nicht einmal eindeutig (!).Auf das anwenden,
Instant
um einZonedDateTime
Objekt zu erzeugen .Um eine Zeichenfolge für die Anzeige für den Benutzer zu generieren, durchsuchen Sie den Stapelüberlauf
DateTimeFormatter
nach vielen Diskussionen und Beispielen.Bei Ihrer Frage geht es wirklich darum, in die andere Richtung zu gehen, von der Eingabe von Benutzerdaten bis zu den Datums- / Uhrzeitobjekten. Im Allgemeinen ist es am besten, Ihre Dateneingabe in zwei Teile zu unterteilen, ein Datum und eine Uhrzeit.
Ihre Frage ist nicht klar. Möchten Sie das Datum und die Uhrzeit interpretieren, die der Benutzer eingegeben hat, um in UTC zu sein? Oder in einer anderen Zeitzone?
Wenn Sie UTC gemeint haben, erstellen Sie eine
OffsetDateTime
mit einem Offset unter Verwendung der Konstante für UTC ,ZoneOffset.UTC
.Wenn Sie eine andere Zeitzone gemeint haben, kombinieren Sie diese zusammen mit einem Zeitzonenobjekt, a
ZoneId
. Aber welche Zeitzone? Möglicherweise erkennen Sie eine Standardzeitzone. Wenn dies kritisch ist, müssen Sie dies dem Benutzer bestätigen, um sicherzugehen, dass er beabsichtigt ist.Um ein einfacheres Objekt zu erhalten, das sich per Definition immer in UTC befindet, extrahieren Sie ein
Instant
.…oder…
An Ihre Datenbank senden.
Ü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
.Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .
Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .
Woher bekomme ich die java.time-Klassen?
Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von java.time. Sie können einige nützliche Klassen hier wie finden
Interval
,YearWeek
,YearQuarter
, und mehr .quelle