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...

356voto

Jon Skeet Punkte 1325502

Das ist nur ein Teil des schrecklichen Durcheinanders, das die Java Datum/Zeit-API darstellt. Aufzulisten, was damit nicht in Ordnung ist, würde sehr lange dauern (und ich bin sicher, dass ich nicht einmal die Hälfte der Probleme kenne). Zugegeben, die Arbeit mit Daten und Zeiten ist knifflig, aber aaargh sowieso.

Tun Sie sich einen Gefallen und verwenden Sie Joda Zeit stattdessen, oder möglicherweise JSR-310 .

EDIT: Was die Gründe dafür angeht - wie in anderen Antworten erwähnt, könnte es durchaus an alten C-APIs liegen, oder einfach an dem allgemeinen Gefühl, dass alles bei 0 anfängt... außer, dass Tage mit 1 beginnen, natürlich. Ich bezweifle, dass irgendjemand außerhalb des ursprünglichen Implementierungsteams wirklich Gründe nennen kann - aber auch hier möchte ich den Lesern raten, sich nicht so viele Sorgen zu machen 如何して Fehlentscheidungen getroffen wurden, als die ganze Palette der Gemeinheiten in java.util.Calendar und etwas Besseres zu finden.

Ein Punkt, der ist für die Verwendung von 0-basierten Indizes ist, dass es Dinge wie "Arrays von Namen" einfacher macht:

// I "know" there are 12 months
String[] monthNames = new String[12]; // and populate...
String name = monthNames[calendar.get(Calendar.MONTH)];

Das klappt natürlich nicht, sobald man einen Kalender mit 13 Monaten erhält... aber zumindest ist die angegebene Größe die Anzahl der Monate, die man erwartet.

Dies ist keine gut Grund, aber es ist a Grund...

EDIT: Als eine Art Kommentar fordert einige Ideen darüber, was ich denke, ist falsch mit Datum/Kalender:

  • Überraschende Basen (1900 als Jahresbasis in Date, zugegebenermaßen für veraltete Konstruktoren; 0 als Monatsbasis in beiden)
  • Veränderbarkeit - die Verwendung unveränderlicher Typen macht es viel einfacher, mit dem zu arbeiten, was wirklich effektiv ist Werte
  • Ein unzureichender Satz von Typen: es ist schön, wenn man Date y Calendar als unterschiedliche Dinge, aber die Trennung zwischen "lokalen" und "zonierten" Werten fehlt, ebenso wie die Trennung zwischen Datum/Uhrzeit und Datum/Zeit
  • Eine API, die zu hässlichem Code mit magischen Konstanten anstelle von klar benannten Methoden führt
  • Eine API, die sehr schwer zu verstehen ist - der ganze Aufwand, wenn Dinge neu berechnet werden usw.
  • Die Verwendung von Konstruktoren ohne Parameter, die standardmäßig auf "now" eingestellt sind, was zu schwer zu testendem Code führt
  • En Date.toString() Implementierung, die immer die lokale Zeitzone des Systems verwendet (das hat schon viele Stack Overflow-Benutzer verwirrt)

59voto

arucker Punkte 641

Denn Rechnen mit Monaten ist viel einfacher.

1 Monat nach Dezember ist Januar, aber um das herauszufinden, müssten Sie normalerweise die Monatszahl nehmen und rechnen

12 + 1 = 13 // What month is 13?

Ich weiß! Ich kann dies schnell beheben, indem ich einen Modulus von 12 verwende.

(12 + 1) % 12 = 1

Das funktioniert 11 Monate lang gut, bis November...

(11 + 1) % 12 = 0 // What month is 0?

Man kann das Ganze wieder hinbekommen, indem man 1 subtrahiert, bevor man den Monat addiert, dann den Modulus durchführt und schließlich wieder 1 addiert... aka ein zugrundeliegendes Problem umgehen.

((11 - 1 + 1) % 12) + 1 = 12 // Lots of magical numbers!

Betrachten wir nun das Problem mit den Monaten 0 - 11.

(0 + 1) % 12 = 1 // February
(1 + 1) % 12 = 2 // March
(2 + 1) % 12 = 3 // April
(3 + 1) % 12 = 4 // May
(4 + 1) % 12 = 5 // June
(5 + 1) % 12 = 6 // July
(6 + 1) % 12 = 7 // August
(7 + 1) % 12 = 8 // September
(8 + 1) % 12 = 9 // October
(9 + 1) % 12 = 10 // November
(10 + 1) % 12 = 11 // December
(11 + 1) % 12 = 0 // January

Alle Monate funktionieren gleich und eine Umgehung ist nicht erforderlich.

38voto

stesch Punkte 7183

C-basierte Sprachen kopieren C bis zu einem gewissen Grad. Die tm Struktur (definiert in time.h ) hat ein ganzzahliges Feld tm_mon mit dem (kommentierten) Bereich von 0-11.

C-basierte Sprachen beginnen Arrays bei Index 0. Dies war also praktisch für die Ausgabe einer Zeichenkette in einem Array mit Monatsnamen, mit tm_mon als Index.

27voto

piksel bitworks Punkte 653

Es gab schon viele Antworten auf diese Frage, aber ich werde trotzdem meine Meinung zu diesem Thema äußern. Der Grund für dieses merkwürdige Verhalten liegt, wie bereits erwähnt, in der POSIX C time.h wobei die Monate in einem int mit dem Bereich 0-11 gespeichert wurden. Um zu erklären, warum, betrachten Sie es so: Jahre und Tage werden in der gesprochenen Sprache als Zahlen betrachtet, aber Monate haben ihre eigenen Namen. Da der Januar also der erste Monat ist, wird er als Offset 0, dem ersten Array-Element, gespeichert. monthname[JANUARY] wäre "January" . Der erste Monat des Jahres ist das erste Element des Monatsarrays.

Da die Tageszahlen keine Namen haben, wäre es verwirrend, sie als 0-30 in einer int-Datei zu speichern, was eine Menge an day+1 Anweisungen für die Ausgabe und sind natürlich anfällig für viele Bugs.

Abgesehen davon ist die Inkonsistenz verwirrend, vor allem in Javascript (das dieses "Feature" ebenfalls geerbt hat), einer Skriptsprache, in der dies weit von der Sprache abstrahiert werden sollte.

TL;DR : Weil die Monate Namen haben und die Tage des Monats nicht.

12voto

Alex Miller Punkte 67243

In Java 8 gibt es eine neue Date/Time-API JSR 310 die vernünftiger ist. Der Leiter der Spezifikation ist derselbe wie der Hauptautor von JodaTime und sie teilen viele ähnliche Konzepte und Muster.

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