我更喜歡所有時間都在 UTC,除了它們顯示的時候。在最后一刻,它們可以轉換為本地時間,僅用于顯示。
我以前總是在 MySQL 中存盤 unix 時間戳(自紀元以來的秒數),在整數欄位中。我正在使用其他人的資料庫架構,我無法更改它使用DATETIME存盤原始時間甚至沒有偏移量的資料庫架構。
如何使用 UTC 格式的資料庫檢索和發送時間物件,因此資料庫絕對不進行任何轉換?
雖然是為 PostgreSQL 撰寫的,但我嘗試遵循 Basil Bourque 在以下問題上的出色回答。我Instant在任何地方都使用,除非他顯示我OffsetDateTime在與 JDBC 互動時使用 an,因為它是唯一保證受 JDBC 4.2 支持的現代 moment 類。
- 如何在 java 8 中將 UTC 日期轉換為 UTC OffsetDateTime?
- 在sql server中用UTC時間保存當前日期的問題
- 以及使用 jdbc 時如何使用時區保存正確的日期時間
我正在使用 MySql Connector/J 8.0.27,并且正在使用&preserveInstants=false&connectionTimeZone=UTC.
讓我們看一下DATETIME資料庫中存盤為“2022-01-14 11:00:00”的 a,它被理解為 UTC。
resultSet.getString(columnName); // "2022-01-14 11:00:00"
resultSet.getObject(columnName, OffsetDateTime.class).toString() // "2022-01-14T11:00-04:00"
resultSet.getObject(columnName, OffsetDateTime.class).toInstant().toString() // "2022-01-14T15:00:00Z"
當它創建時OffsetDateTime,它分配了“-04:00”的系統或服務器(同一臺機器)偏移量并搞砸了一切。我認為我的連接選項&preserveInstants=false&connectionTimeZone=UTC應該已經停止了。
我知道我可以立即將偏移量設定為“ 00:00” .withOffsetSameLocal(ZoneOffset.UTC).toInstant(),但是我如何避免這樣做并讓它直接創建一個OffsetDateTimeUTC 格式的?
uj5u.com熱心網友回復:
TIMESTAMP WITHOUT TIME ZONE
您已經確定了核心問題:您的表的作者將該列定義為 MySQLDATETIME型別。該型別僅表示具有時間的日期,但缺少時區或偏移量的背景關系。該 MySQLDATETIME列類似于 SQL 標準型別的TIMESTAMP WITHOUT TIME ZONE.
java.time.LocalDateTime
DATETIME因此,您在從該列檢索值時使用了錯誤的 Java 類。OffsetDateTime與其使用,不如使用LocalDateTime。與DATETIME( 和TIMESTAMP WITHOUT TIME ZONE) 一樣,Java 型別LocalDateTime表示具有時間但沒有區域或偏移量的日期。
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
確定片刻
您可以分配一個偏移量或時區來精確定位一個時刻,即時間線上的一個點。
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;
或者:
ZoneId z = ZoneId.of( "America/Edmonton" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
你說:
它分配了“-04:00”的系統或服務器(同一臺機器)偏移量并將一切搞砸了。
遍歷路線上的某些部分試圖幫助您實作代碼的意圖,即從僅日期和時間的值開始,并以分配的偏移量結束。很可能您的 JDBC 驅動程式是分配偏移量的部分。由于 MySQL 沒有存盤偏移量DATETIME,因此需要分配一些OffsetDateTime偏移量才能生成您請求的物件。
如上所示,更好的方法是在使用缺少偏移量的資料庫列時不請求物件。OffsetDateTime
你問:
如何使用 UTC 格式的資料庫檢索和發送時間物件,因此資料庫絕對不進行任何轉換?
您不能在 UTC 中看到的時刻與缺少從 UTC 偏移的概念的資料庫列交換。
如果要在 SQL 資料庫中表示時刻,則必須使用適當的資料型別,類似于 SQL 標準型別的型別TIMESTAMP WITH TIME ZONE。
您在將帶有偏移量的日期時間值與僅日期時間的資料庫列交換時所要求的就像要求將日元價格存盤在單純的數字列中一樣。您可以假裝這些記錄值代表日元價格,但您不知道。有人也可以在那里以歐元或比索存盤價格。
由于您似乎對當前的作業情況感到困惑,您可以假裝您的TIMESTAMP WITHOUT TIME ZONE 列存盤 UTC 值。本質上,這就是我上面的代碼示例所做的。
要在寫入值時假裝,請調整為 UTC,然后提取LocalDateTime.
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
OffsetDateTime odt = zdt.withOffsetSameInstant( ZoneOffset.UTC ) ;
LocalDateTime ldt = odt.toLocalDateTime() ;
myPreparedStatement.setObject( … , ldt ) ;
這種偽裝的做法充滿了危險,而且是不負責任的。該資料庫正在跟蹤虛構,而不是真相。請務必記錄此 hack,因為任何剛接觸該系統的程式員都會被徹底搞糊涂。
順便說一下,請注意型別名稱TIMESTAMP WITH TIME ZONE和TIMESTAMP WITHOUT TIME ZONE用詞不當。根據我被告知的情況以及我在草稿中看到的情況,SQL 標準實際上只意味著偏移量,而不是真正的時區。這就是為什么OffsetDateTime在 JDBC 中映射的唯一 Java 類與TIMESTAMP WITH TIME ZONE.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/411781.html
標籤:
上一篇:使用WHERE條件為MIN函式添加過濾器錯誤代碼:1111。組函式的使用無效
下一篇:在插入觸發器后更新另一個表的列值
