問題描述
我遇到了來自 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;
}
}
我想知道為什么會(huì)這樣?
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.
然后您將年份設(shè)置為 2013 年 - 這不是問題.
You're then setting the year to 2013 - that's not a problem.
然后您將月份設(shè)置為 1(即二月).你期望在這里發(fā)生什么?實(shí)際發(fā)生的是它會(huì)記住它需要將月份設(shè)置為 1,但 不會(huì) 重新計(jì)算實(shí)際時(shí)間值.根據(jù) 文檔(重點(diǎn)是我的):
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 更改為 value.此外,它設(shè)置一個(gè)內(nèi)部成員變量來指示日歷字段 f 已更改.盡管日歷字段 f 立即更改,但在下一次調(diào)用 get()、getTime()、getTimeInMillis()、add() 或 roll() 之前,不會(huì)重新計(jì)算日歷的時(shí)間值(以毫秒為單位).因此,多次調(diào)用 set() 不會(huì)觸發(fā)多次不必要的計(jì)算.作為使用 set() 更改日歷字段的結(jié)果,其他日歷字段也可能更改,具體取決于日歷字段、日歷字段值和日歷系統(tǒng).另外,get(f)在重新計(jì)算日歷字段后,不一定會(huì)返回調(diào)用set方法設(shè)置的值.具體由具體的日歷類決定.
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.
當(dāng)您嘗試將1 月 30 日"更改為2 月 30 日"并強(qiáng)制進(jìn)行計(jì)算時(shí),實(shí)際上會(huì)發(fā)生的是您在 3 月 2 日結(jié)束了我的盒子 - 但您的可能會(huì)有所不同實(shí)施.
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.
最好的修復(fù)方法是:
- 使用
Calendar.set(year, month, date)
來避免這個(gè)排序問題 - 首先使用 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.
這篇關(guān)于2 月 java.util.Calendar 的一個(gè)奇怪行為的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,也希望大家多多支持html5模板網(wǎng)!