時區& DST數據的變化
的answer by GriffeyDog和意見建議你是因爲你的計算機和JVM上設置的困惑。該問題可能與Daylight Saving Time (DST)有關,因爲10月20日的時間大約爲DST change for Brazil。 data for time zones and DST隨Java更新一起更新。您可能會看到巴西的更新有所不同。
喬達時間
測試了這一點,通過使用Joda-Time當前版本(現在2.3)。比使用java.util.Date & .Calendar更容易混淆。 Joda-Time中的日期時間知道它自己分配的時區。 Joda-Time同時適用於Java 6 & 7(和8)。 Joda-Time包含自己的時區和DST數據,而不是使用Java捆綁的數據。
使用UTC
正如其中一條評論所暗示的,明確使用UTC進行比較。
示例代碼在約達時間
DateTimeZone timeZoneSao_Paulo = DateTimeZone.forID("America/Sao_Paulo");
DateTime dateTimeSao_Paulo = new DateTime(2041, DateTimeConstants.OCTOBER, 20, 1, 2, 3, timeZoneSao_Paulo).withTimeAtStartOfDay();
DateTime dateTimeUtc = dateTimeSao_Paulo.withZone(DateTimeZone.UTC);
DateTime dateTimeSao_PauloBeforeMidnight = new DateTime(2041, DateTimeConstants.OCTOBER, 19, 23, 50, 0, timeZoneSao_Paulo);
DateTime dateTimeSao_PauloAfterMidnight = dateTimeSao_PauloBeforeMidnight.plusHours(1);
轉儲到控制檯。
System.out.println("dateTimeSao_Paulo: " + dateTimeSao_Paulo);
System.out.println("dateTimeUtc: " + dateTimeUtc);
System.out.println("dateTimeSao_PauloBeforeMidnight: " + dateTimeSao_PauloBeforeMidnight);
System.out.println("dateTimeSao_PauloAfterMidnight: " + dateTimeSao_PauloAfterMidnight);
運行時。
dateTimeSao_Paulo: 2041-10-20T01:00:00.000-02:00
dateTimeUtc: 2041-10-20T03:00:00.000Z
dateTimeSao_PauloBeforeMidnight: 2041-10-19T23:50:00.000-03:00
dateTimeSao_PauloAfterMidnight: 2041-10-20T01:50:00.000-02:00
通過與前一天的工作和通過plusHours
方法添加小時的實驗。
正如你可以在上面的輸出,午夜十月2041 19-20是目前預定日期爲DST變化,從UTC偏移抵消-03:00
到-02:00
。一小時加一小時到午夜前跳wall-clock-time兩小時,從23
小時到01
小時而不是00
小時。
此外,請注意,嘗試構建20日00:00:00的時間會導致Joda-Time異常,因爲沒有這樣的日期時間。
日期從數據庫
一個JDBC結果的getDate
method返回java.sql.Date
這是一個java.util.Date
的bastardized版本。
java.sql.Date和java.util.Date都不包含時區信息,但被假定爲UTC。它們之間的區別在於sql
版本的時間值被設置爲00:00:00(午夜),很難與SQL data type DATE匹配。在SQL中,DATE意味着僅限日期而沒有時間。不幸的是,舊版本的Java和JDBC沒有日期類,但應該有。這已在Java 8與the java.time package及其LocalDate
class糾正,但JDBC尚未趕上。
因此,如果您從數據庫中獲取java.sql.Date,則必須諮詢程序員或數據庫管理員以確認該日期時間是否確實指向UTC。它應該是,但適當的日期時間工作避開了許多程序員和管理員,所以你應該驗證。
如果java.sql.Date確實是UTC,那麼通過將它傳遞給DateTime構造函數來轉換爲Joda-Time。我強烈建議將一個DateTimeZone傳遞給新的DateTime,而不是依賴於被分配的JVM的默認時區。
DateTime dateTimeFromDatabaseBrazil = new DateTime(myJavaSqlDate, timeZoneSao_Paulo);
或
DateTime dateTimeFromDatabaseUtc = new DateTime(myJavaSqlDate, DateTimeZone.UTC);
如果分配到非UTC時區,你可能要在當地與懷念調整時間部分的一天的第一刻的一致性專注於日期而不是時間。要獲得第一時間,請致電withTimeAtStartOfDay
method(Joda-Time 2.3中的新增功能,舊的「午夜」類別和方法不再使用)。
DateTime dateTimeFromDatabaseBrazil = new DateTime(myJavaSqlDate, timeZoneSao_Paulo).withTimeAtStartOfDay();
或者轉換爲LocalDate
對象,如果你確定你想要的日期 - 不只是一天中的時間。
出於興趣,它是否只在輸出巴西利亞時間時給出錯誤結果(即,如果以UTC輸出的結果是什麼)?如果它是一個特定於JDK6的bug,並且您不能使用JDK7,但可以使用外部庫,您可能會發現joda時間有效(?) –
如果您必須堅持使用版本6,則應該支付Oracle修復錯誤的一部分支持合同(如果它是一個bug),因爲JDK 6現在不在公衆支持範圍內 – mschenk74
如果您在JDK7中觀察到不同的行爲,那麼原因可能是不同的時區數據存儲庫。從Oracle嘗試[TZ-Updater-Tool](http://www.oracle.com/technetwork/java/javase/tzupdater-readme-136440.html)以更新您的存儲庫。 –