[英]Assigning java.sql.Timestamp with daylight savings time
我無法理解java.sql.timestamp
。
如果我運行 java 棄用的構造函數:
java.sql.Timestamp(106,2,26,1,0,0,0)
java.sql.Timestamp(106,2,26,2,0,0,0)
java.sql.Timestamp(106,2,26,3,0,0,0) //<-- Separated by one hour
我得到:
2006-03-26 01:00:00.0
2006-03-26 03:00:00.0
2006-03-26 03:00:00.0 //<--These last two are the same
夏令時發生在這些時間(至少在我的國家)。 但是時間前后的日期不會移動。 為什么兩個不同的小時會在同一時間返回?
我想獲得時間戳作為我的輸入,我該如何強制?
不要使用這個已棄用的構造函數,它已被棄用,因為它使用默認時區。
使用具有適當時區 (CET) 的日歷(或 DateFormat),設置日歷的字段(或解析包含要插入的日期的字符串),從日歷/日期中獲取毫秒數,並構建時間戳從毫秒。
使用System.currentTimeMillis();
為您提供格林威治標准時間,不受夏令時、閏秒和其他意外調整日期的影響。
long now = System.currentTimeMillis();
或手動指定時區:
long ms = Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTimeInMillis();
夏令時 (DST) 切換意味着凌晨 2 點從未存在過。 所以你提供了無效的輸入。
ZonedDateTime
類試圖通過調整您的時間輸入來提供幫助,跳到凌晨 3 點,就像時鍾在敲擊 02:00 時比早上跳了一個小時一樣。
ZonedDateTime
.of( 2006 , 3 , 26 , 2 , 0 , 0 , 0 , ZoneId.of( "Africa/Tunis" ) )
.toString()
2006-03-26T03:00+02:00[非洲/突尼斯]
java.sql.Timestamp
是一個糟糕的類,以及它的兄弟類,例如java.util.Date
和Calendar
/ GregorianCalendar
。 它的許多設計問題之一是時區處理混亂。
相反,只使用現代java.time類。
對於時刻(日期、時間和時區或 UTC 偏移量),請使用以下類之一:
Instant
— 始終以 UTC Instant
的時刻。OffsetDateTime
— 與 UTC 有偏移量(小時-分鍾-秒數)但時區未知的時刻ZonedDateTime
— 具有指定時區的時刻。聽起來您打算在自己的區域中使用日期時間。
ZoneId
以Continent/Region
格式指定正確的時區名稱,例如America/Montreal
、 Africa/Casablanca
或Pacific/Auckland
。 永遠不要使用EST
或IST
等 2-4 個字母的縮寫,因為它們不是真正的時區,不是標准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
如果您想使用 JVM 的當前默認時區,請詢問它並作為參數傳遞。 如果省略,代碼讀起來會變得模棱兩可,因為我們不確定您是否打算使用默認值,或者您是否像許多程序員一樣沒有意識到這個問題。
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
ZonedDateTime
指定特定地區(時區)的人們使用的掛鍾時間中所見的時間和日期。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt_1 = ZonedDateTime.of( 2006, 3 , 26 , 1 , 0 , 0 , 0 , z ) ;
ZonedDateTime zdt_2 = ZonedDateTime.of( 2006, 3 , 26 , 2 , 0 , 0 , 0 , z ) ;
ZonedDateTime zdt_3 = ZonedDateTime.of( 2006, 3 , 26 , 3 , 0 , 0 , 0 , z ) ;
System.out.println("zdt_1.toString(): " + zdt_1);
System.out.println("zdt_2.toString(): " + zdt_2);
System.out.println("zdt_3.toString(): " + zdt_3);
zdt_1.toString(): 2006-03-26T01:00+01:00[非洲/突尼斯]
zdt_2.toString(): 2006-03-26T03:00+02:00[非洲/突尼斯]
zdt_3.toString(): 2006-03-26T03:00+02:00[非洲/突尼斯]
我們在第三個項目上看到了一個驚喜,我們要求凌晨 2 點但在凌晨 3 點得到回復。 這是可以理解的,因為夏令時 (DST)切換或“提前”。 從 2005 年開始, 突尼斯采用了夏令時。 2009 年晚些時候,他們恢復了知覺並僅恢復到標准時間。
所以突尼斯當天沒有凌晨 2 點。 當時鍾敲擊凌晨 2 點時,它跳到了凌晨 3 點。 凌晨 2 點從未存在過。 那一天只有 23 小時,而不是通常的 24 小時。 所以我們上面的代碼要求一個無效的日期時間。 ZonedDateTime
類,而不是拋出Exception
,試圖通過調整到有效的時間來幫助我們。 ZonedDateTime.of
的JavaDoc 說明了這一點:
從年、月、日、小時、分鍾、秒、納秒和時區獲取 ZonedDateTime 的實例。
這會創建一個分區日期時間,該日期時間與七個指定字段的本地日期時間盡可能接近。 時區規則,例如夏令時,意味着並非每個本地日期時間都對指定區域有效,因此本地日期時間可能會被調整。
本地日期時間被解析為時間線上的一個瞬間。 這是通過為區域 ID 的規則定義的本地日期時間查找與 UTC/格林威治的有效偏移量來實現的。
在大多數情況下,本地日期時間只有一個有效偏移量。 在重疊的情況下,當時鍾回退時,有兩個有效的偏移量。 此方法使用通常對應於“夏天”的較早偏移量。
在有間隙的情況下,當時鍾向前跳躍時,沒有有效的偏移量。 取而代之的是,本地日期時間被調整為延遲間隔的長度。 對於典型的一小時夏令時更改,本地日期時間將在一小時后移動到通常對應於“夏季”的偏移量中。
所以行為是一個特性,而不是一個錯誤。
java.time框架內置於 Java 8 及更高版本中。 這些類取代麻煩的老傳統日期時間類,如java.util.Date
, Calendar
,和SimpleDateFormat
。
現在處於維護模式的Joda-Time項目建議遷移到java.time類。
要了解更多信息,請參閱Oracle 教程。 並在 Stack Overflow 上搜索許多示例和解釋。 規范是JSR 310 。
您可以直接與您的數據庫交換java.time對象。 使用符合JDBC 4.2或更高版本的JDBC 驅動程序。 不需要字符串,不需要java.sql.*
類。
從哪里獲得 java.time 類?
ThreeTen-Extra項目用額外的類擴展了 java.time。 該項目是未來可能添加到 java.time 的試驗場。 您可以在這里找到一些有用的類,比如Interval
, YearWeek
, YearQuarter
,和更多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.