从2月的java.util.Calendar一个奇怪的行为 [英] A strange behavior from java.util.Calendar on February
问题描述
我从java.util.Calendar遇到了一个奇怪的行为:
I faced with a strange behavior from java.util.Calendar:
import static org.junit.Assert.*;
import org.junit.Test;
import java.util.Calendar;
public class Tester1 {
@Test
public void test_monthOfDate() {
assertEquals(1, monthOfDate(2013, 1, 30)); // OK
assertEquals(1, monthOfDate(2013, 1, 31)); // OK
// Start of February
assertEquals(2, monthOfDate(2013, 2, 1)); // FAIL
assertEquals(2, monthOfDate(2013, 2, 28)); // FAIL
// to the end of it
// and after that it is okay also
assertEquals(3, monthOfDate(2013, 3, 1)); // OK
}
public int monthOfDate(int year, int month, int day) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
// just a simple get! but seems it is very important
cal.get(Calendar.MONTH);
//
cal.set(Calendar.DAY_OF_MONTH, day);
return cal.get(Calendar.MONTH) + 1;
}
}
我想知道为什么会发生这种情况? / p>
I want to know why exactly this is happening?
推荐答案
问题是您在2013年1月30日开始使用日历。
The problem is that you're starting off with a calendar on January 30th 2013.
然后将年份设置为2013年 - 这不是问题。
You're then setting the year to 2013 - that's not a problem.
然后将月份设置为1(即2月)。你期望在这里发生什么?实际发生的是,它会记住它需要将月份设置为1,但不重新计算实际时间值。根据, c 将重新计算 get
的时间值 /javase/7/docs/api/java/util/Calendar.html\">文档(emphsis mine):
You're then setting the month to 1 (i.e. February). What do you expect to happen here? What actually happens is that it will remember that it needs to set the month to 1, but not recompute the actual time value. The time value will be recomputed on your call to get
though, as per the documentation (emphsis mine):
set(f,value)将日历字段f更改为值。此外,它设置一个内部成员变量以指示日历字段f已更改。尽管日历字段f立即更改,但直到下一次调用get(),getTime(),getTimeInMillis(),add()或roll()时才会重新计算日历的时间值(以毫秒为单位)。因此,对set()的多次调用不会触发多个不必要的计算。作为使用set()更改日历字段的结果,其他日历字段也可能更改,具体取决于日历字段,日历字段值和日历系统。 此外,在重新计算日历字段后,get(f)不一定会返回通过set方法调用设置的值。具体日期由具体的日历类确定。
set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although calendar field f is changed immediately, the calendar's time value in milliseconds is not recomputed until the next call to get(), getTime(), getTimeInMillis(), add(), or roll() is made. Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a calendar field using set(), other calendar fields may also change, depending on the calendar field, the calendar field value, and the calendar system. In addition, get(f) will not necessarily return value set by the call to the set method after the calendar fields have been recomputed. The specifics are determined by the concrete calendar class.
当您尝试将1月30日更改为2月30日并强制执行计算时,实际上是什么
When you try to change "January 30th" to "February 30th" and force a computation, what actually happens is that you end up on March 2nd on my box - but it may differ on your implementation.
最好的修复方法是:
- 使用 c> a href =http://joda-time.sf.net> Joda Time 作为一个更为明智的API。
- Use
Calendar.set(year, month, date)
instead to avoid this ordering issue - Use Joda Time as a more sensible API in the first place.
这篇关于从2月的java.util.Calendar一个奇怪的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!