問題描述
我遇到了來自 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;
}
}
我想知道為什么會這樣?
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(即二月).你期望在這里發生什么?實際發生的是它會記住它需要將月份設置為 1,但 不會 重新計算實際時間值.根據 文檔(重點是我的):
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.此外,它設置一個內部成員變量來指示日歷字段 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 日"并強制進行計算時,實際上會發生的是您在 3 月 2 日結束了我的盒子 - 但您的可能會有所不同實施.
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.
最好的修復方法是:
- 使用
Calendar.set(year, month, date)
來避免這個排序問題 - 首先使用 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 的一個奇怪行為的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!