当前位置:  开发笔记 > 编程语言 > 正文

为什么Java Calendar中的1月份为0?

如何解决《为什么JavaCalendar中的1月份为0?》经验,为你挑选了8个好方法。

java.util.Calendar,1月定义为第0个月,而不是第1个月.是否有任何具体原因?

我见过很多人对此感到困惑......



1> Jon Skeet..:

它只是Java日期/时间API的可怕混乱的一部分.列出它的错误需要很长时间(而且我确定我不知道一半的问题).无可否认地处理日期和时间是棘手的,但无论如何,aaargh.

帮自己一个忙,而不是使用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个月的日历,这就会失败......但至少指定的大小是您期望的月数.

这不是一个理由,但这是一个原因......

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

令人惊讶的基数(1900年作为Date的年份基础,不可否认的是被弃用的构造函数; 0作为两者的月基数)

可变性 - 使用不可变类型可以简单地处理真正有效的

一组不充分的类型:拥有DateCalendar不同的东西很好,但缺少"本地"与"分区"值的分离,日期/时间与日期与时间的关系也是如此

一个API导致带有魔术常量的丑陋代码,而不是明确命名的方法

一个非常难以推理的API - 关于重新计算事物的所有业务等

使用无参数构造函数默认为"now",这导致难以测试的代码

Date.toString()它总是使用系统本地时区的实现(这是以前,现在弄得很多堆栈溢出的用户)


...以及如何弃用所有有用的简单Date方法?现在我必须以复杂的方式使用那个可怕的Calendar对象来做一些过去简单的事情.
你没有回答这个问题.
@Brian:我感觉到你的痛苦.同样,Joda Time更简单:)(不变性因素也使得使用起来更加愉快.)
@ user443854:我在编辑中列出了一些要点 - 看看是否有帮助.
如果您正在使用Java 8,那么您可以抛弃Calendar类并切换到新的时尚[DateTime API](https://docs.oracle.com/javase/8/docs/api/java/time/package-summary的.html).新的API还包括一个不可变的/ threadsafe [DateTimeFormatter](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html),这是对问题和昂贵的SimpleDateFormat.

2> 小智..:

因为用数月做数学会容易得多.

12月之后的1个月是1月,但通常你需要拿出月份数并做数学

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

我知道!我可以使用12的模数快速解决这个问题.

(12 + 1) % 12 = 1

直到11月,这个工作正常11个月......

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

您可以通过在添加月份之前减去1来再次使所有这些工作,然后执行模数并最终再次添加1 ...也就是解决潜在问题.

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

现在让我们考虑一下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

所有月份的工作都相同,并且不需要解决问题.


这很令人满意.至少对这种疯狂有一些价值!
我不理解这些投票-`(((11-1 + 1)%12)+ 1 = 12`只是`(11%12)+ 1`,即对于1..12个月,您只需要添加1 *在*做模之后。不需要魔术。
由于类似DateTime.AddMonths之类的理智功能很难在lib中正确实现,因此我们必须自己进行数学描述... Mmmmmkay

3> stesch..:

基于C语言在某种程度上复制C. 的tm结构(在定义的time.h)具有一个整数字段tm_mon具有0-11的(注释)范围.

基于C语言在索引0处启动数组.因此,这对于输出月份名称数组中的字符串非常方便,并将其tm_mon作为索引.



4> piksel bitwo..:

对此有很多答案,但无论如何我都会就这个问题发表看法.如前所述,这种奇怪行为背后的原因来自POSIX C time.h,其中存储在0-11范围内的int的月份.为了解释原因,请这样看; 年和日被认为是口语中的数字,但是几个月都有自己的名字.因此,1月是第一个月,它将被存储为第一个数组元素offset 0.monthname[JANUARY]会的"January".一年中的第一个月是第一个月的数组元素.

另一方面,日期数字,因为它们没有名称,将它们存储在int中作为0-30会令人困惑,添加大量day+1输出指令,当然,容易出现很多错误.

话虽这么说,不一致是令人困惑的,特别是在javascript(它也继承了这个"功能"),一种脚本语言,这应该被抽象远离langague.

TL; DR:因为月份有名字,而月份没有.



5> Alex Miller..:

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


新的Date Time API现在是Java 8的一部分

6> TheSmurf..:

我会说懒惰.数组从0开始(每个人都知道); 一年中的几个月是一个阵列,这使我相信Sun的一些工程师只是不愿意把这一点放在Java代码中.


不,我不会.优化一个客户的效率比一个程序员更重要.由于这位顾客在这里花时间问,他们就失败了.
你可以称之为效率.
它与效率完全无关 - 它不像数月存储在一个阵列中,你需要13代表12个月.这是一个问题,就是不要让API像用户一样友好,因为它们应该首先出现.Josh Bloch在"有效Java"中破坏日期和日历.很少有API是完美的,Java中的日期/时间API具有不幸的作用.这就是生活,但我们不要假装它与效率有任何关系.

7> Paul Tomblin..:

可能是因为C的"struct tm"也是如此.



8> Dinah..:

因为程序员痴迷于基于0的索引.好吧,它比这更复杂:当你使用低级逻辑来使用基于0的索引时,它更有意义.但总的来说,我仍然坚持我的第一句话.

推荐阅读
吻过彩虹的脸_378
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有