我有以下测试,我的理解应该通过。有没有我遗失的东西或者这是日历中的错误?
Calendar inputC = new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.US);
// Sunday
inputC.set(2014, Calendar.JUNE, 22, 0, 0, 0);
inputC.set(Calendar.MILLISECOND, 0);
// START code impl
// Given a date returns back the date with it's day being first day of week and resets time.
Calendar dc = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
dc.set(inputC.get(Calendar.YEAR), inputC.get(Calendar.MONTH), inputC.get(Calendar.DAY_OF_MONTH), 0, 0 , 0);
dc.set(Calendar.MILLISECOND, 0);
// dc.getTimeInMillis();
// dc.set(Calendar.WEEK_OF_YEAR, inputC.get(Calendar.WEEK_OF_YEAR));
dc.set(Calendar.DAY_OF_WEEK, dc.getFirstDayOfWeek());
Date output = dc.getTime();
// END code impl
Calendar expectedSundayC = new GregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.US);
expectedSundayC.set(2014, Calendar.JUNE, 22, 0, 0, 0);
expectedSundayC.set(Calendar.MILLISECOND, 0);
assertEquals(output, expectedSundayC.getTime());
输出:2014-06- 15 T00:00:00Z
预计:2014-06- 22 T00:00:00Z
上述测试失败,除非我取消注释以下两行中的任何一行:
// dc.getTimeInMillis();
// dc.set(Calendar.WEEK_OF_YEAR, inputC.get(Calendar.WEEK_OF_YEAR));
为什么dc.getTimeInMillis()
影响输出?
取消注释上面的第2行似乎是多余的,因为我已经设置了年,月,日,小时,分钟,秒,毫秒字段,这应该是完整日期时间的足够数据。
答案 0 :(得分:16)
你当然给了我一个关于这个的头像,但我明白了。
可以通过调用set方法来设置日历字段值。在需要计算其时间值(Epoch的毫秒数)或日历字段的值之前,不会解释日历中设置的任何字段值。调用get,getTimeInMillis,getTime,add和roll涉及这样的计算。
这意味着,无论何时使用set更改值,都应该告诉它使用其中一种get方法来传播更改来更新自身。但是,除非取消注释代码,否则您的代码不会。因此,代码中的某些内容显然无法与computeTime中的set一起使用。
所以...我们可以看看这个过时但仍然难以驾驭的 GregorianCalendar来源的副本,并准确分析你做的时候发生了什么使用所有其他chanes设置星期几之后的getTime()。
唉,抄袭是痛苦的。我会引导你完成它。首先,我们基本知道getTimeInMillis()
在computeTime()
行调用505
。
您声明了Calendar的实例。它具有预定义的值。今天的确切日期。而且我们也在九月的第三周。重要的是晚些时候!
现在我们在511
行分配您的一天。这是您的一天设置为22的地方。
int day = fields[DAY_OF_MONTH];
行523
是令人兴奋的地方并打破你的约会!我们将其评估为false
并转到第553
行的其他位置。
if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR]))
//evaluates to true
我们在555
输入if语句,因为设置了DAY_OF_WEEK
。我们有DAY_OF_WEEK_IN_MONTH
,但我们没有自己设定。日历在实例化时执行了。还记得九月的第三周吗?是的,它在这里它咬我们回来。它计算6月的第3周的星期日,并且将我们的日期= 22 覆盖到15日,这是6月的第3个星期日。
if (isSet[DAY_OF_WEEK]) { //yup we set this
int first = getFirstDayOfMonth(year, month);
// 3: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
if (isSet[DAY_OF_WEEK_IN_MONTH]) { //we didn't set this, but it's been set!
if (fields[DAY_OF_WEEK_IN_MONTH] < 0) {
month++;
first = getFirstDayOfMonth(year, month);
day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]);
} else
day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1);
// 15 = 1 + 7 * (3 - 1)
int offs = fields[DAY_OF_WEEK] - first;
if (offs < 0)
offs += 7;
day += offs;
}
}
检查您用年,月和日调用的set
方法的源javadoc。
设置日历字段YEAR,MONTH,DAY_OF_MONTH,HOUR_OF_DAY和MINUTE的值。 保留其他字段的先前值。如果不需要,请先调用clear()。
果然,在你的套装之前添加dc.clear();
会返回所需的结果。我没有通过它,但是鉴于目前经历的奇怪行为,每次更改后最好的选择是getTime()
将确保您的时间不会成为意外结果。< / p>
所以基本上,造成这个问题的原因是你有半数据的数据,半新数据与自己相矛盾并覆盖了一些东西。如果这段代码已经在下周运行,你甚至都不会发现这个错误。对于一个不方便的时间依赖条件,这是怎么回事?