Was ist dieses Datumsformat? 2011-08-12T20: 17: 46.384Z

383

Ich habe folgendes Datum : 2011-08-12T20:17:46.384Z. Welches Format ist das? Ich versuche es mit Java 1.4 über zu analysieren DateFormat.getDateInstance().parse(dateStr)und ich bekomme

java.text.ParseException: Nicht analysierbares Datum: "2011-08-12T20: 17: 46.384Z"

Ich denke, ich sollte SimpleDateFormat zum Parsen verwenden, aber ich muss zuerst die Formatzeichenfolge kennen. Alles, was ich bisher dafür habe, ist yyyy-MM-dd, weil ich nicht weiß, was die Bedeutung Tin dieser Zeichenfolge bedeutet - etwas Zeitzonenbezogenes? Diese Datumszeichenfolge stammt von dem lcmis:downloadedOnTag, das im Medientyp "Dateien CMIS-Downloadverlauf" angezeigt wird .

Sarah Vessels
quelle
43
Es ist ISO 8601
Tomasz Nurkiewicz
3
@TomaszNurkiewicz, ist es nicht. ISO8601 hat am Ende kein Z.
t1gor
4
ISO8601 erlaubt ein Z am Ende. Siehe den Link oben, suchen Sie nach UTC.
Jonathan Rosenne
2
@ t1gor Das Zam Ende steht für UTCZulu und bedeutet . Dieses Format mit Sicherheit ist Teil der ISO 8601 Sammlung von Standard - Datum-Zeit - Textformaten. Diese Standardformate werden übrigens standardmäßig in den Klassen java.time verwendet.
Basil Bourque
3
Zu Ihrer Information, die störenden alten Datum Zeitklassen wie java.util.Date, java.util.Calendarund java.text.SimpleDateFormatsind jetzt Erbe , durch die verdrängte java.time Klassen in Java gebaut 8 & Java 9. Siehe Tutorial von Oracle .
Basil Bourque

Antworten:

512

Das T ist nur ein Literal, um das Datum von der Uhrzeit zu trennen, und das Z bedeutet "Null-Stunden-Versatz", auch als "Zulu-Zeit" (UTC) bekannt. Wenn Ihre Zeichenfolgen immer ein "Z" haben, können Sie Folgendes verwenden:

SimpleDateFormat format = new SimpleDateFormat(
    "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));

Oder mit Joda Time können Sie verwenden ISODateTimeFormat.dateTime().

Jon Skeet
quelle
7
Warum brauchen wir die einfachen Anführungszeichen um Tund Z?
Maroun
7
@MarounMaroun: Grundsätzlich wollen wir diese wörtlichen Zeichen. Es ist möglicherweise nicht erforderlich für T(ich kann mich nicht erinnern, wie SimpleDateFormat mit unbekannten Spezifizierern umgeht), aber Zwir möchten, dass es das Zeichen 'Z' und nicht "ein UTC-Versatzwert" (z. B. "00") ist.
Jon Skeet
2
@nyedidikeke: Auf der Wikipedia-Seite, auf die Sie verlinkt haben, wird "Zulu-Zeitzone" für UTC angezeigt. Ich bin mir nicht sicher, was Sie glauben, dass Sie korrigieren.
Jon Skeet
9
@ JonSkeet: Dies kann zu unnötigen Debatten führen. Sie bestreiten Ihre Antwort nicht, wollten aber die Aufmerksamkeit auf das Z lenken, dessen Anfangsbuchstabe von "Null UTC Offset" stammt. Buchstabe Z wird im phonetischen NATO-Alphabet als "Zulu" bezeichnet . Der militärische Ansatz, sich auf den Null-UTC-Versatz zu beziehen, ist wiederum auf dem Buchstaben Z verankert, den sie als Zulu identifizieren, und erhält den codierten Namen: Zulu-Zeitzone. Es ist wichtig zu beachten, dass das Z seine Bedeutung nicht verloren hat und dennoch der Zonenbezeichner für den Null-UTC-Offset ist, da die Zulu-Zeitzone (von Z) einfach eine geerbte codierte Sprache ist, um darauf zu verweisen.
Nyedidikeke
2
@nyedidikeke: Ich bin mir immer noch nicht einig, ob sich jemals jemand um die Unterscheidung in Bezug auf meine Antwort kümmern wird, aber ich habe sie aktualisiert. Ich werde jedoch nicht auf alle Details eingehen, da die Geschichte für die Antwort weitgehend irrelevant ist.
Jon Skeet
86

tl; dr

Das Standardformat ISO 8601 wird von Ihrer Eingabezeichenfolge verwendet.

Instant.parse ( "2011-08-12T20:17:46.384Z" ) 

ISO 8601

Dieses Format wird durch die sinnvolle praktische Norm ISO 8601 definiert .

Das Ttrennt den Datumsanteil vom Tageszeitteil. Das Zam Ende bedeutet UTC (dh ein Versatz von UTC von null Stunden-Minuten-Sekunden). Das Zwird "Zulu" ausgesprochen .

java.time

Die alten Datums- und Uhrzeitklassen, die mit den frühesten Versionen von Java gebündelt wurden, haben sich als schlecht gestaltet, verwirrend und problematisch erwiesen. Vermeide sie.

Verwenden Sie stattdessen das in Java 8 und höher integrierte java.time- Framework. Die java.time-Klassen ersetzen sowohl die alten Datums- / Uhrzeitklassen als auch die äußerst erfolgreiche Joda-Time-Bibliothek.

Die java.time-Klassen verwenden standardmäßig ISO 8601, wenn Textdarstellungen von Datums- und Uhrzeitwerten analysiert / generiert werden.

Die InstantKlasse repräsentiert einen Moment auf der Zeitachse in UTC mit einer Auflösung von Nanosekunden . Diese Klasse kann Ihre Eingabezeichenfolge direkt analysieren, ohne ein Formatierungsmuster definieren zu müssen.

Instant instant = Instant.parse ( "2011-08-12T20:17:46.384Z" ) ;

Tabelle der Datums- und Uhrzeittypen in Java, sowohl modern als auch alt


Ü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?

Tabelle, welche java.time-Bibliothek mit welcher Java- oder Android-Version verwendet werden soll

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 .

Basil Bourque
quelle
3
@star Das „Zulu“ stammt aus der Militär- und Luftfahrttradition, in der 25 Buchstaben des Alphabets AZ (kein „J“), wobei jeder Buchstabe einen aussprechbaren Namen hat, die Version der Zeitzonen darstellen . Die "Zulu" -Zone ist null Stunden von UTC entfernt. Sehen Sie dies und das .
Basil Bourque
27

Ich bin mir nicht sicher über das Java-Parsing, aber das ist ISO8601: http://en.wikipedia.org/wiki/ISO_8601

smparkes
quelle
Ist dies auch "2016-01-27T17: 44: 55UTC", ISO8601?
user1997292
Ich glaube nicht. Es ist nah, aber UTC als Suffix ist nicht erlaubt. Es muss Z oder ein Zeitzonenversatz sein, z. B. +0100. Z und UTC haben jedoch die gleiche Bedeutung, so dass eine Änderung der UTC in Z eine gültige ISO 8601 ergeben würde.
smparkes
9

Es gibt andere Möglichkeiten, es zu analysieren, als die erste Antwort. So analysieren Sie es:

(1) Wenn Sie Informationen zu Datum und Uhrzeit abrufen möchten, können Sie sie in ein ZonedDatetime(seit Java 8 ) oder Date(altes) Objekt analysieren :

// ZonedDateTime's default format requires a zone ID(like [Australia/Sydney]) in the end.
// Here, we provide a format which can parse the string correctly.
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime zdt = ZonedDateTime.parse("2011-08-12T20:17:46.384Z", dtf);

oder

// 'T' is a literal.
// 'X' is ISO Zone Offset[like +01, -08]; For UTC, it is interpreted as 'Z'(Zero) literal.
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX";

// since no built-in format, we provides pattern directly.
DateFormat df = new SimpleDateFormat(pattern);

Date myDate = df.parse("2011-08-12T20:17:46.384Z");

(2) Wenn Sie sich nicht um Datum und Uhrzeit kümmern und die Informationen nur als einen Moment in Nanosekunden behandeln möchten, können Sie Folgendes verwenden Instant:

// The ISO format without zone ID is Instant's default.
// There is no need to pass any format.
Instant ins = Instant.parse("2011-08-12T20:17:46.384Z");
VeryLazyBoy
quelle
1

Wenn Sie nach einer Lösung für Android suchen, können Sie den folgenden Code verwenden, um die Sekunden der Epoche aus der Zeitstempelzeichenfolge abzurufen.

public static long timestampToEpochSeconds(String srcTimestamp) {
    long epoch = 0;

    try {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            Instant instant = Instant.parse(srcTimestamp);
            epoch = instant.getEpochSecond();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z'", Locale.getDefault());
            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
            Date date = sdf.parse(srcTimestamp);
            if (date != null) {
                epoch = date.getTime() / 1000;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return epoch;
}

Beispieleingabe: 2019-10-15T05: 51: 31.537979Z

Beispielausgabe: 1571128673

Rahul Raveendran
quelle
0

Sie können das folgende Beispiel verwenden.

    String date = "2011-08-12T20:17:46.384Z";

    String inputPattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

    String outputPattern = "yyyy-MM-dd HH:mm:ss";

    LocalDateTime inputDate = null;
    String outputDate = null;


    DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern(inputPattern, Locale.ENGLISH);
    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputPattern, Locale.ENGLISH);

    inputDate = LocalDateTime.parse(date, inputFormatter);
    outputDate = outputFormatter.format(inputDate);

    System.out.println("inputDate: " + inputDate);
    System.out.println("outputDate: " + outputDate);
Salih Kesepara
quelle
Sie sollten keine Apostrophe um das setzen Z. Das bedeutet, diesen Brief zu erwarten, aber zu ignorieren. Aber dieser Brief sollte nicht ignoriert werden. Dieser Brief liefert wertvolle Informationen, die Tatsache, dass die Zeichenfolge für UTC bestimmt war, einen Versatz von Null. Ihr Format verwirft diese wichtige Tatsache. Darüber hinaus müssen Sie dieses Formatierungsmuster nicht einmal definieren. Ein Formatierer für dieses Muster ist eingebaut.
Basil Bourque
-1

Diese Technik übersetzt java.util.Date in das UTC-Format (oder ein anderes) und wieder zurück.

Definieren Sie eine Klasse wie folgt:

import java.util.Date;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class UtcUtility {

public static DateTimeFormatter UTC = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZoneUTC();


public static Date parse(DateTimeFormatter dateTimeFormatter, String date) {
    return dateTimeFormatter.parseDateTime(date).toDate();
}

public static String format(DateTimeFormatter dateTimeFormatter, Date date) {
    return format(dateTimeFormatter, date.getTime());
}

private static String format(DateTimeFormatter dateTimeFormatter, long timeInMillis) {
    DateTime dateTime = new DateTime(timeInMillis);
    String formattedString = dateTimeFormatter.print(dateTime);
    return formattedString;
}

}}

Dann benutze es so:

Date date = format(UTC, "2020-04-19T00:30:07.000Z")

oder

String date = parse(UTC, new Date())

Sie können bei Bedarf auch andere Datumsformate definieren (nicht nur UTC).

Gapmeister66
quelle
Beide java.util.Dateund das Joda-Time- Projekt wurden vor Jahren durch die modernen java.time- Klassen ersetzt, die in JSR 310 definiert sind. Der Rat hier ist längst veraltet.
Basil Bourque
java.time wurde in Java 8 eingeführt. Diese Frage bezieht sich speziell auf Java 1.4 und daher habe ich die Verwendung der neueren Klassen bewusst vermieden. Diese Lösung ist für ältere Codebasen geeignet. Ich nehme an, der Autor könnte seine Codebasis auf Java 8 verschieben, aber das ist nicht immer einfach, effizient oder notwendig.
Gapmeister66
-1

@ John-Skeet gab mir den Hinweis, mein eigenes Problem zu beheben. Als jüngerer Programmierer ist dieses kleine Problem leicht zu übersehen und schwer zu diagnostizieren. Also teile ich es in der Hoffnung, dass es jemandem hilft.

Mein Problem war, dass ich die folgende Zeichenfolge analysieren wollte, die einem Zeitstempel aus einem JSON widerspricht, auf den ich keinen Einfluss habe, und ihn in nützlichere Variablen einfügen wollte. Aber ich bekam immer wieder Fehler.

Gehen Sie also wie folgt vor (achten Sie auf den String-Parameter in Pattern ();

String str = "20190927T182730.000Z"

LocalDateTime fin;
fin = LocalDateTime.parse( str, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSZ") );

Error:

Exception in thread "main" java.time.format.DateTimeParseException: Text 
'20190927T182730.000Z' could not be parsed at index 19

Das Problem? Das Z am Ende des Musters muss genau wie das 'T' in 'Z' eingewickelt werden. Wechseln Sie "yyyyMMdd'T'HHmmss.SSSZ"zu "yyyyMMdd'T'HHmmss.SSS'Z'"und es funktioniert.

Das Entfernen des Z aus dem Muster insgesamt führte ebenfalls zu Fehlern.

Ehrlich gesagt würde ich erwarten, dass eine Java-Klasse dies vorweggenommen hat.

spencemw
quelle
1
Dies wurde hier und hier bereits gefragt und beantwortet . Und Ihre Lösung ist falsch. Während Tist ein Literal und muss in Anführungszeichen gesetzt werden, Zist ein Offset (von Null) und muss als solches analysiert werden, sonst erhalten Sie falsche Ergebnisse. Ich weiß nicht, was du meinst, dass es nicht erwartet wurde, ich glaube, dass es hat.
Ole VV
1
Nein, nein, nein, ignoriere das nicht Z. Sie verwerfen wertvolle Informationen. Das Verarbeiten eines Datums- / Uhrzeitwerts unter Ignorieren der Zeitzone oder des Versatzes von UTC ist wie das Verarbeiten eines Geldbetrags unter Ignorieren der Währung!
Basil Bourque
1
Das Ttrennt lediglich den Datumsanteil vom Tageszeitteil und fügt keine Bedeutung hinzu. Das Zauf der anderen Seite fügt definitiv Bedeutung hinzu.
Basil Bourque
Ole, danke für die Links. Ich werde diese sicherlich lesen. Und ich akzeptiere, dass ich als Youngin sicherlich falsch liegen könnte. Alles, was ich sage, ist, dass das Umschließen des Z in einfache Anführungszeichen wie ein Zeichen im Muster den Fehler behoben hat. Meine Kritik ist, dass jeder, der einen "Muster" -Teil der Klasse entworfen hat, um das Vorhandensein oder Fehlen von "Z" (oder einer anderen Zeitzone?) Und "T", das eingepackt ist, codiert haben könnte oder nicht. Weil sie es nicht einzigartig gemacht haben. Das Format, mit dem ich mich befasse, stammt von JSON von einer kommerziellen API, die in eine Zeichenfolge analysiert wurde. Aber ich muss das alles in einen Datums-Zeit-Kalender usw. analysieren, um sie nützlicher zu machen.
spencemw