DateTimeFormatter
课程文档说明了当年的格式代码:
2004年; 2004年; 04 2004年的年代; 04...
年份:字母数决定了使用填充的最小字段宽度。如果字母数是2,则使用减少的两位数形式。对于打印,这将输出最右边的两位数字。对于解析,这将使用2000的基值进行解析,从而产生2000到2099(包括2000和2099)范围内的一年。如果字母数小于4(但不是2),则符号仅按负号年份输出,符合SignStyle.NORMAL。否则,如果超出了焊盘宽度,则会根据SignStyle.EXCEEDS_PAD输出符号。
没有提及“时代”。
那么这两个代码之间有什么区别,u
与y
,year
与year-of-era
?
在使用Java中的日期时,我应该何时使用此模式uuuu-MM-dd
以及何时使用yyyy-MM-dd
?
似乎知道的人使用uuuu
编写的示例代码,但为什么?
遗留SimpleDateFormat
等其他格式化类只有yyyy
,所以我很困惑为什么java.time为“年代”带来了这个uuuu
。
答案 0 :(得分:18)
在java.time
- 包的范围内,我们可以说:
使用更安全" u"而不是" y" 因为DateTimeFormatter
否则会坚持与#34; y" (=年代)。所以使用" u"将在严格的格式化/解析中避免一些可能的意外异常。另见SO-post。另一个小问题是" u" -symbol与" y"正在打印/解析负的格里高利年(远在过去)。
否则我们可以清楚地说明使用" u"而不是" y"打破了Java编程中的长期习惯。直觉上也不清楚" u"表示任何一年,因为a)英文单词的第一个字母"年"与此符号不一致b)SimpleDateFormat
使用了" u"从Java-7(ISO-day-number-of-week)开始用于不同的目的。确保混乱 - 永远?
我们还应该看到,如果我们考虑历史性日期,在ISO的背景下使用时代(符号" G")通常是危险的。如果" G"用于" u"然后两个字段彼此无关。如果" G"用于" y"然后格式化程序很满意,但是当历史日期要求不同的日历和日期处理时,格式化程序仍然使用了预感格里历历。
在开发和集成JSR-310(java.time
- 软件包)时,设计人员决定使用CLDR / LDML-spec作为DateTimeFormatter
中模式符号的基础。符号" u"已经在CLDR中定义为预感格里高利年,所以这个意思被新的即将到来的JSR-310采用(但由于向后兼容的原因,不适用于SimpleDateFormat
。
然而,这个跟随CLDR的决定并不十分一致,因为JSR-310还引入了新的模式符号,这些符号在CLDR中并不存在,但也参见了这个旧的CLDR-ticket 。建议的符号" I"由CLDR更改为" VV"最后被JSR-310取代,包括new symbols "x" and "X"。但是" n"和" N"仍然不存在于CLDR中,并且由于这个旧票据已关闭,所以如果CLDR在JSR-310的意义上支持它,则根本不清楚。此外,机票没有提到符号" p" (JSR-310中的填充指令,但未在CLDR中定义)。 所以我们在不同的库和语言之间的模式定义之间仍然没有完全一致。
关于" y":我们也不应忽视CLDR将这个年代与至少某种混合的朱利安/格里高利年联系在一起而不是作为JSR的温柔格里高利年的事实-310(留下负面年份的奇怪之处)。因此,CLDR和JSR-310之间也没有完美的协议。
答案 1 :(得分:14)
在df2
的javadoc部分Patterns for Formatting and Parsing中,它列出了以下3个相关符号:
DateTimeFormatter
仅作比较,这些其他符号很容易理解:
Symbol Meaning Presentation Examples
------ ------- ------------ -------
G era text AD; Anno Domini; A
u year year 2004; 04
y year-of-era year 2004; 04
D day-of-year number 189
d day-of-month number 10
E day-of-week text Tue; Tuesday; T
,day-of-year
和day-of-month
显然是给定范围内的天(年,月,周)。
因此,day-of-week
表示给定范围(时代)内的年,正上方year-of-era
显示的示例值为era
(另一个值当然是AD
)。
BC
是已签署的年,其中year
年为0
,年1 BC
为-1
,依此类推
说明:什么时候是Julius Caesar assassinated?
2 BC
)MMMM d, y GG
)区别当然只有在年份为零或为负时才有意义,而且由于这种情况很少见,大多数人都不关心,即使他们应该这样做。
结论:如果您使用MMMM d, u
,则还应使用y
。由于很少使用G
,因此正确的年份符号为G
,而非u
,否则非正年将显示不正确。
防御性编程是一种防御性设计,旨在确保在不可预见的情况下的软件的持续功能。
请注意,y
与SimpleDateFormat
一致:
DateTimeFormatter
负面年份一直是个问题,他们现在通过添加Letter Date or Time Component Presentation Examples
------ ---------------------- ------------ --------
G Era designator Text AD
y Year Year 1996; 96
来修复它。
答案 2 :(得分:1)
yyyy
还是uuuu
(还是使用yy
或uu
都一样) 2位数字的年份)。另外两个答案已经说明u
和y
的工作原理非常好,但是我仍然感觉缺少某些东西,因此我贡献了一些基于观点的答案。
假设您不希望在1 CE之前格式化,那么最好的办法就是检查一下这个假设,并做出适当的反应以防万一。例如,根据情况和要求,您可能会打印错误消息或引发异常。一种非常软的故障路径可能是在这种情况下使用带有y
(时代)和G
(时代)的模式,以及带有u
或y
的模式。在正常的当前时代情况下。请注意,如果您要打印当前日期或程序的编译日期,则可以确保它处于普通时代,并且可以选择跳过检查。
在许多(大多数?)情况下,解析也意味着验证意味着您无法保证输入字符串的外观。通常,它来自用户或另一个系统。例如:日期字符串为2018-09-29。在此情况下,uuuu
和yyyy
之间的选择应取决于在字符串包含0或负数的年份(例如0000-08-17
或-012-11-13
)时要发生的情况。假设这将是一个错误,直接的答案是:使用yyyy
以便在这种情况下引发异常。更好:使用uuuu
并在解析后对解析日期进行范围检查。后一种方法既可以进行更好的验证,又可以在发生验证错误时提供更好的错误消息。
特殊情况(已由Meno Hochschild提及):如果您的格式化程序使用严格的解析器样式并且包含y
而没有G
,则解析将总是会失败,因为严格来说是没有时代就是模棱两可的时代:1950年可能意味着1950年或1950年(公元前1950年)。因此,在这种情况下,您需要u
(或提供默认时代,可以通过DateTimeFormatterBuilder
来实现)。
对日期(特别是年份)进行显式范围检查要比依靠uuuu
和yyyy
之间的选择来捕获非常早的年份更好。