webentwicklung-frage-antwort-db.com.de

ZonedDateTime toString-Kompatibilität mit ISO 8601

Ich versuche sicherzustellen, dass der Aufruf von toString() für mein ZonedDateTime-Objekt dem ISO-8601-Format entspricht.

Die Dokumentation für die toString()-Methode lautet:

... Die Ausgabe ist mit ISO-8601 kompatibel, wenn der Offset und die ID die .__ sind. gleich

Bedeutet dies, dass es eine Situation gibt, in der der Aufruf von zdt.getOffset() Etwas anderes zurückgibt als zdt.getZone().getRules().getOffset(zdt.toInstant())?

Das scheint keinen Sinn zu machen.

Kann jemand ein Beispiel geben, in dem Offset und ID nicht identisch sind (dh: toString() entspricht nicht der Norm ISO-8601), damit ich die Beschreibung in der Dokumentation besser verstehen kann.

Vielen Dank.

11
theyuv

Dies ist die vollständige Spezifikation:

 * Outputs this date-time as a {@code String}, such as
 * {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}.
 * <p>
 * The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}.
 * If the {@code ZoneId} is not the same as the offset, then the ID is output.
 * The output is compatible with ISO-8601 if the offset and ID are the same.

Die Javadoc-Spezifikation bezieht sich auf den Fall, in dem ZonedDateTime aus einem ZoneOffset und nicht aus einem benannten ZoneId besteht. In diesem Fall sind Offset und ID identisch:

System.out.println(ZonedDateTime.now(ZoneId.of("Europe/Paris")));
// 2017-04-26T15:13:12.006+02:00[Europe/Paris]

System.out.println(ZonedDateTime.now(ZoneOffset.ofHours(2)));
// 2017-04-26T15:13:12.016+02:00

Wie zu sehen ist, lässt sich im zweiten Fall, in dem ZoneOffset verwendet wird, das toString()-Format den eckigen Klammerabschnitt am Ende aus. Wenn Sie diesen Abschnitt weglassen, ist das Ergebnis ISO-8601-kompatibel.

boolean iso8601Compatible = zdt.getZone() instanceof ZoneOffset;

Um eine ISO-8601-kompatible Ausgabe zu gewährleisten, verwenden Sie toOffsetDateTime():

String isoCompatible = zdt.toOffsetDateTime().toString();

oder ein Formatierer.

20
JodaStephen

Das Beispiel in der Dokumentation ist 2007-12-03T10:15:30+01:00[Europe/Paris]. Dies ist jedoch nicht ISO-kompatibel, da ISO-8601 den [Europe/Paris]-Teil nicht enthält. Dies wurde von den Java.time-Entwicklern in einem Kompromiss hinzugefügt, dem Standard so nahe wie möglich zu sein und dennoch die Zeitzoneninformationen auf eindeutige Weise bereitzustellen.

Die eigentliche Frage kann also tatsächlich das Gegenteil sein: Wenn ZonedDateTime.toString() die Zeitzoneninformationen enthält, die ISO nicht enthält, wenn ist das Ergebnis vollständig ISO-kompatibel? Was bedeutet "wenn Offset und ID gleich sind"? Hier ist zu beachten, dass ZoneOffset eine Unterklasse von ZoneID ist und als Zonen-ID in ZonedDateTime verwendet werden kann. In diesem Fall sind Offset und ID gleich. Sonst sind sie nicht. Für ein bestimmtes Beispiel kann ZonedDateTime.now(ZoneOffset.ofHours(+2)).toString()2017-04-26T15:04:59.828+02:00 produzieren. Dies ist vollständig ISO-kompatibel, da die Zone nur als +02:00 angegeben ist, was dem Offset entspricht. Auch ZonedDateTime.now(ZoneOffset.UTC).toString() gibt etwas im Format 2017-04-26T13:04:59.828Z. Da Z als Offset zählt, ist auch dies kompatibel.

Ich denke, dass es in den meisten Fällen nicht sehr nützlich sein wird. Wenn Ihre Zone nur ein Versatz ist, würden Sie normalerweise OffsetDateTime über ZonedDateTime vorziehen, und wenn ja, ist es Ihnen egal, ob ZonedDateTime.toString() ISO-kompatibel ist oder nicht.

3
Ole V.V.

Ich mag den letzten Kommentar von JodaStephen 'oder ein Formatierungsprogramm' , da die Verwendung des Formatierungsprogramms unabhängig von den Daten robuster ist. Der Grund ist, dass OffsetDateTime toString () den zweiten Unit-Teil überspringt, wenn auf der zweiten Unit und darunter kein Wert vorhanden ist am Ende ergibt sich jjjj-MM-ttTHH: mmZ anstelle von jjjj-MM-ttTHH: mm: ssZ. Dies kann zu Problemen führen, wenn ein anderes System ein statisches Format erwartet und keine Anpassungsfähigkeit hat.

Unten ist der Code, den ich für die Simulation beider Fälle verwendet habe, in denen kein Zeitanteil vorhanden ist.

/**
 * This function is design to convert Date object from other system to ISO dateTime String 
 * which will be sent to another system. and using formatter to lock up the format
 * @param date Java.util.Date
 * @return 'yyyy-MM-ddTHH:mm:ssZ' format ISO dateTime string
 */
public String formatIsoUtcDateTime(Date date) {
    if(null == date) {
        return null;
    }
    return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("UTC"))
                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"));
}

// no time portion with using formatter
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Date date = sdf.parse("20171010");
System.out.println(formatIsoUtcDateTime(date));

// no time portion with using OffsetDateTime toString
System.out.println(ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("UTC")).toOffsetDateTime().toString());

// just current date and probably has at least millisecond, using formatter
System.out.println(formatIsoUtcDateTime(new Date()));

// just current date and probably has at least millisecond, using OffsetDateTime toString
// this will print yyyy-MM-ddTHH:mm:ss.SSSZ format
System.out.println(ZonedDateTime.ofInstant(new Date().toInstant(), ZoneId.of("UTC")).toOffsetDateTime().toString());
0
Steve Park

Laut offiziellen Unterlagen:

Den Offset für einen Moment zu erhalten, ist einfach, da es für jeden Moment genau einen gültigen Offset gibt . Im Gegensatz dazu ist es nicht einfach, den Versatz für ein lokales Datum zu erhalten. Es gibt drei Fälle:

  • Normal, mit einem gültigen Offset. Für die überwiegende Mehrheit des Jahres gilt der Normalfall, wenn für das lokale Datum und die Uhrzeit ein einziger gültiger Versatz vorliegt.
  • Lücke mit null gültigen Offsets. In diesem Fall springen die Uhren normalerweise vorwärts, da sich die Sommerzeit im Frühling von "Winter" auf "Sommer" ändert. In einer Lücke gibt es lokale Datums-/Uhrzeitwerte ohne gültigen Versatz.
  • Überlappung mit zwei gültigen Offsets. In diesem Fall werden die Uhren normalerweise zurückgestellt, da im Herbst die Sommerzeit von "Sommer" auf "Winter" geändert wird. In einer Überlappung gibt es lokale Datums-/Uhrzeitwerte mit zwei gültigen Offsets.

Der 2. und 3. Fall sind also die Situationen, in denen toString () nicht ISO-8601-kompatibel ist.

0
VivekRatanSinha