Heim >Java >javaLernprogramm >JJJJ? jjjj!

JJJJ? jjjj!

Susan Sarandon
Susan SarandonOriginal
2024-11-17 14:51:02872Durchsuche

Wissen Sie, was der Unterschied zwischen den Zeichen „Y“ und „y“ im Java-Datumsmuster ist? In diesem Artikel untersuchen wir, wie ein falsches Datumsformat einen Fehler verursachen kann. Außerdem stellen wir unsere neue V6122-Diagnoseregel für Java vor, die Ihnen plötzliche Zeitreisen erspart.

YYYY? yyyy!

Einführung

Nachdem wir unser großes TODO-Notizbuch entstaubt hatten, stießen wir auf einen besonders interessanten Fall. Ein Kommentator des Artikels hat das potenzielle Problem hervorgehoben.

Der Kommentar
Hier ist übrigens eine Idee für Sie: SimpleDateFormat in Java kann für eine Neujahrsüberraschung sorgen – eine in Kleinbuchstaben geschriebene Jahreszahl ist nicht dasselbe wie eine in Großbuchstaben geschriebene Jahreszahl. In der letzten Woche des Jahres befinden Sie sich möglicherweise plötzlich in der Zukunft, da „JJJJ“ für die Daten 27.12.2021–31.12.2021 das Jahr 2022 ist und nicht 2021, wie manche vielleicht erwarten.

Lassen Sie uns der Sache auf den Grund gehen.

Problemanalyse

Datumsformatierung

Wenn Sie irgendwie vergessen haben, was SimpleDateFormat ist, können Sie Ihr Wissen hier auffrischen.

Um Daten zu speichern und anzuzeigen, müssen sie oft einem bestimmten Muster folgen. SimpleDateFormat ist eine Klasse, die es uns ermöglicht, ein Datum einfach nach einem vorgegebenen Muster zu formatieren. Zusätzlich zur Formatierung kann SimpleDateFormat auch Zeichenfolgen analysieren und in das Datumsobjekt konvertieren.

Ist das alles, was Java zu bieten hat? Zusätzlich zu SimpleDateFormat kann die Klasse DateTimeFormatter auch Datumsangaben formatieren.

Lassen Sie mich Ihnen ein Beispiel für die Verwendung dieser beiden Klassen zeigen.

Wenn wir ein Datum über SimpleDateFormat formatieren:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}

Die Konsole zeigt Folgendes an:

31.12.2024

Was ist hier passiert?

Wir haben ein Datum und möchten es in einem bestimmten Format speichern/anzeigen. Um dies zu erreichen, erstellen wir das Objekt SimpleDateFormat, indem wir eine Musterzeichenfolge an den Konstruktor übergeben. Das Datum wird genau nach diesem Muster formatiert. Die Methode format gibt eine Zeichenfolgendarstellung des formatierten Datums zurück. Das ist genau das, was wir wollten.

Hier ist das Gleiche, aber wir verwenden DateTimeFormatter:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}

Die Konsole zeigt Folgendes an:

31.12.2024

Die gleichen Schritte und das gleiche Ergebnis, aber es gibt einen kleinen Unterschied: Mit DateTimeFormatter können wir nur die Datumsangaben formatieren, die von der Klasse dargestellt werden, die die Schnittstelle TemporalAccessor implementiert. Dazu gehören beispielsweise LocalDate und LocalDateTime. SimpleDateFormat formatiert nur Objekte der Klasse Date.

Kehren wir zum Kommentar zurück. Ändert die Verwendung von „Y“ anstelle von „y“ in einem Datumsmuster wirklich das Ergebnis?

Sehen Sie sich den Code an:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}

Die Konsole zeigt Folgendes an:

31.12.2025

Ups. Ist es dasselbe, wenn es um DateTimeFormatter geht?

Hier ist der Code:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}

Die Konsole zeigt Folgendes an:

31.12.2025

Wir sind tatsächlich ein Jahr in die Zukunft gereist. Es ist Zeit zu sehen, was los ist.

Wesentliches Problem

Mein erster Schritt bestand darin, mir die Dokumentation für die Klasse SimpleDateFormat anzusehen. Unten ist ein kleiner Ausschnitt der Tabelle, der beschreibt, wie das Datumsmuster die für uns interessanten alphabetischen Zeichen interpretiert:

Letter Date or Time Component Presentation Examples
y Year Year 1996; 96
Y Week year Year 2009; 09

Eine Woche im Jahr? Lass es mich erklären.

Das Wochenjahr ist ein Jahr basierend auf der Wochennummer des Jahres. Was bedeutet es und warum ist es wichtig?

Bei bestimmten Aufgaben ist die laufende Nummer der Woche im Jahr wichtig. Um die laufende Nummer der Woche zu bestimmen, müssen wir entscheiden, welche Woche zuerst berücksichtigt werden soll. Dies liegt daran, dass der Übergang von einem Jahr zum anderen oft dazu führt, dass sich einige Wochen über beide Jahre erstrecken. Wie können wir also feststellen, zu welchem ​​Jahr diese Woche gehört? Der ISO-8601-Standard regelt dies.

Nach diesem Standard muss die erste Woche des Jahres folgende Bedingungen erfüllen:

  • Der erste Tag der Woche ist Montag;
  • Die Mindestanzahl von Tagen im Jahr in einer Woche beträgt vier.

Daraus können wir eine einfache Regel ableiten: Eine Woche gilt als die erste des Jahres, wenn der Donnerstag in den Januar fällt.

Ein Beispiel aus der Praxis kann dies weiter verdeutlichen.

Nehmen wir das Datum aus dem Beispiel, es ist der 31.12.2024. Unten finden Sie den Kalenderausschnitt für die Woche, die unser Datum enthält (Dezember 2024–Januar 2025):

Mo Tu We Th Fr Sa Su
30 31 1 2 3 4 5

Diese Woche gilt als die erste Woche des Jahres 2025, da sie die oben genannten Bedingungen erfüllt (sie hat fünf Januartage). Wenn wir also den Spezifizierer „Y“ verwenden, erhalten wir das Jahr 2025.

Wie Sie sich vorstellen können, ist der Fall mit DateTimeFormatter genau derselbe.

Es ist wichtig zu beachten, dass wir nicht nur in die Zukunft, sondern auch in die Vergangenheit reisen können.

Nehmen wir uns ein anderes Datum, den 01.01.2027.

Wird in der ersten Woche des Jahres 2027 der 1. Januar enthalten sein? Schauen wir uns noch einmal den Kalender an.

Unten finden Sie den Kalenderausschnitt für die Woche, die unser Datum enthält (Dezember 2026–Januar 2027):

Mo Tu We Th Fr Sa Su
28 29 30 31 1 2 3

Da es in dieser Woche nur drei Januartage gibt (und in der ersten Woche sollten es gemäß den Anforderungen vier sein), zählt sie als letzte Woche des Jahres 2026. Das Datum wird also bei der Formatierung mit dem „Y“ Charakter, wird uns 2026 zeigen.

Hier sind die Beweise. Schauen Sie sich den Code an:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-yyyy");
    System.out.println(dateFormatter.format(date));
}

Die Konsole zeigt Folgendes an:

01.01.2026

Okay, wir haben das Problem analysiert. Wir fanden es auch interessant genug, dem PVS-Studio Java-Analysator eine spezielle Diagnoseregel hinzuzufügen.

Fehler in realen Projekten

Die Diagnoseregel ist geschrieben, es ist also Zeit, sie zu testen.

Während der Entwicklung des Analysators umfasst eine der Testphasen die Durchführung von Regressionstests. Wir haben einen Artikel über diesen Prozess. Kurz gesagt: Wenn wir eine neue Diagnoseregel hinzufügen, analysieren wir einen großen Pool von Open-Source-Projekten und vergleichen die neuen Berichte mit den Referenzberichten.

Im Falle dieser Diagnoseregel hat der Analysator für mehrere Projekte neue Warnungen ausgegeben. Werfen wir einen Blick darauf.

Hüpfburg

In diesem Projekt sind die Codefragmente, auf die die Diagnoseregel verweist, identisch, daher zeige ich nur eines davon.

Sehen Sie sich den Code an:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
    System.out.println(formatter.format(date));
}

Die PVS-Studio-Warnung:

V6122 Verwendung des Musters „Y“ (Woche, Jahr) wurde erkannt: Es war wahrscheinlich beabsichtigt, „y“ (Jahr) zu verwenden. SkeinParameters.java 246

Zuerst habe ich einen Blick auf GitHub geworfen. Was wäre, wenn es wirklich ein Fehler wäre, die Entwickler ihn bereits gefunden und einen Fix vorgenommen hätten? Genau das ist passiert. Hier ist ein Link zum Commit, den Sie sich ansehen können. Alle unsere „Y“-Zeichen (Wochenjahr) im Muster wurden durch „y“ (Jahr) ersetzt.

Sie fragen sich vielleicht, warum die Commits schon vor relativ langer Zeit vorgenommen wurden. Lass es mich erklären. Unsere Regressionstests sind nicht dazu gedacht, die Qualität dieses oder jenes Open-Source-Projekts kontinuierlich zu kontrollieren. Die Aufgabe besteht darin, zu sehen, wie sich der Bericht ändert, wenn neue Diagnoseregeln hinzugefügt werden: Es sollten keine alten Warnungen verschwinden, keine neuen Fehler erscheinen, da dies darauf hinweisen würde, dass der Analysator ein Problem hat. Der überprüfte Code muss also derselbe sein.

Opengrok

Werfen wir nun einen Blick auf das zweite Projekt, bei dem die Diagnoseregel ausgelöst wurde.

Die PVS-Studio-Warnung:

V6122 Verwendung des Musters „Y“ (Woche, Jahr) wurde erkannt: Es war wahrscheinlich beabsichtigt, „y“ (Jahr) zu verwenden. RepositoryInfo.java 77

Der Code:

public static void main(String[] args) {
    Date date = new Date("2024/12/31");
    var dateFormatter = new SimpleDateFormat("dd-MM-YYYY");
    System.out.println(dateFormatter.format(date));
}

Genau wie beim vorherigen Projekt eilte ich zu den Commits, um zu sehen, was los war. Zunächst ist es erwähnenswert, dass das Feld als Ergebnis des Refactorings in seine abgeleitete Klasse Repository verschoben wurde (hier ist der Link zum Commit). Ich habe weiter gesucht und einen Commit gefunden, der den Fix enthält. Das „Y“-Zeichen im Datumsmuster wurde durch „y“ ersetzt:

public static void main(String[] args) {
    LocalDate date = LocalDate.of(2024, 12, 31);
    var formatter = DateTimeFormatter.ofPattern("dd-MM-YYYY");
    System.out.println(formatter.format(date));
}

Es war also auch hier ein Fehler.

Abschluss

Bei PVS-Studio freuen wir uns über jedes Feedback aus der Community. Nachdem wir den Kommentar eines Habr-Benutzers bearbeitet haben, haben wir den Java-Analysator durch das Hinzufügen einiger nützlicher Diagnoseregeln erweitert. Wenn Sie also irgendwelche Gedanken haben, die Sie uns mitteilen möchten, würden wir uns gerne im Kommentarbereich dieses Artikels mit Ihnen unterhalten.

Übrigens wurde die Diagnoseregel in der Oktoberversion 7.33 eingeführt. Wenn Sie also unseren Analysator ausprobieren möchten, verwenden Sie diesen Link.

Das ist alles. Lassen Sie uns die Dinge hier zum Abschluss bringen. Hoffentlich überrascht Sie die plötzliche Reise ein Jahr vorwärts (oder rückwärts) nicht.

Das obige ist der detaillierte Inhalt vonJJJJ? jjjj!. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn