Java中的`DateTimeFormatter`格式化代码中的`uuuu`与`yyyy`?

时间:2016-12-16 04:48:50

标签: date parsing datetime date-formatting java-time

DateTimeFormatter课程文档说明了当年的格式代码:

  2004年; 2004年; 04

     2004年的年代; 04

     

...

     

年份:字母数决定了使用填充的最小字段宽度。如果字母数是2,则使用减少的两位数形式。对于打印,这将输出最右边的两位数字。对于解析,这将使用2000的基值进行解析,从而产生2000到2099(包括2000和2099)范围内的一年。如果字母数小于4(但不是2),则符号仅按负号年份输出,符合SignStyle.NORMAL。否则,如果超出了焊盘宽度,则会根据SignStyle.EXCEEDS_PAD输出符号。

没有提及“时代”。

那么这两个代码之间有什么区别,uyyearyear-of-era

在使用Java中的日期时,我应该何时使用此模式uuuu-MM-dd以及何时使用yyyy-MM-dd

似乎知道的人使用uuuu编写的示例代码,但为什么?

遗留SimpleDateFormat等其他格式化类只有yyyy,所以我很困惑为什么java.time为“年代”带来了这个uuuu

3 个答案:

答案 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-yearday-of-month显然是给定范围内的(年,月,周)。

因此,day-of-week表示给定范围(时代)内的,正上方year-of-era显示的示例值为era(另一个值当然是AD)。

BC已签署的年,其中year年为0,年1 BC-1,依此类推

说明:什么时候是Julius Caesar assassinated

  • 公元前44年3月15日(使用模式2 BC
  • 3月15日-43(使用模式MMMM d, y GG

区别当然只有在年份为零或为负时才有意义,而且由于这种情况很少见,大多数人都不关心,即使他们应该这样做。

结论:如果您使用MMMM d, u,则还应使用y。由于很少使用G,因此正确的年份符号为G,而非u,否则非正年将显示不正确。

这称为defensive programming

  

防御性编程是一种防御性设计,旨在确保在不可预见的情况下软件的持续功能

请注意,ySimpleDateFormat一致:

DateTimeFormatter

负面年份一直是个问题,他们现在通过添加Letter Date or Time Component Presentation Examples ------ ---------------------- ------------ -------- G Era designator Text AD y Year Year 1996; 96 来修复它。

答案 2 :(得分:1)

长话短说

  1. 对于99%的目的,您都可以扔硬币,无论您使用yyyy还是uuuu(还是使用yyuu都一样) 2位数字的年份)。
  2. 这取决于您想要在1 CE(1 AD)之前一年发生的情况。关键是,在99%的计划中,这样的一年将永远不会发生。

另外两个答案已经说明uy的工作原理非常好,但是我仍然感觉缺少某些东西,因此我贡献了一些基于观点的答案。

用于格式化

假设您不希望在1 CE之前格式化,那么最好的办法就是检查一下这个假设,并做出适当的反应以防万一。例如,根据情况和要求,您可能会打印错误消息或引发异常。一种非常软的故障路径可能是在这种情况下使用带有y(时代)和G(时代)的模式,以及带有uy的模式。在正常的当前时代情况下。请注意,如果您要打印当前日期或程序的编译日期,则可以确保它处于普通时代,并且可以选择跳过检查。

用于解析

在许多(大多数?)情况下,解析也意味着验证意味着您无法保证输入字符串的外观。通常,它来自用户或另一个系统。例如:日期字符串为2018-09-29。在此情况下,uuuuyyyy之间的选择应取决于在字符串包含0或负数的年份(例如0000-08-17-012-11-13)时要发生的情况。假设这将是一个错误,直接的答案是:使用yyyy以便在这种情况下引发异常。更好:使用uuuu并在解析后对解析日期进行范围检查。后一种方法既可以进行更好的验证,又可以在发生验证错误时提供更好的错误消息。

特殊情况(已由Meno Hochschild提及):如果您的格式化程序使用严格的解析器样式并且包含y而没有G,则解析将总是会失败,因为严格来说是没有时代就是模棱两可的时代:1950年可能意味着1950年或1950年(公元前1950年)。因此,在这种情况下,您需要u(或提供默认时代,可以通过DateTimeFormatterBuilder来实现)。

长话短说

对日期(特别是年份)进行显式范围检查要比依靠uuuuyyyy之间的选择来捕获非常早的年份更好。