代码之家  ›  专栏  ›  技术社区  ›  Niels Basjes

DateTimeFormatter基于周的年差异

  •  2
  • Niels Basjes  · 技术社区  · 7 年前

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

    DateTimeFormatter .

    注:我看到这个问题: Java Time's week-of-week-based-year pattern parsing with 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
    

    .appendValue(IsoFields.WEEK_BASED_YEAR) .ofPattern("YYYY") 是不同的。

    据称,这与本地化有关(可以清楚地看出,这是 toString() ).

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

    1. 因此,“以周为基础的年份”因地区而异。然而,我不明白的是,显然在某些地区,周基准年总是与“正常”年相同。为什么?

    2. YYYY 已映射到ISO-8601定义,而不是(非常令人困惑!)本地化形式。

    3. 我在哪里可以找到这方面的适当文档?至少可以说,来自甲骨文的明显的“官方”文档是模糊的。 答复 :我发现了更广泛的文档 DateTimeFormatterBuilder .

    1 回复  |  直到 7 年前
        1
  •  6
  •   user7605325 user7605325    7 年前

    这个 基于周的年份 javadoc ,取决于两件事:一周的第一天是多少,以及第一周的最少天数。

    ISO标准将星期一定义为一周的第一天,第一周至少4天:

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

    ( WeekFields.ISO.weekBasedYear() IsoFields.WEEK_BASED_YEAR 具有 minor differences regarding another calendar systems

    nd公司 2009年,星期五。检查 javadoc for the week-based-year field :

    2008年1月4日结束 2009年(这是从周一开始的第一周,2009年至少有4天),因此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 locale (English (Malta))

    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
    

    从1月4日开始的第一周是2009年至少有4天的周日 至10 en_MT 地区,1月2日 nd公司 2009属于 2008

    ar_SA locale (Arabic (Saudi-Arabia)) ,一周从周六开始,第一周的最小天数为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日结束 nd公司 基于周的年份 2009年 ar_SA公司 区域设置也是2009年(与我使用的值相同) IsoFields 尽管周的定义与ISO完全不同 ).


    虽然 等场。基于周的年 YYYY WeekFields公司 实例对应于格式化程序中设置的区域设置(或JVM默认区域设置,如果未设置)。

    根据每个区域设置的定义(一周中的第一天和第一周中的最少天数),该 基于周的年份 YYYY年 )可能与ISO字段的值相同(或不同)。

    javadoc

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


    图案字母 java.time were based on CLDR Unicode Common Locale Data Repository ). This link about Week based patterns

    Y表示的年份通常始于 场所 s一周的第一天,结束于一周的最后一天

    Y 本地化,以及 Stephen Colebourne's comment 如下:

    CLDR的全部目的是本地化,“Y”模式字母是本地化的。虽然我理解人们对总是使用ISO规则操作的模式字母的渴望,但它并不存在,让CLDR添加它是很难做到的。(Java正在密切关注CLDR)


    Locale.FRENCH 作为一个 WeekFields.ISO.equals(WeekFields.of(Locale.FRENCH)) 退货 true ). 唯一的问题是,区域设置也会影响其他字段(如果您有月份或星期几的名称,例如 MMM EEE ,以及任何其他区域设置敏感数据)。

    推荐文章