在java.util。日历中,一月被定义为第0个月,而不是第1个月。这有什么具体原因吗?
我看到很多人对此感到困惑……
在java.util。日历中,一月被定义为第0个月,而不是第1个月。这有什么具体原因吗?
我看到很多人对此感到困惑……
当前回答
因为程序员痴迷于基于0的索引。好吧,实际情况要比这复杂一些:当您使用基于0的索引来处理底层逻辑时,它更有意义。但总的来说,我还是会坚持我的第一句话。
其他回答
对我来说,没有人比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,而是定义为Calendar.January。这是使用整数作为常量而不是枚举的问题。日历。1月== 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)
There has been a lot of answers to this, but I will give my view on the subject anyway. The reason behind this odd behavior, as stated previously, comes from the POSIX C time.h where the months were stored in an int with the range 0-11. To explain why, look at it like this; years and days are considered numbers in spoken language, but months have their own names. So because January is the first month it will be stored as offset 0, the first array element. monthname[JANUARY] would be "January". The first month in the year is the first month array element.
另一方面,由于日期数字没有名称,将它们存储在0-30的int型中会令人困惑,添加大量的day+1指令用于输出,当然,也容易出现很多错误。
也就是说,这种不一致是令人困惑的,特别是在javascript(它也继承了这个“特性”)中,这种脚本语言应该从语言中抽象出来。
因为月份有名称,而月份中的日期没有。