在java.util。日历中,一月被定义为第0个月,而不是第1个月。这有什么具体原因吗?
我看到很多人对此感到困惑……
在java.util。日历中,一月被定义为第0个月,而不是第1个月。这有什么具体原因吗?
我看到很多人对此感到困惑……
当前回答
可能是因为C的“struct tm”也有同样的功能。
其他回答
这只是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)
基于C的语言在某种程度上复制了C。tm结构(在time.h中定义)有一个整数字段tm_mon,(注释的)范围为0-11。
基于C的语言从索引0开始数组。因此,这对于以tm_mon作为索引输出月份名称数组中的字符串非常方便。
对我来说,没有人比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.
在Java 8中,有一个新的日期/时间API JSR 310,它更加合理。规范负责人与JodaTime的主要作者相同,他们共享许多相似的概念和模式。
就我个人而言,我认为Java日历API的奇特之处表明,我需要摆脱以格里高利为中心的思维方式,并尝试在这方面更加不可知论地编程。具体来说,我再次学会了避免对月份之类的常量进行硬编码。
下面哪个选项更可能是正确的?
if (date.getMonth() == 3) out.print("March");
if (date.getMonth() == Calendar.MARCH) out.print("March");
这说明了Joda Time让我有点恼火的一件事——它可能会鼓励程序员从硬编码常数的角度思考问题。(不过只有一点点。Joda并不是在强迫程序员糟糕地编程。)