为什么 Java 日历中的一月是 0 月?

新手上路,请多包涵

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

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

原文由 Stéphane Bonniez 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 755
2 个回答

它只是 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——关于何时重新计算的所有业务等
  • 使用无参数构造函数默认为“现在”,这导致代码难以测试
  • 始终使用系统本地时区的 Date.toString() 实现(之前让许多 Stack Overflow 用户感到困惑)

原文由 Jon Skeet 发布,翻译遵循 CC BY-SA 3.0 许可协议

因为用几个月做数学要容易得多。

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

所有月份的工作方式都相同,无需变通。

原文由 arucker 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题