Wenn ich das folgende Programm ausführe, das zwei Datumszeichenfolgen analysiert, die auf Zeiten im Abstand von 1 Sekunde verweisen, und diese vergleicht:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
Date sDt3 = sf.parse(str3);
Date sDt4 = sf.parse(str4);
long ld3 = sDt3.getTime() /1000;
long ld4 = sDt4.getTime() /1000;
System.out.println(ld4-ld3);
}
Die Ausgabe ist:
353
Warum ld4-ld3
nicht 1
(wie ich es von dem Zeitunterschied von einer Sekunde erwarten würde), aber 353
?
Wenn ich die Daten 1 Sekunde später auf mal ändere:
String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";
Dann ld4-ld3
wird es sein 1
.
Java-Version:
java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)
Timezone(`TimeZone.getDefault()`):
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]
Locale(Locale.getDefault()): zh_CN
Antworten:
Es ist eine Zeitzonenänderung am 31. Dezember in Shanghai.
Siehe diese Seite für Details von 1927 in Shanghai. Grundsätzlich gingen die Uhren Ende 1927 um Mitternacht 5 Minuten und 52 Sekunden zurück. "1927-12-31 23:54:08" ist also tatsächlich zweimal passiert, und es sieht so aus, als würde Java es als den später möglichen Zeitpunkt für dieses lokale Datum / diese lokale Uhrzeit analysieren - daher der Unterschied.
Nur eine weitere Episode in der oft seltsamen und wundervollen Welt der Zeitzonen.
EDIT: Hör auf zu drücken! Geschichte ändert sich ...
Die ursprüngliche Frage würde nicht mehr das gleiche Verhalten zeigen, wenn sie mit der Version 2013a von TZDB neu erstellt würde . In 2013a wäre das Ergebnis 358 Sekunden mit einer Übergangszeit von 23:54:03 anstelle von 23:54:08.
Ich habe das nur bemerkt, weil ich in Noda Time Fragen wie diese in Form von Komponententests sammle ... Der Test wurde jetzt geändert, aber er zeigt nur, dass nicht einmal historische Daten sicher sind.
EDIT: Die Geschichte hat sich wieder geändert ...
In der TZDB 2014f hat sich die Zeit der Änderung auf 1900-12-31 verschoben und beträgt jetzt nur noch 343 Sekunden (also beträgt die Zeit zwischen
t
undt+1
344 Sekunden, wenn Sie sehen, was ich meine).BEARBEITEN: Um eine Frage zu einem Übergang um 1900 zu beantworten ... es sieht so aus, als würde die Java-Zeitzonenimplementierung alle Zeitzonen für jeden Moment vor Beginn von 1900 UTC als einfach in ihrer Standardzeit befindlich behandeln :
Der obige Code erzeugt keine Ausgabe auf meinem Windows-Computer. Jede Zeitzone, die zu Beginn des Jahres 1900 einen anderen Versatz als den Standardversatz aufweist, zählt dies als Übergang. TZDB selbst hat einige Daten, die früher zurückreichen, und stützt sich nicht auf eine Idee einer "festen" Standardzeit (was
getRawOffset
als gültiges Konzept angenommen wird), sodass andere Bibliotheken diesen künstlichen Übergang nicht einführen müssen.quelle
Sie haben eine lokale Zeitdiskontinuität festgestellt :
Dies ist nicht besonders seltsam und ist fast überall zu der einen oder anderen Zeit passiert, als Zeitzonen aufgrund politischer oder administrativer Maßnahmen gewechselt oder geändert wurden.
quelle
Die Moral dieser Fremdheit ist:
quelle
Wenn Sie die Zeit erhöhen, sollten Sie zurück in UTC konvertieren und dann addieren oder subtrahieren. Verwenden Sie die Ortszeit nur zur Anzeige.
Auf diese Weise können Sie alle Zeiträume durchlaufen, in denen Stunden oder Minuten zweimal vorkommen.
Wenn Sie in UTC konvertiert haben, fügen Sie jede Sekunde hinzu und konvertieren Sie zur Anzeige in die Ortszeit. Sie würden durch 23:54:08 Uhr LMT - 23:59:59 Uhr LMT und dann 23:54:08 Uhr CST - 23:59:59 Uhr CST gehen.
quelle
Anstatt jedes Datum zu konvertieren, können Sie den folgenden Code verwenden:
Und dann sehen Sie, dass das Ergebnis ist:
quelle
1
, da wir unterschiedliche Gebietsschemas haben.Es tut mir leid zu sagen, aber die Zeitdiskontinuität hat sich etwas verschoben
JDK 6 vor zwei Jahren und in JDK 7 erst kürzlich in Update 25 .
Lektion zu lernen: Vermeiden Sie unbedingt Nicht-UTC-Zeiten, außer vielleicht für die Anzeige.
quelle
Wie von anderen erklärt, gibt es dort eine zeitliche Diskontinuität. Es gibt zwei mögliche Zeitzonenversätze für
1927-12-31 23:54:08
atAsia/Shanghai
, aber nur einen Versatz für1927-12-31 23:54:07
. Je nachdem, welcher Offset verwendet wird, gibt es entweder einen Unterschied von einer Sekunde oder einen Unterschied von 5 Minuten und 53 Sekunden.Diese leichte Verschiebung der Offsets anstelle der üblichen einstündigen Sommerzeit (Sommerzeit), die wir gewohnt sind, verschleiert das Problem ein wenig.
Beachten Sie, dass das 2013a-Update der Zeitzonendatenbank diese Diskontinuität einige Sekunden zuvor verschoben hat, der Effekt jedoch weiterhin sichtbar ist.
Mit dem neuen
java.time
Paket unter Java 8 können Sie dies klarer sehen und Tools bereitstellen, um damit umzugehen. Gegeben:Dann
durationAtEarlierOffset
ist es eine Sekunde, währenddurationAtLaterOffset
es fünf Minuten und 53 Sekunden sind.Auch diese beiden Offsets sind gleich:
Aber diese beiden sind unterschiedlich:
Sie können das gleiche Problem zu vergleichen sehen
1927-12-31 23:59:59
mit1928-01-01 00:00:00
, in diesem Fall aber ist es der frühere Zeitpunkt ist versetzt , dass die längere Divergenz erzeugt, und es ist das frühere Datum , die zwei mögliche Offsets hat.Eine andere Möglichkeit, dies zu erreichen, besteht darin, zu überprüfen, ob ein Übergang stattfindet. Wir können das so machen:
Sie können überprüfen, ob der Übergang eine Überlappung ist, bei der es mehr als einen gültigen Versatz für dieses Datum / diese Uhrzeit gibt, oder eine Lücke, bei der dieses Datum / diese Uhrzeit für diese Zonen-ID nicht gültig ist, indem Sie die Methoden
isOverlap()
undisGap()
verwendenzot4
.Ich hoffe, dies hilft den Leuten, diese Art von Problem zu lösen, sobald Java 8 allgemein verfügbar ist, oder für diejenigen, die Java 7 verwenden und den JSR 310-Backport verwenden.
quelle
1900-12-31 23:54:16
und1900-12-31 23:54:17
, aber das funktioniert auf der von Ihnen freigegebenen Site nicht, sodass sie eine andere Java-Version als I verwenden.Meiner Meinung nach ist die allgegenwärtige implizite Lokalisierung in Java der größte Konstruktionsfehler. Es mag für Benutzeroberflächen gedacht sein, aber ehrlich gesagt, wer verwendet Java heute wirklich für Benutzeroberflächen, mit Ausnahme einiger IDEs, bei denen Sie die Lokalisierung grundsätzlich ignorieren können, da Programmierer nicht genau die Zielgruppe dafür sind. Sie können das Problem beheben (insbesondere auf Linux-Servern), indem Sie:
Den Mitgliedern des Java Community Process empfehle ich:
Ich meine, komm schon, sind globale statische Variablen kein Anti-OO-Muster? Nichts anderes sind diese allgegenwärtigen Standardeinstellungen, die von einigen rudimentären Umgebungsvariablen vorgegeben werden .......
quelle
Wie andere sagten, ist es eine Zeitumstellung im Jahr 1927 in Shanghai.
Wenn es
23:54:07
in Shanghai war, der lokalen Standardzeit, aber nach 5 Minuten und 52 Sekunden, drehte es sich zum nächsten Tag um00:00:00
und dann änderte sich die lokale Standardzeit zurück zu23:54:08
. Deshalb beträgt der Unterschied zwischen den beiden Zeiten 343 Sekunden und nicht 1 Sekunde, wie Sie es erwartet hätten.Die Zeit kann auch an anderen Orten wie den USA durcheinander geraten. Die USA haben Sommerzeit. Wenn die Sommerzeit beginnt, läuft die Zeit 1 Stunde vorwärts. Aber nach einer Weile endet die Sommerzeit und sie geht 1 Stunde zurück in die Standardzeitzone. Beim Vergleich der Zeiten in den USA beträgt der Unterschied manchmal etwa
3600
Sekunden und nicht 1 Sekunde.Diese beiden Zeitänderungen haben jedoch etwas anderes. Letzteres ändert sich ständig und Ersteres war nur eine Änderung. Es hat sich nicht um den gleichen Betrag zurück oder wieder geändert.
Es ist besser, UTC zu verwenden, wenn sich die Zeit nicht ändert, es sei denn, Sie benötigen eine Nicht-UTC-Zeit wie in der Anzeige.
quelle