在java.util。日历中,一月被定义为第0个月,而不是第1个月。这有什么具体原因吗?

我看到很多人对此感到困惑……


当前回答

因为程序员痴迷于基于0的索引。好吧,实际情况要比这复杂一些:当您使用基于0的索引来处理底层逻辑时,它更有意义。但总的来说,我还是会坚持我的第一句话。

其他回答

这只是Java日期/时间API这一可怕的混乱的一部分。列出它的问题将花费很长时间(而且我确信我不知道一半的问题)。不可否认,处理日期和时间是很棘手的,但不管怎样。

帮自己一个忙,使用Joda Time代替,或者可能使用JSR-310。

编辑:至于原因——正如在其他回答中提到的,这很可能是由于旧的C api,或者只是一种从0开始的感觉……当然,除了一天从1开始。我怀疑原始实现团队之外的任何人都不能真正说出原因——但是,我再次敦促读者不要过于担心为什么做出了糟糕的决定,而是要看看java.util.Calendar中所有糟糕的事情,并找到更好的东西。

支持使用基于0的索引的一点是,它使“名称数组”之类的事情更容易:

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

当然,一旦你有了13个月的日历,这种方法就行不通了……但至少指定的大小是您期望的月数。

这不是一个很好的理由,但它是一个理由……

编辑:作为一个评论,请求一些关于我认为日期/日历错误的想法:

Surprising bases (1900 as the year base in Date, admittedly for deprecated constructors; 0 as the month base in both) Mutability - using immutable types makes it much simpler to work with what are really effectively values An insufficient set of types: it's nice to have Date and Calendar as different things, but the separation of "local" vs "zoned" values is missing, as is date/time vs date vs time An API which leads to ugly code with magic constants, instead of clearly named methods An API which is very hard to reason about - all the business about when things are recomputed etc The use of parameterless constructors to default to "now", which leads to hard-to-test code The Date.toString() implementation which always uses the system local time zone (that's confused many Stack Overflow users before now)

在Java 8中,有一个新的日期/时间API JSR 310,它更加合理。规范负责人与JodaTime的主要作者相同,他们共享许多相似的概念和模式。

对我来说,没有人比mindpro.com更能解释这一点:

Gotchas java.util.GregorianCalendar has far fewer bugs and gotchas than the old java.util.Date class but it is still no picnic. Had there been programmers when Daylight Saving Time was first proposed, they would have vetoed it as insane and intractable. With daylight saving, there is a fundamental ambiguity. In the fall when you set your clocks back one hour at 2 AM there are two different instants in time both called 1:30 AM local time. You can tell them apart only if you record whether you intended daylight saving or standard time with the reading. Unfortunately, there is no way to tell GregorianCalendar which you intended. You must resort to telling it the local time with the dummy UTC TimeZone to avoid the ambiguity. Programmers usually close their eyes to this problem and just hope nobody does anything during this hour. Millennium bug. The bugs are still not out of the Calendar classes. Even in JDK (Java Development Kit) 1.3 there is a 2001 bug. Consider the following 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 */ The bug disappears at 7AM on 2001/01/01 for MST. GregorianCalendar is controlled by a giant of pile of untyped int magic constants. This technique totally destroys any hope of compile-time error checking. For example to get the month you use GregorianCalendar. get(Calendar.MONTH)); GregorianCalendar has the raw GregorianCalendar.get(Calendar.ZONE_OFFSET) and the daylight savings GregorianCalendar. get( Calendar. DST_OFFSET), but no way to get the actual time zone offset being used. You must get these two separately and add them together. GregorianCalendar.set( year, month, day, hour, minute) does not set the seconds to 0. DateFormat and GregorianCalendar do not mesh properly. You must specify the Calendar twice, once indirectly as a Date. If the user has not configured his time zone correctly it will default quietly to either PST or GMT. In GregorianCalendar, Months are numbered starting at January=0, rather than 1 as everyone else on the planet does. Yet days start at 1 as do days of the week with Sunday=1, Monday=2,… Saturday=7. Yet DateFormat. parse behaves in the traditional way with January=1.

除了DannySmurf关于懒惰的回答之外,我还要补充一句,这是为了鼓励您使用常量,例如Calendar.JANUARY。

因为所有东西都是从0开始的。这是Java编程的一个基本事实。如果有一件事偏离了这一点,那么就会导致一系列的混乱。让我们不要争论它们的构成和代码。