wake-up-neo.com

`uuuu` vs.` yyyy` in `DateTimeFormatter`-Formatierungsmustercodes in Java

Die DateTimeFormatter-Klassendokumentation sagt über ihre Formatierungscodes für das Jahr aus:

u Jahr Jahr 2004; 04

jahr des Jahres 2004; 04

Year: Die Anzahl der Buchstaben bestimmt die minimale Feldbreite, unter der die Auffüllung verwendet wird. Wenn die Anzahl der Buchstaben zwei beträgt, wird eine reduzierte zweistellige Form verwendet. Beim Drucken werden die beiden rechten Ziffern ausgegeben. Beim Parsen wird dies mit dem Basiswert von 2000 analysiert, was zu einem Jahr im Bereich von 2000 bis einschließlich 2099 führt. Wenn die Anzahl der Buchstaben weniger als vier (aber nicht zwei) beträgt, wird das Vorzeichen nur für negative Jahre gemäß SignStyle.NORMAL ausgegeben. Andernfalls wird das Vorzeichen ausgegeben, wenn die Padbreite gemäß SignStyle.EXCEEDS_PAD überschritten wird.

Keine andere Erwähnung von "Ära".

Was ist also der Unterschied zwischen diesen beiden Codes, u gegenüber y, year versus year-of-era?

Wann sollte ich etwas wie dieses Muster uuuu-MM-dd verwenden und wann yyyy-MM-dd, wenn ich mit Datumsangaben in Java arbeite?

Scheint, dass Beispielcode, der von Kennern geschrieben wird, uuuu verwendet, aber warum? 

Andere Formatierungsklassen wie die ältere SimpleDateFormat haben nur yyyy, daher bin ich verwirrt, warum Java.time diese uuuu für "year of era" bringt.

14
Basil Bourque

Im Rahmen von Java.time- package können wir sagen:

  • Es ist sicherer, "u" anstelle von "y" zu verwenden, da andernfalls DateTimeFormatter darauf bestehen wird, eine Ära in Kombination mit "y" (= Jahreszeit) zu haben. Wenn Sie "u" verwenden, werden einige unerwartete Ausnahmen beim strengen Formatieren/Parsen vermieden. Siehe auch diese SO-post . Eine weitere kleinere Sache, die durch das "u" -Symbol im Vergleich zu "y" verbessert wird, ist das Drucken/Parsen negativer gregorianischer Jahre (in der Vergangenheit).

  • Ansonsten können wir eindeutig feststellen, dass die Verwendung von "u" anstelle von "y" langjährige Gewohnheiten bei der Java-Programmierung unterbricht. Es ist auch nicht intuitiv klar, dass "u" irgendeine Art von Jahr bezeichnet, weil a) der erste Buchstabe des englischen Wortes "year" nicht mit diesem Symbol übereinstimmt und b) SimpleDateFormat "u" seit Java für einen anderen Zweck verwendet -7 ( ISO-Wochentag-Nummer ). Verwirrung ist garantiert - für immer?

  • Wir sollten auch sehen, dass die Verwendung von Eras (Symbol "G") im Kontext von ISO im Allgemeinen gefährlich ist, wenn wir historische Daten betrachten. Wenn "G" mit "u" verwendet wird, haben beide Felder keine Beziehung. Wenn "G" mit "y" verwendet wird, ist der Formatierer zufrieden, verwendet jedoch weiterhin einen proleptischen gregorianischen Kalender, wenn das historische Datum unterschiedliche Kalender und Datumsangaben erfordert.

Hintergrundinformation:

Bei der Entwicklung und Integration des JSR-310 (Java.time- Packages) entschieden sich die Entwickler für die Verwendung der CLDR/LDML-Spezifikation als Basis für Mustersymbole in DateTimeFormatter. Das Symbol "u" ​​wurde bereits in CLDR als proleptisches gregorianisches Jahr definiert, daher wurde diese Bedeutung für das neue kommende JSR-310 übernommen (jedoch nicht aus SimpleDateFormat aus Gründen der Rückwärtskompatibilität).

Diese Entscheidung, CLDR zu folgen, war jedoch nicht ganz konsequent, da JSR-310 auch neue Mustersymbole eingeführt hatte, die in CLDR nicht existierten und noch nicht existieren, siehe auch dieses alte CLDR-Ticket . Das vorgeschlagene Symbol "I" wurde von CLDR in "VV" geändert und schließlich von JSR-310 mit neuen Symbolen "x" und "X" übernommen. "N" und "N" sind jedoch in CLDR noch nicht vorhanden, und da dieses alte Ticket geschlossen ist, ist überhaupt nicht klar, ob CLDR es im Sinne von JSR-310 jemals unterstützen wird. Darüber hinaus erwähnt das Ticket nicht das Symbol "p" (Auffüllanweisung in JSR-310, jedoch nicht in CLDR definiert). Wir haben also immer noch keine perfekte Übereinstimmung zwischen den Musterdefinitionen zwischen verschiedenen Bibliotheken und Sprachen.

Und zu "y": Wir sollten auch nicht übersehen, dass CLDR dieses Jahr mindestens mit einer Art gemischtem julianisch-gregorianischem Jahr assoziiert und nicht mit dem proleptischen gregorianischen Jahr, wie es bei JSR-310 der Fall ist negative Jahre beiseite). Also auch hier keine perfekte Übereinstimmung zwischen CLDR und JSR-310.

14
Meno Hochschild

Im Javadoc-Abschnitt Muster für Formatierung und Analyse für DateTimeFormatter werden die folgenden 3 relevanten Symbole aufgelistet:

Symbol  Meaning        Presentation  Examples
------  -------        ------------  -------
 G       era            text          AD; Anno Domini; A
 u       year           year          2004; 04
 y       year-of-era    year          2004; 04

Nur zum Vergleich sind diese anderen Symbole leicht verständlich:

 D       day-of-year    number        189
 d       day-of-month   number        10
 E       day-of-week    text          Tue; Tuesday; T

Der day-of-year, day-of-month und day-of-week sind offensichtlich der Tag innerhalb des angegebenen Bereichs (Jahr, Monat, Woche).

year-of-era bedeutet also year innerhalb des gegebenen Bereichs (Ära), und rechts darüber wird era mit einem Beispielwert von AD angezeigt (der andere Wert ist natürlich BC).

year ist das vorzeichenbehaftete Jahr, wobei Jahr 01 BC ist, Jahr -12 BC und so weiter.

Zur Veranschaulichung: Wann wurde Julius Caesar ermordet ?

  • 15. März 44 v. Chr. (Unter Verwendung des Musters MMMM d, y GG)
  • 15. März -43 (unter Verwendung des Musters MMMM d, u)

Die Unterscheidung ist natürlich nur von Bedeutung, wenn das Jahr null oder negativ ist, und da dies selten ist, ist es den meisten Menschen egal, obwohl sie es sollten.

Schlussfolgerung: Wenn Sie y verwenden, sollten Sie auch G verwenden. Da G selten verwendet wird, ist das korrekte Jahressymbol u und nicht y. Andernfalls wird ein nicht positives Jahr falsch angezeigt.

Dies ist bekannt als defensive Programmierung :

Defensives Programmieren ist eine Form von defensivem Design, die dazu bestimmt ist, die fortlaufende Funktion sicherzustellen einer Software unter unvorhergesehenen Umständen.


Beachten Sie, dass DateTimeFormatter mit SimpleDateFormat konsistent ist:

Letter  Date or Time Component  Presentation  Examples
------  ----------------------  ------------  --------
G       Era designator          Text          AD
y       Year                    Year          1996; 96

Negative Jahre waren schon immer ein Problem und wurden nun durch Hinzufügen von u behoben.

12
Andreas

Um es kurz zu machen

  1. Für 99% der Zwecke, in denen Sie eine Münze werfen können, spielt es keine Rolle, ob Sie yyyy oder uuuu verwenden (oder ob Sie yy oder uu für ein zweistelliges Jahr verwenden).
  2. Es hängt davon ab, was Sie im Fall eines Jahres vor 1 CE (1 AD) passieren möchten. Der Punkt ist, dass in 99% der Programme ein solches Jahr niemals vorkommt.

Zwei andere Antworten haben bereits gezeigt, wie u und y sehr gut funktionieren, aber ich habe immer noch das Gefühl, dass etwas fehlt, und ich füge die etwas mehr meinungsbasierte Antwort hinzu.

Zur Formatierung

Angenommen, Sie erwarten nicht, dass ein Jahr vor dem 1. CE-Format formatiert wird. Am besten prüfen Sie diese Annahme und reagieren angemessen, falls sie kaputt gehen sollte. Abhängig von den Umständen und Anforderungen können Sie beispielsweise eine Fehlermeldung drucken oder eine Ausnahme auslösen. Ein sehr weicher Fehlerpfad könnte in diesem Fall die Verwendung eines Musters mit y (Jahr des Zeitalters) und G (Zeitalter) und eines Musters mit entweder u oder y sein. Wenn Sie das aktuelle Datum oder das Datum drucken, an dem Ihr Programm kompiliert wurde, können Sie sicher sein, dass es sich in der üblichen Ära befindet, und die Prüfung möglicherweise überspringen.

Für die Analyse

In vielen (meistens?) Fällen bedeutet Parsing auch die Validierung, dh Sie haben keine Garantie dafür, wie Ihre Eingabezeichenfolge aussieht. Normalerweise kommt es vom Benutzer oder von einem anderen System. Ein Beispiel: Eine Datumszeichenfolge lautet 2018-09-29. Hier sollte die Wahl zwischen uuuu und yyyy davon abhängen, was Sie möchten, falls die Zeichenfolge ein Jahr von 0 oder negativ enthält (z. B. 0000-08-17 oder -012-11-13). Angenommen, dies wäre ein Fehler, lautet die unmittelbare Antwort: Verwenden Sie yyyy, damit in diesem Fall eine Ausnahme ausgelöst wird. Noch feiner: Verwenden Sie uuuu und führen Sie nach der Analyse eine Bereichsüberprüfung des analysierten Datums durch. Der letztere Ansatz ermöglicht sowohl eine genauere Validierung als auch eine bessere Fehlermeldung im Falle eines Validierungsfehlers.

Sonderfall (bereits von Meno Hochschild erwähnt): Wenn Ihr Formatierer einen strengen Resolver-Stil verwendet und y ohne G enthält, wird das Analysieren immer fehlschlagen, da das Ära des Ära ohne Ära eindeutig mehrdeutig ist: 1950 bedeutet 1950 u (1950 v. Chr.). In diesem Fall benötigen Sie u (oder geben Sie eine Standardzeit an, dies ist über eine DateTimeFormatterBuilder möglich).

Lange Geschichte wieder kurz

Eine explizite Überprüfung Ihrer Daten, insbesondere Ihrer Jahre, ist besser als sich auf die Wahl zwischen uuuu und yyyy zu verlassen, um unerwartete sehr frühe Jahre zu fangen.

1
Ole V.V.