当前位置: 首页 > 面试题库 >

DateTimeFormatter基于周的年差异

利思源
2023-03-14
问题内容

我正在将应用程序从Joda-Time迁移到Java 8 java.time

我遇到的一件事是使用中的图案打印基于周的年份DateTimeFormatter

根据文档

y       year-of-era                 year              2004; 04
Y       week-based-year             year              1996; 96

但是,当我尝试这两个时,似乎Y总是会返回与相同的结果y

我的测试代码:

DateTimeFormatter yearF = DateTimeFormatter.ofPattern("yyyy").withZone(ZoneOffset.UTC);
DateTimeFormatter weekYearF = DateTimeFormatter.ofPattern("YYYY").withZone(ZoneOffset.UTC);

DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
    .appendValue(ChronoField.YEAR_OF_ERA)   .appendLiteral(" ") .append(yearF)
    .appendLiteral(" -- ")
    .appendValue(IsoFields.WEEK_BASED_YEAR) .appendLiteral(" ") .append(weekYearF)
    .toFormatter()
    .withZone(ZoneOffset.UTC);

System.out.println(dateTimeFormatter.toString());

ZonedDateTime dateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(946778645000L), ZoneOffset.UTC);
for (int i = 2000 ; i < 2020; i ++ ) {
    System.out.println(dateTime.withYear(i).format(dateTimeFormatter));
}

输出:

Value(YearOfEra)' '(Value(YearOfEra,4,19,EXCEEDS_PAD))' -- 'Value(WeekBasedYear)' '(Localized(WeekBasedYear,4,19,EXCEEDS_PAD))
2000 2000 -- 1999 2000
2001 2001 -- 2001 2001
2002 2002 -- 2002 2002
2003 2003 -- 2003 2003
2004 2004 -- 2004 2004
2005 2005 -- 2004 2005
2006 2006 -- 2006 2006
2007 2007 -- 2007 2007
2008 2008 -- 2008 2008
2009 2009 -- 2009 2009
2010 2010 -- 2009 2010
2011 2011 -- 2010 2011
2012 2012 -- 2012 2012
2013 2013 -- 2013 2013
2014 2014 -- 2014 2014
2015 2015 -- 2015 2015
2016 2016 -- 2015 2016
2017 2017 -- 2017 2017
2018 2018 -- 2018 2018
2019 2019 -- 2019 2019

从重要的年份(例如2000、2005、2009和2016)来看,.appendValue(IsoFields.WEEK_BASED_YEAR)和的输出.ofPattern("YYYY")是不同的。

在Java的时间与DateTimeFormatter基于周周的–一年模式分析中指出,这与本地化做的(如可以清楚地看到作为一个差toString()DateTimeFormatter)。

现在有几件事我不理解/需要:

  1. 因此,“以周为基础的年份”随语言环境的不同而不同。但是,我不明白的是,在某些语言环境中,以周为基准年显然总是与“正常”年份相同。这是为什么?

  2. 为什么没有将的解析YYYY映射到ISO-8601定义,而不是(非常混乱!)本地化形式。

  3. 在哪里可以找到适当的文档?至少可以说,Oracle提供的明显的“官方”文档含糊不清。 :我发现有关DateTimeFormatterBuilder的文档更多 。


问题答案:

基于为期一周的年
场,根据的Javadoc,取决于两两件事:什么是一周的第一天,天在第一周的最低数量。

ISO标准将星期一定义为一周中的第一天,并且在第一周中至少要有4天:

System.out.println(WeekFields.ISO.getFirstDayOfWeek()); // Monday
System.out.println(WeekFields.ISO.getMinimalDaysInFirstWeek()); // 4

WeekFields.ISO.weekBasedYear()相当于IsoFields.WEEK_BASED_YEAR,与其他日历系统略有不同)

考虑到,例如,1月2日第二 2009年,这是一个星期五。检查javadoc中 基于周的年份
字段

第一周(1)是从getFirstDayOfWeek()开始的一周,一年中至少有getMinimalDaysInFirstWeek()天。因此,第一周可能会在今年年初之前开始。

考虑到ISO定义(周从星期一开始,第一周的最少天数是4),第1周从2008 年12月29 日开始,到2009年1月4
日结束(这是从星期一开始的第一周,并且至少有4周2009年天),因此1月2日第二 2009年以来一个 基于为期一周的年
相当于2009年(与ISO的定义):

// January 2st 2009
LocalDate dt = LocalDate.of(2009, 1, 2);
System.out.println(dt.get(WeekFields.ISO.weekBasedYear())); // 2009
System.out.println(dt.get(WeekFields.ISO.weekOfWeekBasedYear())); // 1
// WeekFields.ISO and IsoFields are equivalent
System.out.println(dt.get(IsoFields.WEEK_BASED_YEAR)); // 2009
System.out.println(dt.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR)); // 1

但是,如果我考虑一个语言环境的WeekFields实例en_MT(英语(马耳他)),则一周的第一天为星期日,而第一周的最少天数为4:

WeekFields wf = WeekFields.of(new Locale("en", "MT"));
System.out.println(wf.getFirstDayOfWeek()); // Sunday
System.out.println(wf.getMinimalDaysInFirstWeek()); // 4
System.out.println(dt.get(wf.weekBasedYear())); // 2008
System.out.println(dt.get(wf.weekOfWeekBasedYear())); // 53

从周日开始并且在2009年至少有4天的第一周是1月4 日至10 日。因此,根据周定义en_MT的语言环境,1月2日第二 2009年属于 53
个星期
的的 基于为期一周的年 2008年。

现在,如果我使用ar_SA语言环境(阿拉伯语(沙特阿拉伯)),则该周从星期六开始,第一周的最少天数为1:

WeekFields wf = WeekFields.of(new Locale("ar", "SA"));
System.out.println(wf.getFirstDayOfWeek()); // Saturday
System.out.println(wf.getMinimalDaysInFirstWeek()); // 1
System.out.println(dt.get(wf.weekBasedYear())); // 2009
System.out.println(dt.get(wf.weekOfWeekBasedYear())); // 1

对于这个区域,本周1点开始在12月27日日 2008年结束在1月2日第二日(它的第一个星期是在一个周六开始,并具有至少1天,2009年)。因此,
基于周年 的1月2日第二,2009年ar_SA区域也是2009年(我已经使用了相同的值IsoFields
即使一周的定义是完全不同于ISO )。

IsoFields.WEEK_BASED_YEAR使用ISO的定义时,该模式YYYY将使用与WeekFields格式化程序中设置的语言环境相对应的实例(如果未设置,则为JVM默认语言环境)。

根据每个语言环境的定义(一周的第一天和第一周的最少天数),本地化模式()中 基于周的年份YYYY可能与ISO字段的值相同(或不相同)。

尽管一个星期可以在另一年开始或结束听起来很奇怪,但是javadoc说它是完全有效的:

一年的第一周和最后一周可能分别包含前一个日历年或下一个日历年的天。

模式字母java.time 基于CLDR(Unicode通用语言环境数据存储库)。关于基于周的模式的此链接说:

Y表示的年份通常从 语言环境 的一周的第一天开始,到一周的最后一天结束

无论如何,CLDR都是关于本地化的,Y本地化也是如此-正如斯蒂芬·科尔本(StephenColebourne)在下面[的评论中所述:

CLDR的全部目的是本地化,因此,是的,“
Y”模式字母已本地化。尽管我了解对希望始终使用ISO规则运行的模式字母的渴望,但它并不存在,要添加CLDR很难甚至不可能。(Java紧紧追随CLDR)

我的结论是,如果要使用ISO周字段,请不要使用本地化模式。或者,作为一种(不太理想,非常丑陋的)解决方法,请使用与ISO星期定义匹配的语言环境(在我的JVM中,请按提示进行Locale.FRENCH操作,作为WeekFields.ISO.equals(WeekFields.of(Locale.FRENCH))return
true)。唯一的问题是,语言环境还会影响其他字段(如果您有月或星期几的名称,例如MMMEEE,以及任何其他语言环境敏感数据)。



 类似资料:
  • 我正在将我的应用程序从Joda-Time迁移到Java8。 我遇到的一件事是使用中的模式打印以周为单位的年份。 注意:我已经看到这个问题:Java Time的week-of-week-based-year模式用DateTimeFormatter解析 根据文件 然而,当我尝试这两个时,似乎总是返回与相同的内容。 我的测试代码: 输出: 查看重要的年份(如2000、2005、2009和2016年),和

  • 我需要以-的格式输出当前日期,即使用ISO周日期,其中一周总是从周一开始,一年的第一周是1月份至少有四天的第一周(因此是1月份有第一个周四的一周)。 由于2015年12月31日为星期四,星期五至星期日,即2016年1月1日至3日,均属2015年第53周(“漫长的一年”),而2016年第一周于1月4日星期一开始。 从DateTimeFormatter规范中,我希望可以使用模式来实现这一点(是,是)。

  • 问题内容: Java 8的类有一个方法,,它使您可以从字符串A-z,a-z字母定义格式。这些例子并没有明确的区别y,今年的时代和Y,以星期为一年。它是什么? 问题答案: 与2006-W52一样,这是“年-周”样式日期的年值。如果有问题的一周跨越年份边界,则可能偏离年份值+1或-1。

  • 如果我使用像这样的模式来创建Java 8 DateTimeFormatter(例如,使用(我将只用于解析,而不是格式化),它将把所有两个字母的年份解释为20xx,例如解析一个字符串,如,将其解释为,这在我的情况下是错误的(应该是在1999年)。 在我的应用程序中,我试图解析OCR文档中的日期,例如,可能仍然是90年代的日期,因此,将日期解释为当前日期之前80年和之后20年的旧SimpleDateF

  • 问题内容: 这是包中的两个字段: IsoFields.WEEK_BASED_YEAR WeekFields.ISO.weekBasedYear() ISO-8601除了其他两种日期之外,还定义了所谓的星期日期,即通常的日历日期(由年,月和日组成)和顺序日期(由年和日组成) )。 周日期以YYYY-‘W’ww-e格式定义 。w代表星期,e代表数字ISO星期。Y代表以周为基础的年份,并且与日历年相同,

  • 问题内容: 我想计算用户输入的总日差 例如,当用户输入 和 现在,我正在使用此代码查找差异 总计的结果为6。但是问题是我不想包括周末(星期六和星期日)的日子 所以结果将是4 -—更新- 我有一个包含日期的表,该表的名称是假期 例如表格包含 因此,总天数为3,因为它没有计算假期日期 我该如何将输入中的日期等同于表中的日期? 问题答案: 很容易与我的最爱,和