Java日历 - 设置day_of_week后日期不可预测

时间:2011-07-17 07:41:18

标签: java

我在JUnit测试中有以下代码,上周似乎工作失败了本周:

Calendar cal = Calendar.getInstance();
cal.set(2011, Calendar.JULY, 12);
cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY); // push the date to 15
System.out.println(cal.get(Calendar.DATE));

你可以从我的评论中推断出,因为12日是星期二,所以我认为将DAY_OF_WEEK设置为星期五之后日期为15。但是,打印的值为22,导致测试失败。

如果我按照以下方式更改代码,并添加额外的调用get:

Calendar cal = Calendar.getInstance();
cal.set(2011, Calendar.JULY, 12);
System.out.println(cal.get(Calendar.DATE));
cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY); // push the date to 15
System.out.println(cal.get(Calendar.DATE));

我得到了我期望的输出,12和15。

有人可以解释发生了什么,为什么这个测试上周有效?

3 个答案:

答案 0 :(得分:19)

首先要明白的是,Month + Day + DayOfWeek对日历没有任何意义。日历将根据

计算日期的真实值
  

年+月+日

  

年+月+周W_K_MONTH + DAY_OF_WEEK

(或其他一些组合,如年份+一年中的某一天等)所以Date + DayOfWeek本身并不意味着它。

要理解的第二件事是,当您设置Java日历时,它实际上不会重新计算绝对时间或更新相关字段,直到强制计算的操作发生。

第一次设置后,日历处于冲突状态。月份和日期说它是7月12日,但是“月中的一周”和“星期几”仍然表示它是今天,无论今天是什么。然后,您将周日设置为星期五。所以今天的月份和日期说是7月12日,但是“一个月的一周”和“一周的一天”字段表示它是'这个'周的星期五。

日历规则说最近设置的字段在发生冲突时“获胜”,因此本周五结合的星期和星期几用于计算其他字段。

在中间插入一个“修复”它,因为它强制将日历的整个内部状态重新计算到7月12日星期二,然后再设置为星期五,因此没有内部冲突。通过在您将星期几设置为星期五之前重新计算,将“月中的一周”设置为包含7月12日的那一周。

编辑:很抱歉在两天后进行更改,发现这在旧的浏览器标签中已打开,并且我认为我会扩展为未来googlers的希望帮助:

Jon在评论中工作的原因是他住在伦敦。他的电脑认为星期一星期开始。所以当被问到'这个'周的星期五时,7月17日星期日被问到时,它仍然在7月15日回复。我提出这个问题是因为在不同的语言环境中,一周的第一天不同只是尝试在日历中使用WEEK_OF字段的另一种方式。它会失败。

答案 1 :(得分:3)

Bug 4655637(看起来类似于您的问题)。我在最新的JDK6(Windows)下检查了该代码,在这两种情况下我都有15。顺便说一句:我建议明确地使用GregorianCalendar类,除非你想要别的东西(取决于你的语言环境)。

答案 2 :(得分:1)

编辑:official docs

  

以下是日历字段的默认组合。该   最近的组合,由最近设定的单曲确定   字段,将被使用。

     

对于日期字段:

 YEAR + MONTH + DAY_OF_MONTH
 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
 YEAR + DAY_OF_YEAR
 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
     

对于时间字段:

 HOUR_OF_DAY
 AM_PM + HOUR

除了@Affe的明确答案外,以下组合似乎有用(截至@ GrzegorzSzpetkowski&#39的错误报告链接)

  

日历需要以下字段组合来确定   约会。

 MONTH + DAY_OF_MONTH
 MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
 DAY_OF_YEAR
 DAY_OF_WEEK + WEEK_OF_YEAR
     

设置DAY_OF_WEEK时,日历需要一个星期字段   (WEEK_OF_MONTH,DAY_OF_WEEK_IN_MONTH或WEEK_OF_YEAR)也被   组。因此,请避免在未设置其中一周的情况下设置DAY_OF_WEEK   字段。