Jon*_*eet 317
它只是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)];
Run Code Online (Sandbox Code Playgroud)
当然,只要您获得13个月的日历,这就会失败......但至少指定的大小是您期望的月数.
这不是一个好理由,但这是一个原因......
编辑:作为一种评论请求一些关于我认为日期/日历错误的想法:
Date
和Calendar
不同的东西很好,但缺少"本地"与"分区"值的分离,日期/时间与日期与时间的关系也是如此Date.toString()
它总是使用系统本地时区的实现(这是以前,现在弄得很多堆栈溢出的用户)小智 43
因为用数月做数学会容易得多.
12月之后的1个月是1月,但通常你需要拿出月份数并做数学
12 + 1 = 13 // What month is 13?
Run Code Online (Sandbox Code Playgroud)
我知道!我可以使用12的模数快速解决这个问题.
(12 + 1) % 12 = 1
Run Code Online (Sandbox Code Playgroud)
直到11月,这个工作正常11个月......
(11 + 1) % 12 = 0 // What month is 0?
Run Code Online (Sandbox Code Playgroud)
您可以通过在添加月份之前减去1来再次使所有这些工作,然后执行模数并最终再次添加1 ...也就是解决潜在问题.
((11 - 1 + 1) % 12) + 1 = 12 // Lots of magical numbers!
Run Code Online (Sandbox Code Playgroud)
现在让我们考虑一下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
Run Code Online (Sandbox Code Playgroud)
所有月份的工作都相同,并且不需要解决问题.
ste*_*sch 35
基于C语言在某种程度上复制C. 的tm
结构(在定义的time.h
)具有一个整数字段tm_mon
具有0-11的(注释)范围.
基于C语言在索引0处启动数组.因此,这对于输出月份名称数组中的字符串非常方便,并将其tm_mon
作为索引.
pik*_*rks 22
对此有很多答案,但无论如何我都会就这个问题发表看法.如前所述,这种奇怪行为背后的原因来自POSIX C time.h
,其中存储在0-11范围内的int的月份.为了解释原因,请这样看; 年和日被认为是口语中的数字,但是几个月都有自己的名字.因此,1月是第一个月,它将被存储为第一个数组元素offset 0.monthname[JANUARY]
会的"January"
.一年中的第一个月是第一个月的数组元素.
另一方面,日期数字,因为它们没有名称,将它们存储在int中作为0-30会令人困惑,添加大量day+1
输出指令,当然,容易出现很多错误.
话虽这么说,不一致是令人困惑的,特别是在javascript(它也继承了这个"功能"),一种脚本语言,这应该被抽象远离langague.
TL; DR:因为月份有名字,而月份没有.
我会说懒惰.数组从0开始(每个人都知道); 一年中的几个月是一个阵列,这使我相信Sun的一些工程师只是不愿意把这一点放在Java代码中.
java.time.Month
Java 为您提供了另一种使用基于 1 的索引数月的方法。使用java.time.Month
枚举。为十二个月中的每一个月预定义一个对象。1 月至 12 月的编号为 1-12;称呼getValue
电话索取号码。
使用Month.JULY
(Gives you 7) 而不是Calendar.JULY
(Gives you 6)。
(import java.time.*;)
Run Code Online (Sandbox Code Playgroud)
您可能会认为,当我们弃用 Date 的大部分内容并添加新的 Calendar 类时,我们就可以解决 Date 最大的烦恼:一月是第 0 个月。我们当然应该这样做,但不幸的是我们没有。我们担心如果 Date 使用从零开始的月份而 Calendar 使用从一开始的月份,程序员会感到困惑。一些程序员可能会这样。但事后看来,Calendar 仍然是从零开始的这一事实引起了巨大的混乱,这可能是 Java 国际 API 中最大的单一错误。
引用自Laura Werner 的Java 国际日历,链接位于底部。
这可能只是重复其他人所说的,抛弃旧的且设计不良的Calendar
类并使用 java.time,现代 Java 日期和时间 API。月份的编号一致,从 1 月(1 月)到 12 月(12 月)。
如果您从尚未升级到 java.time 的旧版 API 获取 a Calendar
,首先要做的就是转换为现代ZonedDateTime
. 根据您的需要,您可以从那里进行进一步的转换。在世界上的大多数地方,Calendar
您获得的对象实际上总是GregorianCalendar
子类的实例(因为Calendar
类本身是抽象的)。示范:
Calendar oldfashionedCalendarObject = Calendar.getInstance();
ZonedDateTime zdt
= ((GregorianCalendar) oldfashionedCalendarObject).toZonedDateTime();
System.out.println(zdt);
System.out.format("Month is %d or %s%n", zdt.getMonthValue(), zdt.getMonth());
Run Code Online (Sandbox Code Playgroud)
我刚才在我的时区跑步时的输出:
Run Code Online (Sandbox Code Playgroud)2021-03-17T23:18:47.761+01:00[Europe/Copenhagen] Month is 3 or MARCH
归档时间: |
|
查看次数: |
154814 次 |
最近记录: |