【问题标题】:Calendar returns wrong Week of the year日历返回错误的一年中的一周
【发布时间】:2019-03-13 20:18:27
【问题描述】:

在将一周的第一天设置为星期日后,我想在 2018 年 9 月 10 日这一天作为一年中的第 42 周。我仍然从下面的 sn-p 得到输出为 41

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

我错过了什么吗?

背景:我们的一周开始时间是可变的。我们的配置能够让用户决定一周的第一天。

【问题讨论】:

  • 是什么让你期待 42??!! 1 月 2 日星期二是 40 周前。去年 12 月 24 日到 30 日这一周应该是今年的第 1 周吗?
  • Calendar 类早已过时,坦率地说,使用起来有些复杂。我推荐java.time, the modern Java date and time API。我并不是说以下内容很简单,但我发现它更清晰,更不容易出错:LocalDate.now(yourTimeZone).get(WeekFields.SUNDAY_START.weekOfWeekBasedYear())。今天,2018 年 10 月 9 日,它给出了 41,但我认为这是正确的,并且同意 Week Numbers 2018 in United States
  • 但是如果我的一周开始时间可以变化呢?有人可能会把它保留为星期一,那我该怎么办? #verynewtojava
  • 周编号需要的不仅仅是知道一周的第一天。在 ISO 中,一年中的第一周是新年至少有四天的那一周,在美国只需要一天。另外,说真的,我怀疑任何用户都想使用没有其他人使用的本土编号方案。你认为他们会吗?
  • 他们很少会使用它.. 但是我们的配置有能力让他们这样做.. 无论如何看起来我会尝试根据一年的第一天做一些模运算和一年中的第几天来解决这个问题

标签: java calendar dayofweek


【解决方案1】:

对不起,如果我太坚持了。我仍然认为您应该将计算留给自定义 WeekFields 对象。如果我正确理解了您的评论,您希望:

    final int daysPerWeek = DayOfWeek.values().length; // A wordy way of writing 7 :-)
    WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, daysPerWeek);
    int customWeekNumber = date.get(customWeekFields.weekOfWeekBasedYear());

为了测试这是否与您已经在做的一致,我编写了以下方法:

static void printWeekNumber(DayOfWeek firstDayOfWeek, LocalDate date) {
    DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("EEE uuuu-MM-dd", Locale.ENGLISH);
    final int daysPerWeek = DayOfWeek.values().length;

    // Week number according to your comment: “using the Temporal adjusters
    // I am getting the date on the last day of the week.
    // After that dividing the Day of the Year from the API by 7”
    DayOfWeek lastDayOfWeek = firstDayOfWeek.minus(1);
    int askersCommentWeekNumber = date
            .with(TemporalAdjusters.nextOrSame(lastDayOfWeek))
            .getDayOfYear()
                    / daysPerWeek;

    // My suggested way of calculating the same week number
    WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, daysPerWeek);
    int customWeekNumber = date.get(customWeekFields.weekOfWeekBasedYear());

    System.out.format(Locale.ENGLISH, "Week begins on %-8s Date is %s. Week %2d or %2d, agree? %s%n", 
            firstDayOfWeek, date.format(dateFormatter), 
            askersCommentWeekNumber, customWeekNumber, 
            askersCommentWeekNumber == customWeekNumber);
}

为了方便手工检查计算,我选择了不同年份的一月份的日期:

    printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2017, Month.JANUARY, 9));
    printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2017, Month.JANUARY, 9));
    printWeekNumber(DayOfWeek.THURSDAY, LocalDate.of(2017, Month.JANUARY, 9));
    printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2018, Month.JANUARY, 9));
    printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2018, Month.JANUARY, 9));
    printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2019, Month.JANUARY, 9));
    printWeekNumber(DayOfWeek.MONDAY, LocalDate.of(2019, Month.JANUARY, 9));

输出:

Week begins on SUNDAY   Date is Mon 2017-01-09. Week  2 or  2, agree? true
Week begins on MONDAY   Date is Mon 2017-01-09. Week  2 or  2, agree? true
Week begins on THURSDAY Date is Mon 2017-01-09. Week  1 or  1, agree? true
Week begins on SUNDAY   Date is Tue 2018-01-09. Week  1 or  1, agree? true
Week begins on MONDAY   Date is Tue 2018-01-09. Week  2 or  2, agree? true
Week begins on SUNDAY   Date is Wed 2019-01-09. Week  1 or  1, agree? true
Week begins on MONDAY   Date is Wed 2019-01-09. Week  1 or  1, agree? true

不过,请检查结果是否如您所愿。对于您问题中的示例,结果既不是 41 也不是 42:

    printWeekNumber(DayOfWeek.SUNDAY, LocalDate.of(2018, Month.OCTOBER, 9));
Week begins on SUNDAY   Date is Tue 2018-10-09. Week 40 or 40, agree? true

编辑:如果您想要 ISO 8601 周数,请使用 date.get(WeekFields.ISO.dayOfWeek())。如果您希望按照 ISO 8601 自定义一周的第一天和第一周的 4 天,请使用:

    WeekFields customWeekFields = WeekFields.of(firstDayOfWeek, 4);

【讨论】:

  • 你是对的!我的计算不正确...非常感谢您如此坚持和乐于助人!您的解决方案确实有效!奇怪的是,虽然 2017 年 1 月 1 日是第 52 周,但我的 QA 对结果仍然满意。
  • 2017 年 1 月 1 日是星期日。因此,如果您的一周从星期一(或例如星期四)开始,则第 1 周尚未从 1 月 1 日开始,因此它与 2016 年的最后一周,即第 52 周有关。如果该周从星期日开始,则 1 2017 年 1 月应该属于第 1 周(我没有测试过这个特殊情况)。
  • 它不属于第 1 周。似乎是国际标准epochconverter.com/weeks/2017
  • 感谢@vkandvia 提出修改建议。我认为这不正确,因此我在答案的底部添加了一些信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-11
  • 2022-01-11
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多