簡體   English   中英

Java最佳實踐,適用於不同地理位置的用戶進行日期處理/存儲

[英]Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users

我已經閱讀了有關日期操作的所有其他問題,但是似乎都沒有一個令人滿意的答案。

我有一個具有不同地理位置用戶的項目,該項目在某些類和數據中使用Date 事實是,我正在尋找一種有效的方式來為不同用戶在各自的時區中操作日期,大多數答案建議使用Joda庫進行Date操作,由於我仍然沒有發現任何東西,所以這還不太了解您無法使用傳統Java執行此操作,因此,如果有人可以解釋使用傳統Java無法完成的Joda功能 ,那么我可以考慮使用它。

我終於找到了使用System.currentTimeMillis()將日期保存到數據庫(任何數據庫)中的方法。 這樣可以避免我擔心使用數據庫存儲日期的時區。 如果要在數據庫中查詢特定日期或日期范圍,我將使用要查詢的Datelong值執行查詢:

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.Datejava.util.Calendar )和Joda-Time項目都被java.time類所替代(在'java.s中搜索的結果為1,890個)。時間')。
  • 您將學到不要將日期時間值跟蹤為從時計數。 由於人類無法理解長整數作為日期時間的含義,因此調試和日志記錄變得非常困難,而bug卻未被發現。 而且由於在各種軟件項目中采用了許多粒度的計數(整秒,毫秒,微秒,納秒,整天等等),並且至少使用了幾十個紀元,因此在數據假設上會造成歧義,並會導致錯誤,誤解和錯誤。混亂。
  • 您將已經學會在數據庫中使用日期時間類型來跟蹤日期時間值。
  • 您將學會在UTC中工作和存儲日期時間值。 僅在邏輯要求或用戶希望演示時調整到時區。 “想全球化,就本地。”
  • 您將了解到,盡管英勇嘗試了行業先機,但傳統的日期時間類設計不良,混亂且麻煩。 請參閱Java日期和時間API有什么問題? 進行一些討論。 Joda-Time是業界第一個好的日期時間庫,它啟發了Java內置於Java 8及更高版本中的java.time類的替換。

我會有些簡短,所有這一切都已經覆蓋了很多次了堆棧溢出。

在UTC工作。 在Java中,這意味着通常使用Instant類。 Instant類以UTC表示時間軸上的時刻,分辨率為納秒 (最多十進制的九(9)位數字)。

Instant instant = Instant.now();

任何嚴肅的數據庫,例如Postgres,都會以UTC跟蹤日期時間值。 JDBC驅動程序處理從數據庫內部存儲的數據轉換為Java類型的細節。 符合JDBC 4.2及更高版本的JDBC驅動程序可以通過PreparedStatement::setObjectResultSet::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.time框架內置於Java 8及更高版本中。 這些類取代了麻煩的舊式舊式日期時間類,例如java.util.Date.Calendarjava.text.SimpleDateFormat

現在處於維護模式Joda-Time項目建議遷移到java.time。

要了解更多信息,請參見Oracle教程 並在Stack Overflow中搜索許多示例和說明。 規格為JSR 310

在哪里獲取java.time類?

  • Java SE 8SE 9及更高版本
    • 內置的
    • 標准Java API的一部分,具有捆綁的實現。
    • Java 9添加了一些次要功能和修復。
  • Java SE 6SE 7
    • java.time的許多功能在ThreeTen- Backport中都被反向移植到Java 6和7。
  • 安卓系統

ThreeTen-Extra項目使用其他類擴展了java.time。 該項目為將來可能在java.time中添加內容提供了一個試驗場。 您可以在這里找到一些有用的類,比如IntervalYearWeekYearQuarter ,和更多

我可以用Joda做什么,而傳統Java則無法做到

通常情況下,這與使用傳統Java可以做什么或不能做什么有關。 與庫API的工作方式有關的更多信息是如何使您比傳統Java更好地編寫更好(更健壯和更正確)的代碼。

如此之多以至於從Java 8開始,Joda API幾乎被逐字復制/采用,只是更改了程序包名稱並將其合並到Java 8 SE標准庫中。

因此,如果您使用的是Java 8,則應該選擇新的API,否則,您應該考慮使用Joda至少會為您提供一條通向Java 8升級/移植的平穩之路。

一些例子:

  • 日期和時間類型的一致API。
  • 日期/時間對象是不可變的,操作會返回表示更改后的值的類型的新實例。 (如Java字符串)。 這使得更容易推理出日期/時間對象的重用。
  • 通過設計避免將DST和時區相關的值/操作與DST和時區不可知的值/操作混合在一起。 這使得編寫一致且正確地工作並且沒有依賴於時區/地區/日期/時間的極端情況的代碼變得容易得多。
  • Sane默認使用toString()類的東西,因此可以期望序列化/反序列化以最小的努力正確地工作。
  • 依賴於文化/語言環境的特殊情況和您尚未意識到的事情(例如,您是否了解傳統的韓國日歷?),這在在語言環境/日歷系統之間轉換日期時間時為您節省了很多麻煩。 另外:豐富的格式化選項。
  • Instant的概念表示“絕對”時間戳,當使用地理分布式系統(系統默認時鍾/時區和DST規則可能不同)或互操作時,該概念非常有用,因為它使用UTC。

編輯添加:

根據我已閱讀的一些意見,有人強調說,存儲System.currentTimeMillis()絕對不是最佳實踐,但是由於某些原因,他們都錯過了為什么不推薦這樣做的原因。 我想念什么嗎?

System.currentTimeMillis()有一些缺點。 最大的缺點是時鍾的類型定義不正確。 它可以是單調時鍾,也可以是受DST和時區限制的時鍾,也可以是UTC時間。 它也不一定是准確的時鍾,實際上並不能保證精確到毫秒。 基本上,將發生什么事情都可以像當前時間一樣進行

這意味着,例如,如果您想使用多個服務器來處理傳入請求,則當您不得不考慮在另一個服務器上運行的程序的上下文中使用服務器ASystem.currentTimeMillis()的輸出時,這將變得很棘手。 B第二天說。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM