什么比日期和时区更难? SQL / JDBC中的日期和时区!
在jOOQ郵件列表上,最近有一個有趣的討論,關(guān)于jOOQ當(dāng)前缺乏對TIMESTAMP WITH TIME ZONE數(shù)據(jù)類型的現(xiàn)成支持。
沒有人說日期,時間和時區(qū)很容易! 這里有一個有趣的部分,我建議閱讀: 虛假的程序員相信時間
當(dāng)那還不夠時,還請閱讀: 更多的虛假程序員相信時間
我個人喜歡程序員錯誤地認為“ Unix時間是自1970年1月1日以來的秒數(shù)”。 …Unix時間無法代表leap秒;)
返回JDBC
這是Jaybird開發(fā)人員(Firebird JDBC驅(qū)動程序) Mark Rotteveel提出的一個有趣的Stack Overflow答案: java.sql.Timestamp時區(qū)是否特定?
可以按照以下方式觀察Mark的解釋(我在這里使用PostgreSQL):
Connection c = getConnection(); Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));try (PreparedStatement ps = c.prepareStatement("select"+ " ?::timestamp,"+ " ?::timestamp,"+ " ?::timestamp with time zone,"+ " ?::timestamp with time zone" )) {ps.setTimestamp(1, new Timestamp(0));ps.setTimestamp(2, new Timestamp(0), utc);ps.setTimestamp(3, new Timestamp(0));ps.setTimestamp(4, new Timestamp(0), utc);try (ResultSet rs = ps.executeQuery()) {rs.next();System.out.println(rs.getTimestamp(1) + " / " + rs.getTimestamp(1).getTime());System.out.println(rs.getTimestamp(2, utc)+ " / " + rs.getTimestamp(2, utc).getTime());System.out.println(rs.getTimestamp(3) + " / " + rs.getTimestamp(3).getTime());System.out.println(rs.getTimestamp(4, utc)+ " / " + rs.getTimestamp(4, utc).getTime());} }上面的程序使用Java和DB中使用時區(qū)而不使用時區(qū)的所有排列,并且輸出始終相同:
1970-01-01 01:00:00.0 / 0 1970-01-01 01:00:00.0 / 0 1970-01-01 01:00:00.0 / 0 1970-01-01 01:00:00.0 / 0如您所見,在每種情況下,UTC時間戳0均已正確存儲并從數(shù)據(jù)庫中檢索到。 我自己的語言環(huán)境是瑞士,即CET / CEST,在Epoch是UTC + 1,這就是在Timestamp.toString()上獲取輸出的地方。
當(dāng)您在SQL和/或Java中使用時間戳文字時,事情會變得很有趣。 如果這樣替換綁定變量:
Timestamp almostEpoch = Timestamp.valueOf("1970-01-01 00:00:00");ps.setTimestamp(1, almostEpoch); ps.setTimestamp(2, almostEpoch, utc); ps.setTimestamp(3, almostEpoch); ps.setTimestamp(4, almostEpoch, utc);這又是我在CET / CEST上獲得的東西
1970-01-01 00:00:00.0 / -3600000 1970-01-01 00:00:00.0 / -3600000 1970-01-01 00:00:00.0 / -3600000 1970-01-01 00:00:00.0 / -3600000即不是Epoch,而是我首先發(fā)送到服務(wù)器的時間戳文字。 請注意,綁定/獲取的四種組合仍然始終產(chǎn)生相同的時間戳。
讓我們看看如果寫入數(shù)據(jù)庫的會話使用與從數(shù)據(jù)庫中獲取會話不同的時區(qū)(假設(shè)您在PST中)(我再次使用CET或UTC),會發(fā)生什么情況。 我正在運行此程序:
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));Calendar pst = Calendar.getInstance(TimeZone.getTimeZone("PST"));try (PreparedStatement ps = c.prepareStatement("select"+ " ?::timestamp,"+ " ?::timestamp,"+ " ?::timestamp with time zone,"+ " ?::timestamp with time zone" )) {ps.setTimestamp(1, new Timestamp(0), pst);ps.setTimestamp(2, new Timestamp(0), pst);ps.setTimestamp(3, new Timestamp(0), pst);ps.setTimestamp(4, new Timestamp(0), pst);try (ResultSet rs = ps.executeQuery()) {rs.next();System.out.println(rs.getTimestamp(1)+ " / " + rs.getTimestamp(1).getTime());System.out.println(rs.getTimestamp(2, utc)+ " / " + rs.getTimestamp(2, utc).getTime());System.out.println(rs.getTimestamp(3)+ " / " + rs.getTimestamp(3).getTime());System.out.println(rs.getTimestamp(4, utc)+ " / " + rs.getTimestamp(4, utc).getTime());} }它產(chǎn)生以下輸出:
1969-12-31 16:00:00.0 / -32400000 1969-12-31 17:00:00.0 / -28800000 1970-01-01 01:00:00.0 / 0 1970-01-01 01:00:00.0 / 0第一個時間戳記是將Epoch存儲為PST(16:00),然后數(shù)據(jù)庫中刪除了時區(qū)信息,這將Epoch變成了您在Epoch處的本地時間(-28800秒/ -8h),即真正存儲。
現(xiàn)在,當(dāng)我從自己的時區(qū)CET獲取該時間時,我仍然想要獲取當(dāng)?shù)貢r間(16:00)。 但是在我的時區(qū)中,這不再是-28800秒,而是-32400秒(-9h)。 夠古怪嗎?
當(dāng)我獲取存儲的本地時間(16:00)時,事情發(fā)生了相反的變化,但是我強迫獲取發(fā)生在UTC中,這將產(chǎn)生您存儲的時間戳,最初是PST(-28800)秒)。 但是,在我的時區(qū)CET中打印此時間戳(-28800秒)時,現(xiàn)在是17:00。
當(dāng)我們在數(shù)據(jù)庫中使用TIMESTAMP WITH TIME ZONE數(shù)據(jù)類型時,將保持時區(qū)(PST),并且當(dāng)我獲取Timestamp值時,無論使用CET還是UTC,我仍然會得到Epoch,它已安全地存儲到了數(shù)據(jù)庫,在CET中打印為01:00。
ew。
TL; DR:
使用jOOQ時 ,如果正確的UTC時間戳對您很重要,請使用TIMESTAMP WITH TIMEZONE,但是您必須實現(xiàn)自己的數(shù)據(jù)類型Binding ,因為jOOQ當(dāng)前不支持該數(shù)據(jù)類型。 一旦使用了自己的數(shù)據(jù)類型Binding,就可以使用Java 8的time API,它比java.sql.Timestamp +丑陋的Calendar更好地表示了這些不同的類型。
如果當(dāng)?shù)貢r間對您很重要,或者您不在跨時區(qū)工作,則可以使用TIMESTAMP和jOOQ的Field <Timestamp>。
幸運的是,如果您像我一樣,可以在一個只有一個時區(qū)的很小的國家/地區(qū)進行操作,而大多數(shù)本地軟件都不會遇到此問題。
翻譯自: https://www.javacodegeeks.com/2015/07/whats-even-harder-than-dates-and-timezones-dates-and-timezones-in-sql-jdbc.html
總結(jié)
以上是生活随笔為你收集整理的什么比日期和时区更难? SQL / JDBC中的日期和时区!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JAX-RS 2.x与Spring MV
- 下一篇: DMLC深盟分布式深度机器学习开源平台解