2014-12-09 21 views
7

我正在嘗試調試一些遺留代碼中的問題。爲什麼java.util.calendar對象的值在調用get(int)後發生變化

我已經縮小了問題下面的方法:

public String formatDateTimeFromCalendar (Calendar cal){ 
     StringBuffer sb = new StringBuffer(); 
     String hr = ""+cal.get(Calendar.HOUR_OF_DAY); 
     sb.append(String.format("%02d", hr)); 
     sb.append(":"); 
     sb.append(String.format("%02d", cal.get(Calendar.MINUTE))); 
     sb.append(" on "); 
     sb.append(String.format("%02d", cal.get(Calendar.DAY_OF_MONTH))); 
     sb.append("/"); 
     sb.append(String.format("%02d", cal.get(Calendar.MONTH)+1)); 
     sb.append("/"); 
     sb.append(cal.get(Calendar.YEAR)); 
     return sb.toString(); 
    } 

調試 2號線的cal參數是一個將來的日期。 (2015-01-06T00:00:00.000Z)

與第一cal.get(cal PARAM的值3線的執行已經改變之後(以2014-12-12T00:00:00.000Z)

爲什麼/這怎麼可能?

這裏是正在創建日曆:

Calendar startDateAndTime = Calendar.getInstance(); 
     startDateAndTime.setTime(response.getStartDate().toGregorianCalendar().getTime()); 
     startDateAndTime.set(Calendar.HOUR_OF_DAY, response.getStartTime().getHour()); 
     startDateAndTime.set(Calendar.MINUTE, response.getStartTime().getMinute()); 
     startDateAndTime.set(Calendar.SECOND, response.getStartTime().getSecond()); 
     startDateAndTime.set(Calendar.MILLISECOND, response.getStartTime().getMillisecond()); 

response.getStartDate()返回XMLGregorianCalendar

+3

是在多個線程中使用的傳入日曆對象嗎? – geert3 2014-12-09 12:23:39

+0

請注意,您使用'String'作爲'%02d'格式的參數,該格式通常需要一個整數。 – geert3 2014-12-09 12:25:16

+0

顯式沒有線程。它是一個Web應用程序的一部分。 – 2014-12-09 12:26:12

回答

3

這是因爲get電話正常化寬鬆模式Calendar,並驗證其在嚴格模式:

返回給定日曆字段的值。在寬鬆模式下,所有日曆字段都被標準化。在非寬鬆模式下,所有日曆字段都將進行驗證,並且如果任何日曆字段的值超出範圍,此方法將引發異常。規範化和驗證由complete()方法處理,該過程依賴於日曆系統。

看起來您的Calendar對象處於寬鬆模式,因此執行標準化。規範化取決於日曆實例。

+3

但2015-01-06完全有效,這怎麼能正常化到2014-12-12? – geert3 2014-12-09 12:28:00

+1

@ geert3例如,當您使用set()方法時,它會在隨後的get()中強制重新計算字段。 – mkrakhin 2014-12-09 12:31:33

+0

@mkrakhin ok有道理。調試器正在顯示「舊」值,而實際上它在那時已經被更改。 – geert3 2014-12-09 12:32:18

2

這是get()方法的java.util.Calendar的源代碼。

public int get(int field) 
    { 
     complete(); 
     return internalGet(field); 
    } 

complete()方法檢查是否所有字段都在實例中設置並可以規範化日期和時間。
這是默認實現完整的()方法

protected void complete() 
{ 
    if (!isTimeSet) 
     updateTime(); 
    if (!areFieldsSet || !areAllFieldsSet) { 
     computeFields(); // fills in unset fields 
     areAllFieldsSet = areFieldsSet = true; 
    } 
} 


,但你不要以爲你的領域是必要的無效。如果您手動編輯調用set()方法的日曆實例,則可能會發生這種情況,它會無條件地將isTimeSet和areFieldsSet設置爲false,以強制在隨後獲取數據時重新計算。

+0

日曆對象使用.set方法進行編輯。我會仔細檢查這些值是否正確。 – 2014-12-09 12:40:41

+0

@MarkW在第二個答案中檢查我的答案的更新和geert3的最後評論。 – mkrakhin 2014-12-09 12:45:52

相關問題