我在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。
有人可以解释发生了什么,为什么这个测试上周有效?
答案 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 字段。