346 Stimmen

Warum ist der Januar im Java-Kalender der Monat 0?

En java.util.Calendar Der Januar ist als Monat 0 definiert, nicht als Monat 1. Gibt es dafür einen bestimmten Grund?

Ich habe gesehen, wie viele Leute darüber verwirrt waren...

4voto

Edwin Dalorzo Punkte 73377

Für mich erklärt es niemand besser als mindpro.de :

Gotchas

java.util.GregorianCalendar hat weit weniger Bugs und Probleme als old java.util.Date Klasse, aber es ist trotzdem kein Zuckerschlecken.

Hätte es Programmierer gegeben, als Daylight Sa vorgeschlagen wurde, hätten sie ihr Veto als unsinnig und unlösbar eingelegt. Mit Sommerzeit gibt es eine grundsätzliche Zweideutigkeit. Wenn man im Herbst stellen Sie Ihre Zeitpunkte, die beide 1:30 Uhr Ortszeit heißen. Sie können sie nur unterscheiden unterscheiden, wenn Sie bei der Ablesung vermerken, ob Sie Sommerzeit oder Sommerzeit oder Normalzeit ablesen.

Leider gibt es keine Möglichkeit zu sagen GregorianCalendar w beabsichtigt. Sie müssen sich darauf beschränken, ihm den Ort UTC TimeZone angeben, um die Mehrdeutigkeit zu vermeiden. Programmierer verschließen normalerweise ihre die Augen vor diesem Problem und hoffen einfach, dass in dieser Stunde niemand etwas tut. Stunde.

Millennium-Bug. Die Bugs sind immer noch nicht aus den Kalenderklassen verschwunden. Sogar im JDK (Java Development Kit) 1.3 gibt es einen Fehler aus dem Jahr 2001. Betrachten Sie den folgenden Code:

GregorianCalendar gc = new GregorianCalendar();
gc.setLenient( false );
/* Bug only manifests if lenient set false */
gc.set( 2001, 1, 1, 1, 0, 0 );
int year = gc.get ( Calendar.YEAR );
/* throws exception */

Der Fehler verschwindet um 7 Uhr morgens am 2001/01/01 für MST.

GregorianCalendar wird von einem riesigen Haufen von magischen Konstanten. Diese Technik macht jede Hoffnung auf eine Kompilierzeit-Fehlerprüfung. Um zum Beispiel die mo GregorianCalendar. get(Calendar.MONTH));

GregorianCalendar h GregorianCalendar.get(Calendar.ZONE_OFFSET) a GregorianCalendar. get( Calendar. DST_OFFSET) , tatsächliche Zeitzonenverschiebung. Sie müssen diese beiden Werte getrennt ermitteln und sie zusammenzählen.

GregorianCalendar.set( year, month, day, hour, minute) d die Sekunden auf 0.

DateFormat y GregorianCalendar nicht richtig ineinandergreifen. Sie müssen den Kalender zweimal angeben, einmal indirekt als Datum.

Wenn der Benutzer seine Zeitzone nicht konfiguriert hat, kann entweder auf PST oder GMT eingestellt.

Im GregorianischenKalender sind Monate n und nicht bei 1, wie es alle anderen Länder der Welt tun. Dennoch beginnen die Tage bei 1 wie auch die Wochentage mit Sonntag=1, Montag=2, Samstag=7. Dennoch DateFormat. parse verhält sich auf die traditionelle Weise mit Januar=1.

4voto

Paul Brinkley Punkte 6196

Ich persönlich nahm die Seltsamkeit der Java-Kalender-API als ein Zeichen dafür, dass ich mich von der gregorianischen Denkweise lösen und versuchen sollte, in dieser Hinsicht agnostischer zu programmieren. Insbesondere habe ich wieder einmal gelernt, hart kodierte Konstanten für Dinge wie Monate zu vermeiden.

Welche der folgenden Aussagen ist am ehesten zutreffend?

if (date.getMonth() == 3) out.print("March");

if (date.getMonth() == Calendar.MARCH) out.print("March");

Dies veranschaulicht eine Sache, die mich an Joda Time ein wenig stört - es könnte Programmierer dazu ermutigen, in Form von fest kodierten Konstanten zu denken. (Allerdings nur ein wenig. Es ist ja nicht so, dass Joda erzwingen. Programmierer schlecht zu programmieren.)

3voto

Basil Bourque Punkte 256611

Tl;dr

Month.FEBRUARY.getValue()  // February  2.

2

Einzelheiten

En Antwort von Jon Skeet ist richtig.

Jetzt haben wir einen modernen Ersatz für die lästigen alten Datum-Zeit-Klassen: die java.time Klassen.

java.time.Month

Zu diesen Klassen gehört auch die Month enum . Ein Enum enthält ein oder mehrere vordefinierte Objekte, die beim Laden der Klasse automatisch instanziiert werden. Auf Month haben wir ein Dutzend solcher Objekte, die jeweils einen Namen haben: JANUARY , FEBRUARY , MARCH , und so weiter. Jedes dieser Elemente ist ein static final public Klassenkonstante. Sie können diese Objekte überall in Ihrem Code verwenden und übergeben. Beispiel: someMethod( Month.AUGUST )

Zum Glück haben sie eine vernünftige Nummerierung: 1-12, wobei 1 für Januar und 12 für Dezember steht.

Erhalten Sie eine Month Objekt für eine bestimmte Monatsnummer (1-12).

Month month = Month.of( 2 );  // 2  February.

In der anderen Richtung, fragen Sie einen Month Objekt für seine Monatsnummer.

int monthNumber = Month.FEBRUARY.getValue();  // February  2.

Viele andere nützliche Methoden dieser Klasse, wie z.B. die Kenntnis die Anzahl der Tage in jedem Monat . Die Klasse kann sogar einen lokalisierten Namen erzeugen des Monats.

Sie können den lokalisierten Namen des Monats in verschiedenen Längen oder Abkürzungen erhalten.

String output = 
    Month.FEBRUARY.getDisplayName( 
        TextStyle.FULL , 
        Locale.CANADA_FRENCH 
    );

février

Außerdem sollten Sie Objekte dieser Aufzählung anstelle von Integer-Zahlen an Ihre Codebasis weitergeben . Dies bietet Typsicherheit, gewährleistet einen gültigen Wertebereich und sorgt für eine bessere Selbstdokumentation Ihres Codes. Siehe Oracle-Tutorial wenn Sie mit der erstaunlich leistungsfähigen enum-Funktion in Java nicht vertraut sind.

Nützlich sind auch die Year y YearMonth Klassen.


Über java.time

En java.time Framework ist in Java 8 und höher integriert. Diese Klassen verdrängen die lästigen alten Erbe Datum-Zeit-Klassen wie java.util.Date , .Calendar , & java.text.SimpleDateFormat .

En Joda-Time Projekt, jetzt in Wartungsmodus rät zur Migration auf java.time.

Weitere Informationen finden Sie in der Oracle-Tutorial . Und suchen Sie auf Stack Overflow nach vielen Beispielen und Erklärungen. Spezifikation ist JSR 310 .

Wo erhält man die java.time-Klassen?

  • Java SE 8 y SE 9 und später
    • Eingebaut.
    • Teil der Standard-Java-API mit einer gebündelten Implementierung.
    • Java 9 fügt einige kleinere Funktionen und Korrekturen hinzu.
  • Java SE 6 y SE 7
    • Ein Großteil der java.time-Funktionalität wurde in Java 6 und 7 zurückportiert in DreiZehn-Backport .
  • Android

En DreiZehn-Extra Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt dient als Versuchsfeld für mögliche zukünftige Erweiterungen von java.time. Sie finden hier vielleicht einige nützliche Klassen wie Interval , YearWeek , YearQuarter y mehr .

0voto

Pål GD Punkte 1011

Er ist nicht per se als Null definiert, sondern als Calendar.January. Dies ist das Problem der Verwendung von Ints als Konstanten anstelle von Enums. Kalender.Januar == 0.

0voto

Tihamer Punkte 835

Denn das Schreiben von Sprachen ist schwieriger, als es aussieht, und vor allem der Umgang mit der Zeit ist viel schwieriger, als die meisten Menschen denken. Einen kleinen Teil des Problems (in der Realität, nicht in Java) zeigt das YouTube-Video "The Problem with Time & Timezones - Computerphile" unter https://www.youtube.com/watch?v=-5wpm-gesOY . Wundern Sie sich nicht, wenn Ihnen vor lauter Lachen der Kopf abfällt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X