Ist das nicht ein Implementierungsdetail, da die Konstanten JANUAR, FEBRUAR usw. existieren? Die Datumsklassen sind älter als die ordnungsgemäße Unterstützung von Java-Enums.
Gnud
6
Noch ärgerlicher - warum gibt es einen Undecember?
Matt B
40
@gnud: Nein, es ist kein Implementierungsdetail. Es ist sehr schmerzhaft, wenn Sie eine Ganzzahl in "natürlicher" Basis (dh Jan = 1) erhalten haben und diese mit der Kalender-API verwenden müssen.
Jon Skeet
1
@matt b: Es ist für nicht-gregorianische Kalender (Mondkalender usw.), die dreizehn Monate haben. Aus diesem Grund ist es am besten, nicht in Zahlen zu denken, sondern den Kalender die Lokalisierung vornehmen zu lassen.
Erickson
7
Das 13-monatige Argument macht keinen Sinn. Wenn dem so ist, warum sollte der zusätzliche Monat nicht 0 oder 13 sein?
Quinn Taylor
Antworten:
323
Es ist nur ein Teil des schrecklichen Chaos, das die Java-API für Datum und Uhrzeit darstellt. Das Auflisten, was daran falsch ist, würde sehr lange dauern (und ich bin sicher, dass ich die Hälfte der Probleme nicht kenne). Zugegeben, mit Datums- und Uhrzeitangaben zu arbeiten ist schwierig, aber trotzdem.
Tun Sie sich selbst einen Gefallen und verwenden Sie stattdessen Joda Time oder möglicherweise JSR-310 .
EDIT: Was die Gründe angeht, warum - wie in anderen Antworten erwähnt - dies möglicherweise auf alte C-APIs zurückzuführen ist oder nur auf das allgemeine Gefühl, alles mit 0 zu beginnen ... außer dass die Tage natürlich mit 1 beginnen. Ich bezweifle, dass jemand außerhalb des ursprünglichen Implementierungsteams wirklich Gründe angeben kann - aber ich möchte die Leser erneut auffordern, sich nicht so viele Gedanken darüber zu machen, warum schlechte Entscheidungen getroffen wurden, sondern die gesamte Bandbreite der Gemeinheit zu betrachten java.util.Calendarund etwas Besseres zu finden.
Ein Punkt, der ist für den Einsatz von 0 basierte Indizes ist , dass es Dinge wie „Arrays von Namen“ erleichtert:
// I "know" there are 12 monthsString[] monthNames =newString[12];// and populate...String name = monthNames[calendar.get(Calendar.MONTH)];
Dies schlägt natürlich fehl, sobald Sie einen Kalender mit 13 Monaten erhalten ... aber mindestens die angegebene Größe entspricht der Anzahl der Monate, die Sie erwarten.
Das ist kein guter Grund, aber es ist ein Grund ...
BEARBEITEN: Als Kommentar werden einige Ideen dazu angefordert, was meiner Meinung nach mit Datum / Kalender falsch ist:
Überraschende Basen (1900 als Jahresbasis in Datum, zugegebenermaßen für veraltete Konstrukteure; 0 als Monatsbasis in beiden)
Veränderbarkeit - Die Verwendung unveränderlicher Typen macht es viel einfacher, mit wirklich effektiven Werten zu arbeiten
Eine unzureichende Menge von Typen: Es ist schön zu haben Dateund Calendarals verschiedene Dinge, aber die Trennung von "lokalen" vs "zonierten" Werten fehlt, ebenso wie Datum / Uhrzeit vs Datum vs Zeit
Eine API, die zu hässlichem Code mit magischen Konstanten anstelle klar benannter Methoden führt
Eine API, über die man nur schwer nachdenken kann - das ganze Geschäft darüber, wann Dinge neu berechnet werden usw.
Die Verwendung parameterloser Konstruktoren wird standardmäßig auf "jetzt" gesetzt, was zu schwer zu testendem Code führt
Die Date.toString()Implementierung, die immer die lokale Zeitzone des Systems verwendet (das hat viele Stack Overflow-Benutzer bisher verwirrt)
... und was ist los mit all den nützlichen einfachen Date-Methoden? Jetzt muss ich dieses schreckliche Kalenderobjekt auf komplizierte Weise verwenden, um Dinge zu tun, die früher einfach waren.
Brian Knoblauch
3
@ Brian: Ich fühle deinen Schmerz. Wieder ist Joda Time einfacher :) (Der Unveränderlichkeitsfaktor macht es auch so viel angenehmer, damit zu arbeiten.)
Jon Skeet
8
Sie haben die Frage nicht beantwortet.
Zeemee
2
@ user443854: Ich habe einige Punkte in einer Bearbeitung aufgelistet - sehen Sie, ob das hilft.
Jon Skeet
2
Wenn Sie Java 8 verwenden, können Sie die Calendar-Klasse verlassen und zur neuen und eleganten DateTime-API wechseln . Die neue API enthält auch einen unveränderlichen / threadsicheren DateTimeFormatter, der eine große Verbesserung gegenüber dem problematischen und teuren SimpleDateFormat darstellt.
ccpizza
43
Weil es viel einfacher ist, mit Monaten zu rechnen.
1 Monat nach Dezember ist Januar, aber um dies normal herauszufinden, müssten Sie die Monatszahl nehmen und rechnen
12+1=13// What month is 13?
Ich weiß! Ich kann dies schnell beheben, indem ich einen Modul von 12 verwende.
(12+1)%12=1
Dies funktioniert gut für 11 Monate bis November ...
(11+1)%12=0// What month is 0?
Sie können all dies wieder zum Laufen bringen, indem Sie 1 subtrahieren, bevor Sie den Monat hinzufügen, dann Ihren Modul ausführen und schließlich wieder 1 hinzufügen ... auch bekannt als Umgehung eines zugrunde liegenden Problems.
((11-1+1)%12)+1=12// Lots of magical numbers!
Lassen Sie uns nun über das Problem mit den Monaten 0 - 11 nachdenken.
Das ist befriedigend. Zumindest hat dieser Wahnsinn einen gewissen Wert!
Moljac024
"Viele magische Zahlen" - nein, es ist nur eine, die zweimal vorkommt.
user123444555621
Einen Monat zurück zu gehen ist jedoch immer noch ein bisschen schwierig, dank Cs unglücklicher Verwendung eines "Rest" -Operators anstelle von "Modul". Ich bin mir auch nicht sicher, wie oft man wirklich einen Monat stoßen muss, ohne das Jahr anzupassen, und wenn die Monate 1-12 gehen, ist das kein Problem mit `while (Monat> 12) {month- = 12; Jahr ++;}
Supercat
2
Da vernünftige Funktionen wie DateTime.AddMonths zu schwierig sind, um richtig in einer Bibliothek implementiert zu werden, müssen wir die von Ihnen selbst beschriebenen Berechnungen
durchführen
8
Ich verstehe diese Upvotes nicht - ((11 - 1 + 1) % 12) + 1 = 12ist nur (11 % 12) + 1für Monate 1..12, Sie müssen nur die 1 hinzufügen, nachdem Sie das Modulo gemacht haben. Keine Magie erforderlich.
Mfitzp
35
C-basierte Sprachen kopieren C bis zu einem gewissen Grad. Die tmStruktur (definiert in time.h) hat ein ganzzahliges Feld tm_monmit dem (kommentierten) Bereich von 0-11.
C-basierte Sprachen starten Arrays bei Index 0. Dies war praktisch, um eine Zeichenfolge in einem Array von Monatsnamen mit tm_monals Index auszugeben.
Es gab viele Antworten darauf, aber ich werde trotzdem meine Meinung zu diesem Thema äußern. Der Grund für dieses seltsame Verhalten liegt, wie bereits erwähnt, bei POSIX C, time.hwo die Monate in einem Int mit dem Bereich 0-11 gespeichert wurden. Um zu erklären, warum, sehen Sie es so an; Jahre und Tage werden in gesprochener Sprache als Zahlen betrachtet, aber Monate haben ihre eigenen Namen. Da Januar der erste Monat ist, wird er als Offset 0, das erste Array-Element, gespeichert. monthname[JANUARY]wäre "January". Der erste Monat im Jahr ist das Array-Element des ersten Monats.
Die Tageszahlen hingegen sind verwirrend, da sie keine Namen haben und sie in einem int day+1von 0 bis 30 speichern. Sie fügen viele Anweisungen für die Ausgabe hinzu und sind natürlich anfällig für viele Fehler.
Abgesehen davon ist die Inkonsistenz verwirrend, insbesondere in Javascript (das auch dieses "Feature" geerbt hat), einer Skriptsprache, in der dies weit entfernt von der Sprache abstrahiert werden sollte.
TL; DR : Weil Monate Namen haben und Tage des Monats nicht.
"Monate haben Namen und Tage nicht." Schon mal was von 'Freitag' gehört? ;) OK, ich vermute, Sie meinten "..Tage des Monats nicht" - vielleicht würde es sich lohnen, Ihre (ansonsten gute) Antwort zu bearbeiten. :-)
Andrew Thompson
Wird 0/0/0000 besser als "00-Jan-0000" oder als "00-XXX-0000" gerendert? IMHO, viel Code wäre sauberer gewesen, wenn es dreizehn "Monate" gegeben hätte, aber Monat 0 wurde ein Dummy-Name gegeben.
Supercat
1
Das ist eine interessante Einstellung, aber 0/0/0000 ist kein gültiges Datum. Wie würden Sie 40/40/0000 rendern?
Piksel Bitworks
12
In Java 8 gibt es eine neue Datums- / Uhrzeit-API JSR 310 , die vernünftiger ist. Der Spezifikationsleiter ist der gleiche wie der Hauptautor von JodaTime und sie teilen viele ähnliche Konzepte und Muster.
Ich würde Faulheit sagen. Arrays beginnen bei 0 (das weiß jeder); Die Monate des Jahres sind ein Array, was mich glauben lässt, dass sich ein Ingenieur bei Sun einfach nicht die Mühe gemacht hat, diese eine Kleinigkeit in den Java-Code zu integrieren.
Nein, würde ich nicht. Es ist wichtiger, die Effizienz der Kunden zu optimieren als die Programmierer. Da dieser Kunde hier Zeit damit verbringt zu fragen, ist er dabei gescheitert.
TheSmurf
2
Es hat nichts mit Effizienz zu tun - es ist nicht so, als würden Monate in einem Array gespeichert, und Sie würden 13 benötigen, um 12 Monate darzustellen. Es geht darum, die API nicht so benutzerfreundlich zu gestalten, wie es eigentlich hätte sein sollen. Josh Bloch zeigt Datum und Kalender in "Effective Java". Sehr wenige APIs sind perfekt, und die Datums- / Zeit-APIs in Java haben die unglückliche Rolle, diejenigen zu sein, die vermasselt wurden. So ist das Leben, aber tun wir nicht so, als hätte es etwas mit Effizienz zu tun.
Quinn Taylor
1
Warum dann nicht Tage von 0 bis 30 zählen? Es ist nur inkonsistent und schlampig.
Weil Programmierer von 0-basierten Indizes besessen sind. OK, es ist etwas komplizierter: Es ist sinnvoller, wenn Sie mit Logik auf niedrigerer Ebene arbeiten, die 0-basierte Indizierung zu verwenden. Aber im Großen und Ganzen bleibe ich immer noch bei meinem ersten Satz.
Dies ist ein weiterer dieser Idiome / Gewohnheiten , die gehen Weg zu Assembler oder Maschinensprache zurück , wo alles in Bezug auf die Offsets erfolgt, nicht Indizes. Die Array-Notation wurde zu einer Abkürzung für den Zugriff auf zusammenhängende Blöcke, beginnend mit Offset 0.
Ken Gentle
4
Persönlich nahm ich die Seltsamkeit der Java-Kalender-API als Hinweis darauf, dass ich mich von der gregorianischen Denkweise trennen und versuchen musste, diesbezüglich agnostischer zu programmieren. Insbesondere habe ich noch einmal gelernt, fest codierte Konstanten für Dinge wie Monate zu vermeiden.
Welche der folgenden Aussagen ist wahrscheinlicher?
Dies zeigt eine Sache, die mich ein wenig an Joda Time ärgert - es kann Programmierer dazu ermutigen, in fest codierten Konstanten zu denken. (Nur ein bisschen. Es ist nicht so, als ob Joda Programmierer dazu zwingt , schlecht zu programmieren.)
Aber welches Schema bereitet Ihnen eher Kopfschmerzen, wenn Sie keine Konstante in Ihrem Code haben - Sie haben einen Wert, der das Ergebnis eines Webdienstaufrufs oder was auch immer ist.
Jon Skeet
Dieser Webdienstaufruf sollte natürlich auch diese Konstante verwenden. :-) Gleiches gilt für jeden externen Anrufer. Sobald wir festgestellt haben, dass mehrere Standards existieren, wird die Notwendigkeit, einen durchzusetzen, offensichtlich. (Ich hoffe, ich habe Ihren Kommentar verstanden ...)
Paul Brinkley
3
Ja, wir sollten den Standard durchsetzen, den fast alles andere auf der Welt verwendet, um Monate auszudrücken - den 1-basierten Standard.
Jon Skeet
Das Schlüsselwort hier ist "fast". Natürlich fühlt sich Jan = 1 usw. in einem Datumssystem mit extrem großer Verwendung natürlich an, aber warum sollten wir auch in diesem Fall eine Ausnahme von der Vermeidung fest codierter Konstanten machen?
Paul Brinkley
3
Weil es das Leben leichter macht. Es tut es einfach. Ich habe noch nie ein Problem mit einem 1-basierten Monatssystem festgestellt . Ich habe viele solche Fehler mit der Java-API gesehen. Zu ignorieren, was alle anderen auf der Welt tun, macht einfach keinen Sinn.
Jon Skeet
4
Für mich erklärt es niemand besser als mindpro.com :
Fallstricke
java.util.GregorianCalendarhat weit weniger Käfer und Fallstricke als die
old java.util.DateKlasse, aber es ist immer noch kein Picknick.
Hätte es Programmierer gegeben, als die Sommerzeit zum ersten Mal vorgeschlagen wurde, hätten sie ein Veto gegen sie eingelegt, da sie verrückt und unlösbar waren. Bei der Sommerzeit besteht eine grundlegende Unklarheit. Im Herbst, wenn Sie Ihre Uhren um eine Stunde um 2 Uhr morgens zurückstellen, gibt es zwei verschiedene Zeitpunkte, die beide als 1:30 Uhr Ortszeit bezeichnet werden. Sie können sie nur unterscheiden, wenn Sie mit dem Messwert aufzeichnen, ob Sie Sommerzeit oder Standardzeit beabsichtigt haben.
Leider können Sie nicht sagen, GregorianCalendarwelche Sie beabsichtigt haben. Um die Mehrdeutigkeit zu vermeiden, müssen Sie die Ortszeit mit der Dummy-UTC-Zeitzone angeben. Programmierer schließen normalerweise die Augen vor diesem Problem und hoffen nur, dass in dieser Stunde niemand etwas tut.
Millennium Bug. Die Fehler gehören immer noch nicht zu den Kalenderklassen. Selbst in JDK (Java Development Kit) 1.3 gibt es einen Fehler von 2001. Betrachten Sie den folgenden Code:
GregorianCalendar gc =newGregorianCalendar();
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 am 01.01.2001 um 7 Uhr morgens für MST.
GregorianCalendarwird von einem Riesenhaufen untypisierter int magischer Konstanten kontrolliert. Diese Technik zerstört völlig jede Hoffnung auf eine Fehlerprüfung zur Kompilierungszeit. Zum Beispiel, um den Monat zu erhalten, den Sie verwenden
GregorianCalendar. get(Calendar.MONTH));
GregorianCalendarhat die Roh-
GregorianCalendar.get(Calendar.ZONE_OFFSET)und die Sommerzeit
GregorianCalendar. get( Calendar. DST_OFFSET), aber keine Möglichkeit, den tatsächlich verwendeten Zeitzonenversatz zu erhalten. Sie müssen diese beiden separat erhalten und addieren.
GregorianCalendar.set( year, month, day, hour, minute) setzt die Sekunden nicht auf 0.
DateFormatund GregorianCalendarnicht richtig ineinander greifen. Sie müssen den Kalender zweimal angeben, einmal indirekt als Datum.
Wenn der Benutzer seine Zeitzone nicht richtig konfiguriert hat, wird standardmäßig entweder PST oder GMT verwendet.
Im Gregorianischen Kalender werden die Monate ab Januar = 0 nummeriert und nicht wie alle anderen auf dem Planeten mit 1. Die Tage beginnen jedoch bei 1, ebenso wie die Wochentage mit Sonntag = 1, Montag = 2,… Samstag = 7. Noch DateFormat. parse verhält sich traditionell mit Januar = 1.
Java bietet Ihnen eine weitere Möglichkeit, 1-basierte Indizes monatelang zu verwenden. Verwenden Sie die java.time.MonthAufzählung. Für jeden der zwölf Monate ist ein Objekt vordefiniert. Sie haben Nummern von 1 bis 12 für Januar bis Dezember; Rufen Sie getValuefür die Nummer.
Verwenden Sie Month.JULY(Gibt Ihnen 7) anstelle von Calendar.JULY(Gibt Ihnen 6).
Jetzt haben wir einen modernen Ersatz für diese problematischen alten alten Datums- und Zeitklassen : die java.time- Klassen.
java.time.Month
Unter diesen Klassen ist die Aufzählung . Eine Aufzählung enthält ein oder mehrere vordefinierte Objekte, Objekte, die beim Laden der Klasse automatisch instanziiert werden. Auf wir ein Dutzend solcher Objekte haben, da jeder einen Namen: , , , und so weiter. Jedes davon ist eine Klassenkonstante. Sie können diese Objekte überall in Ihrem Code verwenden und übergeben. Beispiel:MonthMonthJANUARYFEBRUARYMARCHstatic final publicsomeMethod( Month.AUGUST )
Glücklicherweise haben sie eine vernünftige Nummerierung, 1-12, wobei 1 Januar und 12 Dezember ist.
Holen Sie sich ein MonthObjekt für eine bestimmte Monatsnummer (1-12).
Month month =Month.of(2);// 2 → February.
Wenn Sie in die andere Richtung gehen, fragen Sie ein MonthObjekt nach seiner Monatsnummer.
int monthNumber =Month.FEBRUARY.getValue();// February → 2.
Außerdem sollten Sie Objekte dieser Aufzählung um Ihre Codebasis herum übergeben und nicht nur Ganzzahlen . Dies bietet Typensicherheit, stellt einen gültigen Wertebereich sicher und macht Ihren Code selbstdokumentierender. Weitere Informationen finden Sie im Oracle-Lernprogramm, wenn Sie mit der überraschend leistungsstarken Enum-Funktion in Java nicht vertraut sind.
Sie können auch die Yearund YearMonthKlassen nützlich finden .
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 .
Es ist nicht genau als Null an sich definiert, sondern als Kalender.Januar. Es ist das Problem, Ints als Konstanten anstelle von Enums zu verwenden. Kalender.Januar == 0.
Die Werte sind ein und dasselbe. Die APIs können auch 0 zurückgeben, es ist identisch mit der Konstante. Calendar.JANUARY hätte als 1 definiert werden können - das ist der springende Punkt. Eine Aufzählung wäre eine gute Lösung, aber echte Aufzählungen wurden der Sprache erst in Java 5 hinzugefügt, und Date gibt es von Anfang an. Es ist bedauerlich, aber Sie können eine so grundlegende API wirklich nicht "reparieren", wenn sie von Code von Drittanbietern verwendet wird. Das Beste, was getan werden kann, ist, eine neue API bereitzustellen und die alte zu verwerfen, um die Leute zu ermutigen, weiterzumachen. Vielen Dank, Java 7 ...
Quinn Taylor
0
Weil das Schreiben von Sprachen schwieriger ist als es aussieht und insbesondere der Umgang mit Zeit viel schwieriger ist als die meisten Leute denken. Einen kleinen Teil des Problems (in Wirklichkeit nicht Java) finden Sie im YouTube-Video "Das Problem mit Zeit und Zeitzonen - Computerphile" unter https://www.youtube.com/watch?v=-5wpm-gesOY . Seien Sie nicht überrascht, wenn Ihr Kopf vom verwirrten Lachen abfällt.
Das ist alles sehr gut, wenn Sie den Code explizit für einen bestimmten Monat schreiben, aber es ist ein Schmerz, wenn Sie den Monat in "normaler" Form aus einer anderen Quelle haben.
Jon Skeet
1
Es ist auch ein Schmerz, wenn Sie versuchen, diesen Monatswert auf eine bestimmte Weise zu drucken - Sie fügen immer 1 hinzu.
Brian Warshaw
-2
Weil alles mit 0 beginnt. Dies ist eine grundlegende Tatsache der Programmierung in Java. Wenn eine Sache davon abweichen würde, würde dies zu einer ganzen Reihe von Verwirrung führen. Lassen Sie uns nicht über ihre Entstehung streiten und mit ihnen codieren.
Nein, die meisten Dinge in der realen Welt beginnen mit 1. Offsets beginnen mit 0, und der Monat des Jahres ist kein Offset, sondern einer der zwölf, genau wie der Tag des Monats einer der 31 oder 30 oder 29 oder ist 28. Die Behandlung des Monats als Versatz ist nur launisch, insbesondere wenn wir gleichzeitig den Tag des Monats nicht auf die gleiche Weise behandeln. Was wäre der Grund für diesen Unterschied?
SantiBailors
In der realen Welt beginnen Sie mit 1, in der Java-Welt beginnen Sie mit 0. ABER ... Ich denke, das liegt daran, dass: - um den Wochentag zu berechnen, er nicht für ein paar Berechnungen ausgeglichen werden kann, ohne ein paar weitere Schritte hinzuzufügen it ... - Zusätzlich werden bei Bedarf die vollständigen Tage im Monat angezeigt (ohne Verwirrung oder Überprüfung des Februar). - Für den Monat werden Sie gezwungen, in einem Datumsformat auszugeben, das in beiden Fällen verwendet werden sollte. Da die Anzahl der Monate in einem Jahr regelmäßig ist und die Tage in einem Monat nicht, ist es außerdem sinnvoll, Arrays zu deklarieren und einen Offset zu verwenden, um das Array besser anzupassen.
Antworten:
Es ist nur ein Teil des schrecklichen Chaos, das die Java-API für Datum und Uhrzeit darstellt. Das Auflisten, was daran falsch ist, würde sehr lange dauern (und ich bin sicher, dass ich die Hälfte der Probleme nicht kenne). Zugegeben, mit Datums- und Uhrzeitangaben zu arbeiten ist schwierig, aber trotzdem.
Tun Sie sich selbst einen Gefallen und verwenden Sie stattdessen Joda Time oder möglicherweise JSR-310 .
EDIT: Was die Gründe angeht, warum - wie in anderen Antworten erwähnt - dies möglicherweise auf alte C-APIs zurückzuführen ist oder nur auf das allgemeine Gefühl, alles mit 0 zu beginnen ... außer dass die Tage natürlich mit 1 beginnen. Ich bezweifle, dass jemand außerhalb des ursprünglichen Implementierungsteams wirklich Gründe angeben kann - aber ich möchte die Leser erneut auffordern, sich nicht so viele Gedanken darüber zu machen, warum schlechte Entscheidungen getroffen wurden, sondern die gesamte Bandbreite der Gemeinheit zu betrachten
java.util.Calendar
und etwas Besseres zu finden.Ein Punkt, der ist für den Einsatz von 0 basierte Indizes ist , dass es Dinge wie „Arrays von Namen“ erleichtert:
Dies schlägt natürlich fehl, sobald Sie einen Kalender mit 13 Monaten erhalten ... aber mindestens die angegebene Größe entspricht der Anzahl der Monate, die Sie erwarten.
Das ist kein guter Grund, aber es ist ein Grund ...
BEARBEITEN: Als Kommentar werden einige Ideen dazu angefordert, was meiner Meinung nach mit Datum / Kalender falsch ist:
Date
undCalendar
als verschiedene Dinge, aber die Trennung von "lokalen" vs "zonierten" Werten fehlt, ebenso wie Datum / Uhrzeit vs Datum vs ZeitDate.toString()
Implementierung, die immer die lokale Zeitzone des Systems verwendet (das hat viele Stack Overflow-Benutzer bisher verwirrt)quelle
Weil es viel einfacher ist, mit Monaten zu rechnen.
1 Monat nach Dezember ist Januar, aber um dies normal herauszufinden, müssten Sie die Monatszahl nehmen und rechnen
Ich weiß! Ich kann dies schnell beheben, indem ich einen Modul von 12 verwende.
Dies funktioniert gut für 11 Monate bis November ...
Sie können all dies wieder zum Laufen bringen, indem Sie 1 subtrahieren, bevor Sie den Monat hinzufügen, dann Ihren Modul ausführen und schließlich wieder 1 hinzufügen ... auch bekannt als Umgehung eines zugrunde liegenden Problems.
Lassen Sie uns nun über das Problem mit den Monaten 0 - 11 nachdenken.
Alle Monate arbeiten gleich und eine Umgehung ist nicht erforderlich.
quelle
((11 - 1 + 1) % 12) + 1 = 12
ist nur(11 % 12) + 1
für Monate 1..12, Sie müssen nur die 1 hinzufügen, nachdem Sie das Modulo gemacht haben. Keine Magie erforderlich.C-basierte Sprachen kopieren C bis zu einem gewissen Grad. Die
tm
Struktur (definiert intime.h
) hat ein ganzzahliges Feldtm_mon
mit dem (kommentierten) Bereich von 0-11.C-basierte Sprachen starten Arrays bei Index 0. Dies war praktisch, um eine Zeichenfolge in einem Array von Monatsnamen mit
tm_mon
als Index auszugeben.quelle
Es gab viele Antworten darauf, aber ich werde trotzdem meine Meinung zu diesem Thema äußern. Der Grund für dieses seltsame Verhalten liegt, wie bereits erwähnt, bei POSIX C,
time.h
wo die Monate in einem Int mit dem Bereich 0-11 gespeichert wurden. Um zu erklären, warum, sehen Sie es so an; Jahre und Tage werden in gesprochener Sprache als Zahlen betrachtet, aber Monate haben ihre eigenen Namen. Da Januar der erste Monat ist, wird er als Offset 0, das erste Array-Element, gespeichert.monthname[JANUARY]
wäre"January"
. Der erste Monat im Jahr ist das Array-Element des ersten Monats.Die Tageszahlen hingegen sind verwirrend, da sie keine Namen haben und sie in einem int
day+1
von 0 bis 30 speichern. Sie fügen viele Anweisungen für die Ausgabe hinzu und sind natürlich anfällig für viele Fehler.Abgesehen davon ist die Inkonsistenz verwirrend, insbesondere in Javascript (das auch dieses "Feature" geerbt hat), einer Skriptsprache, in der dies weit entfernt von der Sprache abstrahiert werden sollte.
TL; DR : Weil Monate Namen haben und Tage des Monats nicht.
quelle
In Java 8 gibt es eine neue Datums- / Uhrzeit-API JSR 310 , die vernünftiger ist. Der Spezifikationsleiter ist der gleiche wie der Hauptautor von JodaTime und sie teilen viele ähnliche Konzepte und Muster.
quelle
Ich würde Faulheit sagen. Arrays beginnen bei 0 (das weiß jeder); Die Monate des Jahres sind ein Array, was mich glauben lässt, dass sich ein Ingenieur bei Sun einfach nicht die Mühe gemacht hat, diese eine Kleinigkeit in den Java-Code zu integrieren.
quelle
Wahrscheinlich, weil Cs "struct tm" dasselbe tut.
quelle
Weil Programmierer von 0-basierten Indizes besessen sind. OK, es ist etwas komplizierter: Es ist sinnvoller, wenn Sie mit Logik auf niedrigerer Ebene arbeiten, die 0-basierte Indizierung zu verwenden. Aber im Großen und Ganzen bleibe ich immer noch bei meinem ersten Satz.
quelle
Persönlich nahm ich die Seltsamkeit der Java-Kalender-API als Hinweis darauf, dass ich mich von der gregorianischen Denkweise trennen und versuchen musste, diesbezüglich agnostischer zu programmieren. Insbesondere habe ich noch einmal gelernt, fest codierte Konstanten für Dinge wie Monate zu vermeiden.
Welche der folgenden Aussagen ist wahrscheinlicher?
Dies zeigt eine Sache, die mich ein wenig an Joda Time ärgert - es kann Programmierer dazu ermutigen, in fest codierten Konstanten zu denken. (Nur ein bisschen. Es ist nicht so, als ob Joda Programmierer dazu zwingt , schlecht zu programmieren.)
quelle
Für mich erklärt es niemand besser als mindpro.com :
quelle
java.util.Month
Java bietet Ihnen eine weitere Möglichkeit, 1-basierte Indizes monatelang zu verwenden. Verwenden Sie die
java.time.Month
Aufzählung. Für jeden der zwölf Monate ist ein Objekt vordefiniert. Sie haben Nummern von 1 bis 12 für Januar bis Dezember; Rufen SiegetValue
für die Nummer.Verwenden Sie
Month.JULY
(Gibt Ihnen 7) anstelle vonCalendar.JULY
(Gibt Ihnen 6).quelle
tl; dr
Einzelheiten
Die Antwort von Jon Skeet ist richtig.
Jetzt haben wir einen modernen Ersatz für diese problematischen alten alten Datums- und Zeitklassen : die java.time- Klassen.
java.time.Month
Unter diesen Klassen ist die Aufzählung . Eine Aufzählung enthält ein oder mehrere vordefinierte Objekte, Objekte, die beim Laden der Klasse automatisch instanziiert werden. Auf wir ein Dutzend solcher Objekte haben, da jeder einen Namen: , , , und so weiter. Jedes davon ist eine Klassenkonstante. Sie können diese Objekte überall in Ihrem Code verwenden und übergeben. Beispiel:
Month
Month
JANUARY
FEBRUARY
MARCH
static final public
someMethod( Month.AUGUST )
Glücklicherweise haben sie eine vernünftige Nummerierung, 1-12, wobei 1 Januar und 12 Dezember ist.
Holen Sie sich ein
Month
Objekt für eine bestimmte Monatsnummer (1-12).Wenn Sie in die andere Richtung gehen, fragen Sie ein
Month
Objekt nach seiner Monatsnummer.Viele andere nützliche Methoden für diesen Kurs, z. B. die Anzahl der Tage pro Monat . Die Klasse kann sogar einen lokalisierten Namen des Monats generieren .
Sie können den lokalisierten Namen des Monats in verschiedenen Längen oder Abkürzungen abrufen.
Außerdem sollten Sie Objekte dieser Aufzählung um Ihre Codebasis herum übergeben und nicht nur Ganzzahlen . Dies bietet Typensicherheit, stellt einen gültigen Wertebereich sicher und macht Ihren Code selbstdokumentierender. Weitere Informationen finden Sie im Oracle-Lernprogramm, wenn Sie mit der überraschend leistungsstarken Enum-Funktion in Java nicht vertraut sind.
Sie können auch die
Year
undYearMonth
Klassen nützlich finden .Ü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
, &java.text.SimpleDateFormat
.Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu 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?
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 .quelle
Es ist nicht genau als Null an sich definiert, sondern als Kalender.Januar. Es ist das Problem, Ints als Konstanten anstelle von Enums zu verwenden. Kalender.Januar == 0.
quelle
Weil das Schreiben von Sprachen schwieriger ist als es aussieht und insbesondere der Umgang mit Zeit viel schwieriger ist als die meisten Leute denken. Einen kleinen Teil des Problems (in Wirklichkeit nicht Java) finden Sie im YouTube-Video "Das Problem mit Zeit und Zeitzonen - Computerphile" unter https://www.youtube.com/watch?v=-5wpm-gesOY . Seien Sie nicht überrascht, wenn Ihr Kopf vom verwirrten Lachen abfällt.
quelle
Zusätzlich zu DannySmurfs Antwort auf Faulheit möchte ich hinzufügen, dass es Sie ermutigen soll, die Konstanten zu verwenden, wie z
Calendar.JANUARY
.quelle
Weil alles mit 0 beginnt. Dies ist eine grundlegende Tatsache der Programmierung in Java. Wenn eine Sache davon abweichen würde, würde dies zu einer ganzen Reihe von Verwirrung führen. Lassen Sie uns nicht über ihre Entstehung streiten und mit ihnen codieren.
quelle