【问题标题】:Inconsistency in java date library for week of year一年中的一周的Java日期库中的不一致
【发布时间】:2018-10-23 11:41:17
【问题描述】:

根据https://en.wikipedia.org/wiki/ISO_8601#Week_dates,工作日从星期一开始。但是,从 Java 中,如果您尝试以两种不同的方式提取周数,如果日期是星期日,则会出现两个不同的输出。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class TestDate {
    public static void main(String[] args) throws ParseException {
        final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        final SimpleDateFormat weekFormatter = new SimpleDateFormat("ww");
        String date = "2018-10-21";
        System.out.println(weekFormatter.format(formatter.parse(date)));
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(formatter.parse(date));
        System.out.println(calendar.get(Calendar.WEEK_OF_YEAR));
    }
}

输出:

43
42

这是不一致吗?

这只是我为重现问题而编写的一个测试程序,我注意到 Hive 中的问题,如下所示:

0: jdbc:hive2://zk0-something> select from_unixtime(t, 'ww'), weekofyear(from_unixtime(t, 'yyyy-MM-dd')) from (select 1540122033 as t) a;
+------+------+--+
| _c0  | _c1  |
+------+------+--+
| 43   | 42   |
+------+------+--+
1 row selected (0.388 seconds)
0: jdbc:hive2://zk0-something>

【问题讨论】:

  • 不要怪SimpleDateFormat,要怪你的默认语言环境将星期日定义为一周的第一天。如果您想要“正确”的值(嗯,取决于观点),然后使用将星期一定义为一周第一天的国家/地区的语言环境,例如法国 (new SimpleDateFormat("ww", Locale.FRANCE))
  • 我建议你避免使用SimpleDateFormat 类。它不仅过时了,而且出了名的麻烦。今天我们在java.time, the modern Java date and time API 的表现要好得多。

标签: java hive simpledateformat datetime-format week-number


【解决方案1】:

java.time

    String date = "2018-10-21";
    LocalDate ld = LocalDate.parse(date);
    int weekOfYear = ld.get(WeekFields.ISO.weekOfYear());
    System.out.println(weekOfYear);

输出:

42

由于您对ISO 8601 规则for week numbers 感兴趣,请使用WeekFields.ISOLocalDate 获取与周相关的数据。如果您愿意,也可以使用formatter

    DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern("ww", Locale.FRANCE);
    System.out.println(ld.format(weekFormatter));

输出是一样的:

42

传递给DateTimeFormatter.ofPattern 的语言环境决定了周计划。如果我改为通过 Locale.US,我得到 43。

我建议您使用现代 Java 日期和时间 API java.time,并远离旧的日期时间类,如 SimpleDateFormatCalendar。旧的设计不佳,而现代的则更好用。

你的代码出了什么问题?

过时的 SimpleDateFormat 类和现代的 DateTimeFormatter 都从他们的语言环境中获取他们的周编号方案。如果没有为格式化程序指定语言环境,它将使用 JVM 的默认语言环境。因此,如果 JVM 具有美国语言环境,例如,格式化程序将在您的第一个示例中打印 43,因为在美国,今年 10 月 21 日星期日是第 43 周。如果语言环境是法语,它将打印 42,因为那天是周42 在法国。法国遵循 ISO 8601 标准,美国没有。

在您的示例中,将 Calendar 的第一天设置为星期一会导致周数为 42,如您所料。然而,情况并非总是如此。周数不仅由一周的第一天定义,而且由第 1 周的定义定义。来自您的链接:

一年中的第一周 ISO 最多可能有三天 实际上是在即将结束的公历年;如果他们是 周一、周二和周三。同样,一年中的最后一周 ISO 实际上在公历中最多可能有三天 开始的年份;如果是周五、周六和周日。这 每个 ISO 周的星期四始终是公历年 用 ISO 周编号年份表示。

美国对第 1 周的定义不同:在美国,1 月 1 日总是在第 1 周。因此,如果您的 Calendar 是使用美国语言环境创建的,则将其一周的第一天设置为星期一是不够的make 遵循 ISO 8601 规则。不过巧合的是,2018 年的周数是一致的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    • 1970-01-01
    相关资源
    最近更新 更多