Java 纪年和基于周的年份之间的差异?

Java 纪年和基于周的年份之间的差异?,java,date,datetime,java-8,java-time,Java,Date,Datetime,Java 8,Java Time,Java 8的类有一个方法,of模式(字符串模式),它允许您从a-z,a-z字母的字符串中定义格式。这些示例没有阐明纪年y和基于周的年份y之间的区别。这是什么 Symbol Meaning Presentation Examples ------ ------- ------------ ------- y year-of-era year

Java 8的类有一个方法,
of模式(字符串模式)
,它允许您从
a-z
a-z
字母的字符串中定义格式。这些示例没有阐明纪年
y
和基于周的年份
y
之间的区别。这是什么

Symbol  Meaning                     Presentation      Examples
------  -------                     ------------      -------
 y       year-of-era                 year              2004; 04
 Y       week-based-year             year              1996; 96
这是“年-周”样式日期的年值,如2006-W52。 如果所述周跨越年份边界,则可能会偏离纪年值+1或-1


请参见每个字段都记录在一个“字段”类中,例如
ChronoField
WeekFields
IsoFields

“纪年”字段记录在中

“基于周的年”字段记录在。

基于周的年 一周只属于一年的概念。例如:

LocalDate.parse("2019-12-29").format(DateTimeFormatter.ofPattern("M/d/Y")) 
---> "12/29/2020"`
LocalDate.parse("2019-12-29").format(DateTimeFormatter.ofPattern("M/d/y"))
---> "12/29/2019"
纪年 常用的一年,1/1总是一年中的第一天。例如:

LocalDate.parse("2019-12-29").format(DateTimeFormatter.ofPattern("M/d/Y")) 
---> "12/29/2020"`
LocalDate.parse("2019-12-29").format(DateTimeFormatter.ofPattern("M/d/y"))
---> "12/29/2019"

Y
建议我们要根据ISO 8601周编号年份设置给定日期的格式。根据,第01周的定义为

一年中第一个星期四所在的一周(正式ISO定义)

因此

一年中的第一个ISO周最多可以有三天,实际上是在公历年的最后一天

我们考虑“2019-12—30”日期,这是一个星期一。

如果我们看看那一周,我们有2019年12月30日和31日是星期一和星期二;2020年1月1日至4日为周三、周四、周五和周六。如你所见,本周跨越(我们使用的日历系统)2019年和公历2020年。如果我们应用上述基于周的年份01周的定义,我们可以看到2019年12月30日至2020年5月1日之间的一周是基于周的2020年01周(ISO标准规定为星期一)。因此,如果我们想用dateTimeFormatter
'YYYY-MM-dd'
解析“2019-12-30”,正确的结果是
'2020-12-30'
。但是,如果使用“yyyy-MM-dd”,最终结果将是“2019-12-30”

System.out.println(LocalDate.parse("2019-12-30").format(DateTimeFormatter.ofPattern("YYYY-MM-dd"))); // output "2020-12-30"
System.out.println(LocalDate.parse("2019-12-30").format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); // output "2019-12-30"
我认为Java实现可能存在一个潜在的问题。如果我们考虑上面给出的山姆贝瑞,“2019-1229”的输出与定义的基于周的年不一致。原因是“2019-12-29”是一个周日。如果我们应用上面维基百科的定义,“2019-12-29”应该被解析为“2019-12-29”,即使给定
'YYYY-MM-dd'
。这是因为按照ISO标准,01周的开始是周一而不是周日。如果我们向上看,我们可以看到2020年第1周从“2019-12-30”开始。我怀疑这可能是因为API的实施者认为一周的开始是星期日,这是不符合ISO标准的。 更新

关于Java实现错误的怀疑。这不是实现错误。谢谢你在下面的评论。在格式化过程中,对01周开始的定义存在细微的依赖,这会受到
区域设置的影响。例如,如果区域设置为欧洲,则一周的开始时间为周一,这与ISO标准一致。因此

System.out.println(LocalDate.of(2019, Month.DECEMBER, 29).format(DateTimeFormatter.ofPattern("YYYY-MM-dd", Locale.FRANCE)));
具有输出
2019-12-29
。然而,在美国,一周的开始被认为是星期天。因此

System.out.println(LocalDate.of(2019, Month.DECEMBER, 29).format(DateTimeFormatter.ofPattern("YYYY-MM-dd", Locale.US)));

已经输出了
2020-12-29

从其他答案中,我没有发现它非常清晰,所以请允许我试一试

基于周的年份或有时简称周年是相关周数所属的年份。因此,例如,第1周的所有日期都具有相同的基于周的年份,即使其中一些周位于上一个日历年中。或者反过来说,假设一年中的第52周一直延伸到下一年(这在某些情况下是可能的,而不是所有的周编号方案),那么该周的每一天都将旧日历年作为其基于周的年份。在我居住的地方,2020年的第一周是从12月30日星期一到1月5日星期日(含)。因此,截至12月29日,日历年和基于周的年份商定为2019年。12月30日和31日是以周为基础的2020年,但当然仍然是2019日历年。从1月1日起,再次商定日历年和基于周的年份,现在是2020年

因此,基于周的年份除了与周数一起使用外,几乎没有任何有意义的用途

它变得有点复杂(我认为其他答案不太清楚)的地方是周编号取决于区域设置,因此基于周的年份也是如此。
DateTimeFormatter
有一个区域设置,并使用此区域设置来选择周编号方案,以便在为给定日期确定基于周的年份时使用

为了说明这一点,我将2022年新年前后的10天安排在三个不同的地点:

  • 我想展示ISO 8601周,并选择法国作为遵循ISO的国家
  • 美国周从星期天开始
  • 在许多阿拉伯国家,新的一周从周六开始;我以摩洛哥为例
  • 我的代码:

        DateTimeFormatter iso
                = DateTimeFormatter.ofPattern("Y w E", Locale.FRANCE);
        DateTimeFormatter us
                = DateTimeFormatter.ofPattern("Y w E", Locale.US);
        DateTimeFormatter arabic = DateTimeFormatter
                .ofPattern("Y w E", Locale.forLanguageTag("ar-MA"));
        
        System.out.println("                ISO           US          Morocco");
        LocalDate d = LocalDate.of(2021, Month.DECEMBER, 25);
        for (int i = 0; i < 10; i++) {
            System.out.format("%-10s  %-12s  %-11s  %s%n",
                    d, d.format(iso), d.format(us), d.format(arabic));
            d = d.plusDays(1);
        }
    
    观察结果

    • 在所有三列中,周-年在第1周开始的同一天更改
    • 这一变化发生在三个地区的不同日期:
    • 在美国,以周为基础的2022年从2021年圣斯蒂芬节开始
    • 在摩洛哥,以周为基础的2022年恰巧开始于2022日历年的第一天,但这只是因为2022年那天是星期六,因此是一周的第一天
    • 在ISO 8601中,以周为基础的2022年直到1月3日才开始
    为完整起见:定义周编号分为两部分:

  • 新的一周从哪一天开始
  • 一周必须包括多少天的新年才能成为第一周。这称为第一周的最小天数
  • 在美国和摩洛哥,第1周被定义为包含1月1日的一周。换句话说,一周只需要在新的一年中至少有一天就可以成为新的一年的第一周。事实并非如此
    DateTimeFormatter.ofPattern( "dd/MM/uuuu" ) ;
    
    LocalDate localDate = LocalDate.parse( "30/12/2019" ) ;
    
    String output = localDate.format( DateTimeFormatter.ISO_WEEK_DATE ) ;
    
    LocalDate localDate = 
        LocalDate.parse( 
            "2020-W01-1" , 
            DateTimeFormatter.ISO_WEEK_DATE
        )
    ;
    
    LocalDate localDate = LocalDate.of( 2019 , Month.DECEMBER , 30 ) ;  // Monday 2019-12-30. Its week-based year is 2020. 
    YearWeek yearWeek = YearWeek.from( localDate ) ;
    String wFormatted = yearWeek.toString() ;
    
    LocalDate localDate = yearWeek.atDay( DayOfWeek.MONDAY ) ;