Eine Stunde verlieren, wenn er ein Datum im Januar 1970 von Millisekunden zurückgibt
-
26-10-2019 - |
Frage
Ich habe den folgenden Code, der eine Reihe von Millisekunden nimmt (stammt aus einem RSS -Feed.
public static void main(String[] args) {
String ms = "1302805253";
SimpleDateFormat dateFormatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(Long.parseLong(ms));
try {
String dateFormat = dateFormatter.format(calendar.getTime());
System.out.println("Date Format = " + dateFormat);
Date dateParse = dateFormatter.parse(dateFormatter.format(calendar.getTime()));
System.out.println("Date Parse = " + dateParse);
} catch (ParseException e) {
// TODO: handle exception
}
}
Output:
Date Format = Fri, 16 Jan 1970 02:53:25 GMT
Date Parse = Fri Jan 16 03:53:25 GMT 1970
Wie Sie sehen können, geht zwischen der Formatierung des Kalenderobjekts und der Parsen der resultierenden Zeichenfolge eine Stunde verloren. Auch die Formatierung der Ausgabe hat sich geändert. Kann mir jemand helfen, warum dies passiert und wie ich es umhergehen kann? Ich möchte, dass das Datumsobjekt das gleiche Format wie die Ausgabe "Datumsformat" ist.
Lösung
Ich glaube, es passiert, weil Großbritannien es nicht getan hat eigentlich Verwenden Sie GMT im Jahr 1970, und Java hat einen Fehler darum ... es wird es wird Format Ein Datum im Jahr 1970, als würde das Vereinigte Königreich GMT verwenden, ohne den Offset tatsächlich zu ändern. Einfaches Beispiel:
Date date = new Date(0);
SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss zzz");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(sdf.format(date));
Ergebnis:
01 Jan 1970 01:00:00 GMT
Beachten Sie, dass es 1 Uhr GMT ist ... was falsch ist. Es war 1 Uhr morgens in Europa/London, aber Europa/London beobachtete GMT nicht.
Joda -Zeit bekommt das richtig darin, dass es BST ausdruckt - aber Joda Time mag es nicht Parsing Werte mit Zeitzonenabkürzungen. Sie können es jedoch dazu bringen, die Zeitzone zu verwenden Offets stattdessen:
import org.joda.time.*;
import org.joda.time.format.*;
public class Test {
public static void main(String[] args) throws Exception {
DateTime date = new DateTime(0, DateTimeZone.forID("Europe/London"));
DateTimeFormatter formatter = DateTimeFormat.forPattern(
"dd MMM yyyy HH:mm:ss Z");
String text = formatter.print(date); // 01 Jan 1970 01:00:00 +0100
System.out.println(text);
DateTime parsed = formatter.parseDateTime(text);
System.out.println(parsed.equals(date)); // true
}
}
Andere Tipps
Das Antwort von Jon Skeet ist richtig.
Java.Time
Lassen Sie uns dieselbe Eingabe über Java -Time ausführen, um die Ergebnisse zu sehen.
Angeben a richtiger Zeitzonenname. Verwenden Sie niemals die 3-4-Buchstabenabkürzung wie z. BST
, EST
, oder IST
da sie keine wahren Zeitzonen sind, nicht standardisiert und nicht einmal einzigartig (!). Also benutzen wir Europe/London
.
Das Instant
Die Klasse repräsentiert einen Moment auf der Zeitleiste in koordinierte Weltzeit mit einer Lösung von Nanosekunden.
String input = "1302805253";
long millis = Long.parseLong ( input );
Instant instant = Instant.ofEpochMilli ( millis );
Wenden Sie eine Zeitzone an, um a zu erzeugen ZonedDateTime
Objekt.
ZoneId zoneId = ZoneId.of ( "Europe/London" );
ZonedDateTime zdt = instant.atZone ( zoneId );
Dump zu Konsole. Wir sehen das in der Tat Europe/London
Die Zeit ist in diesem Moment eine Stunde vor UTC. Der Tageszeit ist also 02
Stunden und nicht 01
Std. Beide repräsentieren denselben gleichzeitigen Moment auf der Zeitleiste, die gerade durch die Objektive von zwei verschiedenen betrachtet wurde Wandverrückte.
System.out.println ( "input: " + input + " | instant: " + instant + " | zdt: " + zdt );
Eingabe: 1302805253 | Instant: 1970-01-16T01: 53: 25.253z | ZDT: 1970-01-16T02: 53: 25.253+01: 00 [Europa/London
Ganze Sekunden
Übrigens vermute ich, dass Ihre Eingangszeichenfolge repräsentiert ganz Sekunden seit der Epoche von 1970 UTC und nicht seit der EPOCHE Millisekunden. Interpretierte, dass wir als Sekunden 2011 ein Datum im Monat in dem Monat erhalten, in dem diese Frage veröffentlicht wurde.
String output = Instant.ofEpochSecond ( Long.parseLong ( "1302805253" ) ).atZone ( ZoneId.of ( "Europe/London" ) ).toString ();
2011-04-14t19: 20: 53+01: 00 [Europa/London
Über Java.Time
Das Java.Time Das Rahmen ist in Java 8 und später in eingebaut. Diese Klassen ersetzen die alten störenden Datumszeitklassen wie z. java.util.Date
, .Calendar
, & java.text.SimpleDateFormat
.
Das Joda-Zeit Projekt jetzt in Wartungsmodus, rät die Migration zu Java.Time.
Um mehr zu erfahren, sehen Sie die Oracle Tutorial. Und Suchstapelüberlauf für viele Beispiele und Erklärungen.
Ein Großteil der Java. TreeTen-backport und weiter angepasst an Android in TreeTenabp.
Das Treetren-extra Das Projekt erweitert Java.Time mit zusätzlichen Klassen. Dieses Projekt ist ein nachweisender Grund für mögliche zukünftige Ergänzungen zu Java.