[英]Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users
我已經閱讀了有關日期操作的所有其他問題,但是似乎都沒有一個令人滿意的答案。
我有一個具有不同地理位置用戶的項目,該項目在某些類和數據中使用Date
。 事實是,我正在尋找一種有效的方式來為不同用戶在各自的時區中操作日期,大多數答案建議使用Joda庫進行Date
操作,由於我仍然沒有發現任何東西,所以這還不太了解您無法使用傳統Java執行此操作,因此,如果有人可以解釋使用傳統Java無法完成的Joda功能 ,那么我可以考慮使用它。
我終於找到了使用System.currentTimeMillis()
將日期保存到數據庫(任何數據庫)中的方法。 這樣可以避免我擔心使用數據庫存儲日期的時區。 如果要在數據庫中查詢特定日期或日期范圍,我將使用要查詢的Date
的long
值執行查詢:
SELECT * FROM table1 WHERE date1>=1476653369000
當檢索ResultSet
我將使用請求數據的用戶所在的時區將從數據庫中檢索到的long
值格式化為可讀的Date
。
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(resultSet.getLong(1));
cal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
Date myDate = cal.getTime();
根據我已閱讀的一些意見,有人強調說,存儲System.currentTimeMillis()
絕對不是最佳實踐,但是由於某些原因,他們都錯過了為什么不推薦這樣做的原因 。 我想念什么嗎? 這是否會導致Long->Date
/ Date->Long
轉換的性能問題? 在數據庫中使用Long
代替Date
時,是否有任何用例無法完成? 有人可以對此發表基本解釋嗎?
另一方面,假設我一直使用Date
值在數據庫中存儲日期,是否有一種方法可以避免在處理數據庫Date
時擔心時區?
提前致謝。
我已經閱讀了有關日期操作的所有其他問答。
不,你肯定沒看過他們所有。
java.util.Date
和java.util.Calendar
)和Joda-Time項目都被java.time類所替代(在'java.s中搜索的結果為1,890個)。時間')。 我會有些簡短,所有這一切都已經覆蓋了很多次了堆棧溢出。
在UTC工作。 在Java中,這意味着通常使用Instant
類。 Instant
類以UTC表示時間軸上的時刻,分辨率為納秒 (最多十進制的九(9)位數字)。
Instant instant = Instant.now();
任何嚴肅的數據庫,例如Postgres,都會以UTC跟蹤日期時間值。 JDBC驅動程序處理從數據庫內部存儲的數據轉換為Java類型的細節。 符合JDBC 4.2及更高版本的JDBC驅動程序可以通過PreparedStatement::setObject
和ResultSet::getObject
方法直接處理java.time類型。
myPreparedStatement.setObject( … , instant );
對於不符合標准的驅動程序,回落到使用的java.sql類型,如java.sql.Timestamp
與數據庫進行通信,並通過加入到老班新方法轉換到/自java.time類型。 數據庫如何處理日期時間值的內部細節可能與java.time的方法完全不同。 在大多數情況下,JDBC驅動程序會向您隱藏所有細節。 但是一個關鍵問題是分辨率,您應該在數據庫中進行研究。 java.time類處理的日期時間的分辨率最高為納秒,但數據庫可能不會。 例如,Postgres使用微秒的分辨率。 因此來回意味着數據丟失。 您想在java.time類上使用截斷方法來匹配您的數據庫。
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) );
因此,不涉及任何時區。 因此,無需“在處理數據庫日期時擔心時區”。
當您想通過某個區域的時鍾時鍾看到同一時刻時 ,請應用ZoneId
來獲取ZonedDateTime
。
ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );
將帶區域的日期時間帶回到數據庫時,請提取Instant
。
Instant instant = zdt.toInstant();
請注意,在任何給定時刻,日期和一天中的時間在全球范圍內隨時區變化。 因此,如果確切的時刻很重要,例如合同到期時,請注意不要使用僅日期的值。 可以將日期時間值用於確切的時刻,或者將預期的時區與僅日期一起存儲,以便稍后可以計算出准確的時刻。
LocalDate ld = LocalDate.of( 2016, 1 , 1 );
// Determine the first moment of 2016-01-01 as it happens in Kolkata.
ZonedDateTime zdt = ld.atStartOfDay( ZoneId.of( "Asia/Kolkata" ) );
Instant instant = zdt.toInstant(); // Adjust to UTC and store.
java.time框架內置於Java 8及更高版本中。 這些類取代了麻煩的舊式舊式日期時間類,例如java.util.Date
, .Calendar
和java.text.SimpleDateFormat
。
現在處於維護模式的Joda-Time項目建議遷移到java.time。
要了解更多信息,請參見Oracle教程 。 並在Stack Overflow中搜索許多示例和說明。 規格為JSR 310 。
在哪里獲取java.time類?
ThreeTen-Extra項目使用其他類擴展了java.time。 該項目為將來可能在java.time中添加內容提供了一個試驗場。 您可以在這里找到一些有用的類,比如Interval
, YearWeek
, YearQuarter
,和更多 。
我可以用Joda做什么,而傳統Java則無法做到
通常情況下,這與使用傳統Java可以做什么或不能做什么有關。 與庫API的工作方式有關的更多信息是如何使您比傳統Java更好地編寫更好(更健壯和更正確)的代碼。
如此之多以至於從Java 8開始,Joda API幾乎被逐字復制/采用,只是更改了程序包名稱並將其合並到Java 8 SE標准庫中。
因此,如果您使用的是Java 8,則應該選擇新的API,否則,您應該考慮使用Joda至少會為您提供一條通向Java 8升級/移植的平穩之路。
一些例子:
toString()
類的東西,因此可以期望序列化/反序列化以最小的努力正確地工作。 Instant
的概念表示“絕對”時間戳,當使用地理分布式系統(系統默認時鍾/時區和DST規則可能不同)或互操作時,該概念非常有用,因為它使用UTC。 編輯添加:
根據我已閱讀的一些意見,有人強調說,存儲
System.currentTimeMillis()
絕對不是最佳實踐,但是由於某些原因,他們都錯過了為什么不推薦這樣做的原因。 我想念什么嗎?
System.currentTimeMillis()
有一些缺點。 最大的缺點是時鍾的類型定義不正確。 它可以是單調時鍾,也可以是受DST和時區限制的時鍾,也可以是UTC時間。 它也不一定是准確的時鍾,實際上並不能保證精確到毫秒。 基本上,將發生什么事情都可以像當前時間一樣進行 。
這意味着,例如,如果您想使用多個服務器來處理傳入請求,則當您不得不考慮在另一個服務器上運行的程序的上下文中使用服務器A
的System.currentTimeMillis()
的輸出時,這將變得很棘手。 B
第二天說。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.