2014-01-24 62 views
1

我試圖更改日曆對象的時區,同時保持實際的日期/時間,以便我可以調用更新的日曆對象上的getTimeInMilliseconds()。我看了一下this other question。這裏,接受的答案是單獨設置新日曆對象的每個字段。不過,只需更改原始日曆對象副本的時區即可使其工作。奇怪的是,這隻有在重設時區之前對原始日曆進行一些修改纔有效。以下示例說明了不一致性。JAVA:更改日曆對象的TimeZone時奇怪的行爲,而不更改日期/時間

public void TestCalendar() 
{ 
    Calendar nextYear = Calendar.getInstance(); 
    nextYear.add(Calendar.YEAR, 1); 
    log.info("Next Year: {}", getUTCMilliseconds(nextYear)); 

    Calendar now = Calendar.getInstance(); 
    log.info("Now: {}", getUTCMilliseconds(now)); 
} 

protected String getUTCMilliseconds(Calendar cal) 
{ 
    // Create a new calendar so we don't modify input 
    Calendar expectedDbTime = (Calendar) cal.clone(); 
    // Change the TimeZone the contained date is interpreted in 
    expectedDbTime.setTimeZone(TimeZone.getTimeZone("UTC")); 
    // Return millisecond value of this date in the UTC timezone 
    return String.valueOf(expectedDbTime.getTimeInMillis()); 
} 

我跑了1月24日該計劃,2015年@下午2:33,並得到了以下的輸出:

Next Year: 1422110038529 //(Corresponding UTC Date: Sat Jan 24 2015 2:33:58 PM) 
Now: 1390599238531 //(Corresponding UTC Date: Fri Jan 24 2014 9:33:58 PM) 

正如你可以看到,如預期的那樣nextYear版畫,但下一行與預期的不同,它不是 (它應該對應於2014年1月24日下午2點33分58秒,相反,它對應於當前日期/時間,即2014年1月24日2:33:58 MTN) 。有人能告訴我這裏發生了什麼事嗎?

編輯:只是更新了一些格式。

+1

setTimeZone的'的行爲()'是非常反直覺的,有效打破。這種行爲存在一些錯誤: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4827490 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id= 4177484 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4096231 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4227735 –

+0

@goparkyourcar你的問題不明確。究竟你想從什麼開始,你想要什麼作爲輸出? –

+0

我的意圖是,給定一個日曆對象,表示某個時區的某個日期/時間(說2012年1月1日12AM MTN),我想獲得同一日期在另一個時區的毫秒值(Say 2012年1月1日上午12點)。我的問題是,爲什麼我必須在調用我的getUTCMilliseconds()函數以使所述函數正常工作之前修改Calendar對象。 – Cod3Citrus

回答

2

設置時區不能像設置字段一樣工作。設置字段時,將重新計算內部毫秒數以匹配字段。設置時區時,將重新計算這些字段,以使毫秒數保持不變! (也就是說,當你有一個clanedar評估,以2:00 PM山,將其設置爲UTC,它不計算代表2PM UTC毫秒,它改變了時間至晚上9時。)

現在,這裏的地方橫向,當你有一個掛起的set(或add在你的情況下)告訴日曆重新計算毫秒數(打開add)的標誌優先於標誌,告訴是否重新計算文本字段的毫秒數開啓由setTimeZone

所以情況1日曆具有文本值:

星期六2015年1月24日2時33分58秒PM UTC,因爲add被稱爲「基於'人類'值重新計算毫秒'」的標誌被打開,並且它給了您預期的#號。

情況2日曆具有文本值:

星期六2015年1月24日下午2時33分58秒UTC,而是說要重新計算毫秒#不上標誌,所以不是該標誌開啓的時區設置以「毫秒爲基礎」重新計算「人類價值觀」已打開,並將其更改爲晚上9點。

如果你改變你的代碼:

public void TestCalendar() { 
    Calendar nextYear = Calendar.getInstance(); 
    nextYear.add(Calendar.YEAR, 1); 
    nextYear.getTime(); 
    log.info("Next Year: {}", getUTCMilliseconds(nextYear)); 

    Calendar now = Calendar.getInstance(); 
    log.info("Now: {}", getUTCMilliseconds(now)); 
} 

你會看到兩者之間的一致行爲,因爲調用的getTime()清除該標誌重新計算之前,設置時區毫秒。

現在你知道爲什麼股票回答這樣的問題是'omg use jodatime'!

的「安全」的方式來獲得你正期待出現的情況是:

protected String getUTCMilliseconds(Calendar cal) { 
    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 
    utcCal.set(Calendar.YEAR, cal.get(Calendar.YEAR)); 
    utcCal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR)); 
    utcCal.set(Calendar.HOUR_OF_DAY, cal.get(Calendar.HOUR_OF_DAY)); 
    utcCal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE)); 
    utcCal.set(Calendar.SECOND, cal.get(Calendar.SECOND)); 
    utcCal.set(Calendar.MILLISECOND, cal.get(Calendar.MILLISECOND)); 
    return String.valueOf(utcCal.getTimeInMillis()); 
}