【问题标题】:Java Calendar WEEK_OF_YEAR not ISO-8601compliant?Java 日历 WEEK_OF_YEAR 不符合 ISO-8601 标准?
【发布时间】:2016-04-15 20:21:33
【问题描述】:

ISO-8601 标准规定

"一年的第一周是包含第一个星期四的那一周 年(因此,总是包含 1 月 4 日)。”

意思是一年的第一周不是包含 1 月 1 日的那一周,而是包含至少四天到新年的第一周。

根据那个星期一,2016 年 1 月 11 日是第 2 周。 Here is a list of week numbers for 2016.

Ubuntu 在其时间小部件中反映了这一点:

cal 命令也可以:

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 日星期一是第 3 周

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 的周编号?

【问题讨论】:

  • 这是特定于语言环境的。例如,将默认的 Locale 设置为 Locale.UK 会给出正确的星期,2。
  • 但这会改变周数之外的其他内容!
  • 是的,请参阅下面的答案以获得更好的方法。 :-)

标签: java date iso


【解决方案1】:

正如我在评论中指出的,默认行为 是特定于语言环境的。有些语言环境会给出 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

【讨论】:

    【解决方案2】:

    tl;博士

    myZonedDateTime.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) 
    

    ……和……

    myZonedDateTime.get( IsoFields.WEEK_BASED_YEAR )
    

    避免使用旧的日期时间类

    正如correct Answer by haraldK 解释的那样,Calendar 类对星期的定义因地区而异。虽然出于善意,但这令人困惑。

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

    ISO 8601 周

    至于ISO 8601 week,明确表示:

    • 第一天是星期一,一直持续到星期日。
    • 一周年的第一周包含日历年的第一个星期四。
    • 基于周的一年有 52 周或 53 周。
    • 日历年的第一天/最后几天可能出现在基于上一周/下一周的年份中。

    java.time

    java.time 类包括对ISO 8601 standard weeks 的有限支持。在LocalDateZonedDateTime 等各种类上调用get 方法。传递在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 的 Calendar app supplied by Apple 默认为“公历”日历定义的星期。至于这意味着什么,我不知道,因为我找不到任何关于他们的意图/定义的文档。对于 ISO 8601 周,您必须change a setting away from default


    关于java.time

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

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

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

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多