这个答案搜了很多,好像也没有一个明确的回答
最初猜想:
Calendar
类当初设计时的一个bug,由于已经使用开来,没法贸然的修改
查源码找答案
下面是Calendar类中属性MONTH
的注释以及定义:
1 | /** |
注释大致的意思是:
字段编号指示
月份
以用于get/set方法,这是特定于日历的值。 格列高利历(Gregorian) /朱利安历(Julian)的一年中的第一个月是JANUARY
,即0
; 最后一个月份取决于一年中的月数。
最后一句话是什么意思呢? 下面再说。 我们一起看一下上述13
个月份的定义,请注意,不是12个月,而是13个月。
1 | /** |
把重点放在第一个月以及最后一个月的注释上面:
JANUARY初始化int数值 = 0
, 指示在格列高利历(Gregorian) /朱利安历(Julian)中的第一个月份
JANUARY = 0 - indicating the first month of the year in the Gregorian and Julian calendars.
格里高利历(Gregorian Calendar)
格里高利历,是国际通用的历法,即公历。到今天,格里高利历已被世界广泛采用,成为国际通用历法。
中国采用格里高利历
中国使用格里高利历是在公元1912年1月1日,中华民国成立之时。但由于历史原因,依旧使用中华民国记年。类似的情况如日本至今还保持着天皇年号纪年,比如平成某某年。公元1949年10月1日,中华人民共和国成立,正式采用公元纪年法。
因为中国人民在日常人活中的月份都是从1
开始计算的,而Calendar
类从0
开始算,于是乎便解释了为何取出的月份比实际少1
。
为何要将JANUARY定义为0
目前确实也没有一个准确的答案,但还是可以挑选出一些大家认为合理的:
- 数组以0作为索引开始,月份也借鉴此做法;
- 年份月份日期唯独只有月份有自己的名字,什么意思呢? 一月 = January,二月=February… 于是将其从0开始标注索引
- Java是基于C语言的,而C语言的’time.h’里面的月份
tm_mon
也是从0~11 - SUN公司开发人员的懒惰
【重要】使用Calendar关于月份的建议
set 月份时 一律 - 1
get 月份时 一律 + 1
1 |
|
当然在同时存在get()
和set()
月份方法的时候,你不额外加+1
和-1
,数据是没有问题的。但:如果两个方法调用相隔很远,又或者只有其中一个方法呢 ?
若是某个客户端使用了错误生成日历的方法,找到问题的根源会比较麻烦。尽可能的按照上述要求来做,这样在日历的月份上出错的可能性大大降低。
执行结果:
0
1
8