2016-12-02 35 views
2

GregorianCalendar的一個日期正在不一致:獲取從一個GregorianCalendar

Calendar cal = new GregorianCalendar(2000, 0, 1); 
long testCalOne = cal.getTimeInMillis(); 
cal.setTimeZone(TimeZone.getTimeZone("UTC")); 
long testCalTwo = cal.getTimeInMillis(); 

Calendar cal2 = new GregorianCalendar(2000, 0, 1); 
cal2.setTimeZone(TimeZone.getTimeZone("UTC")); 
long testCalThree = cal2.getTimeInMillis(); 

System.out.println(testCalOne + ", " + testCalTwo + ", " + testCalThree); 

結果

946681200000, 946681200000, 946684800000 

這分別表示2000-01-01午夜GMT + 1,GMT + 1和UTC 。我的時區是相對於UTC的+1小時。

這裏的問題是,getTimeInMillis應該返回自1970-01-01以來的UTC毫秒數。只有testCalThree是正確的。

另一個問題是setTimeZone看起來不工作,這取決於我之前是否調用了getTimeInMillis。

我的目標是將我從其他代碼接收的日曆作爲參數,並獲取UTC(java.util)日期以供進一步使用。

+1

如果您想保持理智,請切換到JodaTime或Java8新的日期/時間API。 – lexicore

+0

爲什麼還要使用'Calendar'? (沒有違法) – Spotted

+0

不是我的代碼,我只是從它的參數。 – Juryt

回答

0

我認爲這是Calendar實現中的一個錯誤。 time被高速緩存,即,如果一旦重新使用了,除非發生某些變化

但不知何故設置時區不被認爲是相關的變化。

您可以通過顯式更改或清除某個字段強制重新計算時間,以毫秒爲單位。所以這個:

Calendar cal = new GregorianCalendar(2000, 0, 1); 
    long testCalOne = cal.getTimeInMillis(); 
    cal.clear(Calendar.ZONE_OFFSET); 
    cal.setTimeZone(TimeZone.getTimeZone("UTC")); 
    long testCalTwo = cal.getTimeInMillis(); 

    Calendar cal2 = new GregorianCalendar(2000, 0, 1); 
    cal2.setTimeZone(TimeZone.getTimeZone("UTC")); 
    long testCalThree = cal2.getTimeInMillis(); 

    System.out.println(testCalOne + ", " + testCalTwo + ", " + testCalThree); 

給出:

946681200000, 946684800000, 946684800000 

如你所願。在設置時區之前,我必須做的唯一事情是cal.clear(Calendar.ZONE_OFFSET)

無論如何,我想重複評論中的建議。如果您重視您的理智,請切換至JodaTime或Java8日期/時間。

+0

從技術上講,它仍然不像預期的那樣,因爲getTimeInMillis應該考慮偏移量並將其作爲UTC返回。因此,設置時區應該是不相關的。 但是,getTimeInMillis似乎被竊聽,使得時區更改相關。 謝謝你的回答。 – Juryt

+0

如何設置時區應該不相關? 'getTimeInMillis()'返回1970-01-01 00:00:00 UTC和日曆實例中的日期之間的毫秒數。設置時區是重大更改,因爲日曆在您的情況下包含_local_ date 2000-01-01 00:00:00。 2000-01-01 00:00:00 UTC與2000-01-01 00:00:00 UTC + 1不同。 – Archie

0

對此進一步思考後,代碼可能按預期工作。根據是否在日曆上調用了getter,setTimeZone的功能可能會有所不同。

在第一種情況下,它改變時區,但由於時間已經被獲得並因此被初始化,所以UTC時間不變。

在第二種情況下,它表示我們在構造函數中傳遞的2001-1-1的初始化日期是UTC時間,應該被解析爲UTC而不是本地時區。

如果是這樣,那麼結果是有道理的。

+0

這是無稽之談。你調用* getter *的時刻應該完全不相關。我認爲這是一個錯誤。 – lexicore

+0

在內部,日曆很懶。它只會在需要時實際計算其內部字段。但是,您可以直接設置它們。這讓我懷疑,對於這個班級,當你打電話給一個吸氣劑是相關的。 (但反直覺和笨重。) – Juryt

0

TL;博士

myGregCal.toZonedDateTime() 
     .toInstant() 

......或者......

java.util.Date.from(
    myGregCal.toZonedDateTime() 
      .toInstant() 
) 

java.time

我的目標是拿我收到來自其他代碼參數日曆並獲得UTC(java.util)進一步使用的日期。的CalendarDate

麻煩的舊日期,時間類現在是傳統,由java.time類取代。幸運的是,您可以通過調用舊類的新方法來轉換爲java.time。

ZonedDateTime zdt = myGregCal.toZonedDateTime() ; 

對於UTC值,提取Instant。該類表示UTC時間軸上的時間,分辨率爲納秒。

Instant instant = zdt.toInstant() ; 

要生成表示標準ISO 8601格式的UTC值的字符串,請撥打toString

String output = instant.toString() ; 

如果您需要在生成的字符串等格式,轉換爲更靈活OffsetDateTime和使用DateTimeFormatter。搜索堆棧溢出了很多例子。

最好避免Date類。但是,如果你必須轉換。與Instant類似,Date表示UTC中時間線上的一個點。但是Date限於毫秒分辨率。所以你風險數據丟失,從三位數的毫秒數與十位數的納秒數之間的小數部分中刪除數字。

java.util.Date utilDate = Date.from(instant) ; 

關於java.time

java.time框架是建立在Java 8和更高版本。這些類取代了日期時間類legacy,如java.util.Date,Calendar,& SimpleDateFormat

Joda-Time項目現在位於maintenance mode,建議遷移到java.time。請參閱Oracle Tutorial。並搜索堆棧溢出了很多例子和解釋。規格是JSR 310

從何處獲取java.time類?

ThreeTen-Extra項目與其他類擴展java.time。這個項目是未來可能增加java.time的一個試驗場。您可以在這裏找到一些有用的類,如Interval,YearWeek,YearQuartermore