Java日历WEEK_OF_YEAR是否符合ISO-8601标准?

10
ISO-8601标准规定:“一年中的第一周是包含该年第一个星期四的那个星期(因此,始终包含1月4日)。”这意味着一年的第一周不是包含1月1日的那个星期,而是第一个包含新年至少四天的星期。
根据这个规定,2016年1月11日星期一是第二周。这里是2016年每周的列表。 Ubuntu在其时间小部件中反映了这一点:

enter image description here

而且 cal 命令也可以:

enter image description here

Oracle使用TO_CHAR的"iw"参数来支持它:

> select to_char(to_date('11/01/2016','dd/mm/yyyy'),'iw') weekno from dual;
> WEEKNO
    02

但是Java说2016年1月11日星期一是第三周

Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
System.out.println(c.get(Calendar.WEEK_OF_YEAR));

Output:
Mon Jan 11 09:02:35 VET 2016
3

Java认为一年的第一周是包含1月1日的那个周。

- Java是否有使用符合ISO-8601标准的周编号的方法?


1
这是与地区有关的。例如,将默认的“Locale”设置为“Locale.UK”可以得到正确的第二周。 - Harald K
但那会改变除了周数以外的其他东西! - Tulains Córdova
是的,请看下面我的答案,有更好的方法。 :-) - Harald K
2个回答

10

正如我在评论中提到的,默认行为是与所在地区相关的。某些地区可能会显示3,而另一些则会显示2。

幸运的是,你可以为特定的 Calendar 指定在一年中必须存在的第一周的天数。就像你上面写的那样,在 ISO 8601 中,这个数字是 4,因此以下代码应该可以工作:

Calendar c = Calendar.getInstance();
c.setMinimalDaysInFirstWeek(4); // For ISO 8601
System.out.println(c.getTime());
System.out.println(c.get(Calendar.WEEK_OF_YEAR));

无论语言环境如何,这应该使输出正确。

测试输出:

Mon Jan 11 14:54:22 CET 2016
2

4

简述

myZonedDateTime.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) 

…并且…

myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR )

避免使用旧版日期时间类

正如haraldK所述的正确答案Calendar类对于一周的定义因语言环境而异。虽然出于好意,但这很容易引起混淆。

您应该避免使用Calendar和相关类,例如Date,它们已经被新的java.time类所取代。

ISO 8601周

关于ISO 8601周,要明确它的定义:

  • 第一天是星期一,到星期日为止。
  • 基于周的一年中的第一周包括日历年的第一个星期四。
  • 一年按周计算有52或53周。
  • 日历年的前几天和后几天可能属于上一个或下一个基于周的年份。

java.time

java.time类包含了有限的支持ISO 8601标准周的方法。在各种类中调用get方法,例如LocalDateZonedDateTime。传递在IsoFields类中作为常量的TemporalField实现。

int week = myZonedDateTime.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ;
int weekBasedYear = myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR ) ;

ThreeTen-Extra

更好的是,将ThreeTen-Extra库添加到您的项目中,以使用YearWeek类。

org.threeten.extra.YearWeek yw = YearWeek.from( myZonedDateTime ) ;

小心日历软件设置

不要假设周数的定义。确保该数字的来源与您具有相同的周定义,例如ISO 8601定义。

例如,macOS提供的日历应用程序默认使用“公历”日历的周定义。至于这意味着什么,我不知道,因为我找不到关于他们意图/定义的任何文档。对于ISO 8601周,必须更改默认设置


关于java.time

java.time框架内置于Java 8及更高版本。这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参见Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范为JSR 310

使用符合JDBC 4.2或更高版本的JDBC驱动程序,您可以直接与数据库交换java.time对象。不需要字符串或java.sql.*类。

如何获取java.time类?

ThreeTen-Extra 项目通过增加类来扩展java.time。该项目是java.time可能未来增加内容的试验场所。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuarter更多


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接