JSR-310中两个不同的基于周的年定义的动机是什么?

时间:2014-04-04 22:58:53

标签: java java-8 iso8601 java-time

这些是包java.time.temporal中的两个字段:

IsoFields.WEEK_BASED_YEAR

WeekFields.ISO.weekBasedYear()

ISO-8601定义了除其他两种日期之外的所谓周日期,即通常的日历日期(包括年,月和日)和顺序日期(包括年和日) - 年)。 以yYYY格式定义周期日 - ' W' ww-e 。 w代表一周的年份,e代表数字ISO-星期几。 Y代表以周为基础的年份,与日历年相同,但在日历年的开始或结束时除外,因为基于周的年份与最终可能在上一年开始的周周期相关联。有两条规则对于理解星期日的形成非常重要:

  1. 周总是从星期一开始。
  2. 日历年的第一周是至少包含四天的一周。
  3. 乍一看,两个JSR-310字段看起来都是相同的,因为ISO-8601只提到了一种基于周的年份。但是等一下,惊喜。我们来考虑以下代码示例:

    LocalDate date1 = 
      LocalDate.of(2000, 2, 29).with(IsoFields.WEEK_BASED_YEAR, 2014);
    System.out.println("IsoFields-Test: " + date1); // output: 2014-03-01
    
    LocalDate date2 = 
      LocalDate.of(2000, 2, 29).with(WeekFields.ISO.weekBasedYear(), 2014);
    System.out.println("WeekFields-Test: " + date2); // output: 2014-02-25
    

    虽然我非常了解第二种变化,但我真的很惊讶看到使用"官方"的第一次约会的不同结果。 ISO-8601-classname中的引用。解释计算结果:

    日期2000-02-29对应于ISO-weekdate-notation的2000-W09-2,而2014-02-25对应于2014-W09-2 保留了一周的年份和日期 - 的周即可。到目前为止很好。较小字段的这种保留特性类似于如何更改日历年的规则(在大多数情况下应该保持日历日期中的月份和日期不变)。

    但结果2014-03-01是什么?这里算法简单地将相应的周日添加了四天,以便考虑字段中的差异"日期" (29对25)。我没有找到此行为的任何来源或官方文档。有谁知道我们在哪里可以找到这两个领域之间差异的理由?有关算法行为的任何文档吗?

    更新

    现在我尝试使用此表达式测试新API的自我一致性,以便找出更好地支持哪两个字段:

    System.out.println(
      "14 week-based-years later = "
      + LocalDate.of(2000, 2, 29).plus(14, IsoFields.WEEK_BASED_YEARS));
    

    输出是2014-03-01,类似于IsoFields.WEEK_BASED_YEAR描述的情况,尽管我仍然发现2014-02-25(= 2014-W09-2)的结果更合乎逻辑。由于此类时间单位也在类IsoFields中找到,因此行为在类IsoFields中是自洽的。看起来像一个没有文档记录和非直观的功能"。

    我使用的是版本: java.runtime.version = 1.8.0-b132

    更多测试:

    LocalDate d = LocalDate.of(2014, 3, 1); // 2014-W09-6
    System.out.println(
      "week-of-year in 2014-03-01: " 
      + d.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
    System.out.println(
      "day-of-week in 2014-03-01: " 
      + d.get(ChronoField.DAY_OF_WEEK));
    
    LocalDate later = d.plus(14, IsoFields.WEEK_BASED_YEARS); // 2028-03-02 = 2028-W09-4
    System.out.println(
      "14 week-based-years later = " 
      + later);
    System.out.println(
      "week-of-year in " + later + ": " 
      + later.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
    System.out.println(
      "day-of-week in " + later + ": " 
      + later.get(ChronoField.DAY_OF_WEEK));
    

    输出:

    week-of-year in 2014-03-01: 9
    day-of-week in 2014-03-01: 6
    14 week-based-years later = 2028-03-02
    week-of-year in 2028-03-02: 9
    day-of-week in 2028-03-02: 4
    

    我不承认任何明确的规则。在添加14周的年份时,不保留星期几,也不保留日期。 所以这是一个额外的问题:IsoFields.WEEK_BASED_YEARS背后的规则是什么?也许JSR-310团队可以启发我们?

1 个答案:

答案 0 :(得分:8)

这是IsoFields中的一个错误,因为这种方法未经测试(对不起)。正确实施后,IsoFieldsWeekFields.ISO之间应该存在非常小的可观察差异。

请参阅bug report和补丁,这些补丁最终将通过系统运行并修复。

注意,测试显示获得该字段很好,该错误仅影响with的{​​{1}} / adjustInto方法。单位WEEK_BASED_YEAR会受到影响,因为通过重复使用损坏的WEEK_BASED_YEARS在内部实施添加。

更新2014-08-28:这是14个java.time错误之一fixed in 8u20