为什么 Java 日历中的 1 月为 0?

2022-08-31 04:58:38

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

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


答案 1

这只是可怕的混乱的一部分,即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个月的日历,这就会失败......但至少指定的大小是您期望的月数。

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

编辑:作为评论,我要求一些关于我认为日期/日历有问题的想法:

  • 令人惊讶的基数(1900 年作为 Date 中的年基数,诚然,对于已弃用的构造函数;0 作为两者的月基数)
  • 可变性 - 使用不可变类型可以更轻松地处理真正有效的
  • 一组不充分的类型:拥有和不同的东西是很好的,但是缺少“本地”与“分区”值的分离,日期/时间与日期与时间DateCalendar
  • 一个API,它导致带有魔术常量的丑陋代码,而不是明确命名的方法
  • 一个非常难以推理的API - 所有关于何时重新计算事物的业务等
  • 使用无参数构造函数默认为“now”,这会导致代码难以测试
  • 始终使用系统本地时区的实现(这在以前使许多Stack Overflow用户感到困惑)Date.toString()

答案 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

所有月份的工作方式都是一样的,不需要解决方法。


推荐