Nie*_*jes 2 java datetime dayofweek java-8 java-time
我正在将我的应用程序从Joda-Time迁移到Java 8 java.time.
我遇到的一件事是使用图案中的模式打印基于周的一年DateTimeFormatter.
注意:我已经看到了这个问题: Java Time使用DateTimeFormatter解析基于星期的周模式
根据文件
y year-of-era year 2004; 04
Y week-based-year year 1996; 96
Run Code Online (Sandbox Code Playgroud)
然而,当我尝试这两个时,似乎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));
}
Run Code Online (Sandbox Code Playgroud)
输出:
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
Run Code Online (Sandbox Code Playgroud)
看看它重要的年份(如2000年,2005年,2009年和2016年)的产量.appendValue(IsoFields.WEEK_BASED_YEAR)和.ofPattern("YYYY")不同.
在Java的时间的基于周的星期年图案DateTimeFormatter分析中指出,这与本地化做的(如可以清楚地看到作为一个差toString()的DateTimeFormatter).
现在有一些我不理解/不需要的东西:
因此,"以周为基础的年份"因Locale而异,很好.然而我不明白,显然在一些Locales中,周基年总是与'正常'年相同.这是为什么?
为什么没有YYYY映射到ISO-8601定义的解析而不是(非常混乱!)本地化形式.
我在哪里可以找到适当的文件?甲骨文的明显"官方"文件至少可以说含糊不清. 答:我使用DateTimeFormatterBuilder找到了更广泛的文档 .
小智 6
在基于为期一周的年场,根据的Javadoc,取决于两两件事:什么是一周的第一天,天在第一周的最低数量.
ISO标准将星期一定义为一周的第一天,并在第一周定义至少4天:
System.out.println(WeekFields.ISO.getFirstDayOfWeek()); // Monday
System.out.println(WeekFields.ISO.getMinimalDaysInFirstWeek()); // 4
Run Code Online (Sandbox Code Playgroud)
(WeekFields.ISO.weekBasedYear()等同于IsoFields.WEEK_BASED_YEAR与关于另一个日历系统的细微差别)
考虑到,例如,1月2日ND 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
Run Code Online (Sandbox Code Playgroud)
但是如果我考虑一个localeWeekFields实例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
Run Code Online (Sandbox Code Playgroud)
从星期日开始并且在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
Run Code Online (Sandbox Code Playgroud)
对于这个区域,本周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也是本地化的 - 正如Stephen Colebourne在下面的评论所述:
CLDR的整个目的是本地化,所以是的,"Y"模式字母是本地化的.虽然我理解对始终使用ISO规则运行的模式字母的需求,但它不存在并且让CLDR添加它将很难不可能.(Java密切关注CLDR)
我的结论是,如果您想要ISO周字段,请不要使用本地化模式.或者,作为一个 - 不理想,相当丑陋 - 的解决方法,使用与ISO的周定义相匹配的语言环境(在我的JVM中,Locale.FRENCH做诀窍,作为WeekFields.ISO.equals(WeekFields.of(Locale.FRENCH))返回true).唯一的问题是语言环境也会影响其他字段(如果您有月份或星期几的名称,例如MMM或EEE,以及任何其他区域设置敏感数据).
| 归档时间: |
|
| 查看次数: |
848 次 |
| 最近记录: |