2015-10-26 29 views
7

在我們的Web應用程序中,我們需要顯示並輸入 不同時區的不同國家/地區的日期時間信息。現在,我們爲每個國家/地區維護單獨的Web服務器和單獨的數據庫(Oracle 11g)。在Web應用程序中處理時區

我們計劃將所有內容合併到一個帶有單個數據庫(oracle 11g)的門戶中。 此門戶應在用戶本地時區捕獲/顯示日期和時間。

到目前爲止,我已經搜索了這個,我得到了以下建議。

1)將Web服務器和數據庫服務器的時區設置爲UTC,同時將數據(數據和時間)轉換爲用戶本地時區。

如果你建議這種方法,那麼請澄清以下具體的 問題。

  • 大多數時候我們單獨拍攝日期的時候,是要求它 拍攝日期和時間與永遠的時區一起?

  • while存儲日期和時間,我們需要將用戶本地時間 區域轉換爲javascript/java/oracle中的UTC?

  • 而獲取的日期和時間,我們需要UTC轉換爲用戶
    當地時區查詢本身/ JAVA/Java腳本?

  • 許多地方,我們有報告基於日期列比如今天
    /電流月/日range.how我們可以處理顯示(輸入 - 用戶 本地時區 - 數據庫UTC)?

  • 我們必須使用哪些數據類型用於日期字段 (日期/時間戳/帶時區的時間戳/本地時間爲 區)?

2)捕獲用戶本地時區和UTC的日期和時間。作爲單獨的列存儲,用戶本地時區將用於顯示目的,UTC將用於業務邏輯。

如果你建議這種方法,那麼請澄清以下具體的 問題。

  • 是否常見的做法是存儲用戶本地時區和UTC?

  • 哪一列我必須檢查條件,而基於日期列獲取報告顯示 如今天/當前月/日期範圍?

  • 我們(與本地時間
    區與時區/時間戳日期/時間戳記/時間戳)使用的日期欄
    哪些數據類型?

在此先感謝

+0

如果插入數據的用戶和查詢數據的用戶在不同的時區,您會發現什麼? –

+0

@Gopi你可以重新寫一下倒數第二顆子彈嗎? –

回答

-2

你應該考慮JodaTime和應遵循的第一suggestion.JodaTime有很多類,如LOCALDATE的,LocalDateTime,你可以使用你的不同的使用情況。

3

將TIMESTAMP與本地時區一起使用
如果您希望數據庫自動將 轉換爲數據庫與會話時區之間的時間。

存儲日期和時間精確到小數點後9位。此數據類型對時區差異敏感,爲 。此類型的值在數據庫時區和本地(會話)時區之間自動轉換爲 。當存儲在數據庫中的值爲 時,它們將轉換爲數據庫時區,但不會存儲本地 (會話)時區。當從數據庫檢索到值時,該值將從數據庫時區轉換爲本地(會話)時區。

+0

正如附加內容:'TIMESTAMP WITH LOCAL TIME ZONE'總是在當前用戶會話時區中顯示時間,不需要轉換。 –

+0

@)阿爾伯特愛因斯坦1)我使用JDBC連接oracle數據庫。如何將用戶會話時區設置爲數據庫連接。 – Gopi

+0

@艾爾伯特愛因斯坦2)日期提取是好的。 Oracle將負責轉換。如何處理日期保存。我有許多屏幕與用戶輸入日期(沒有時間)。 – Gopi

12

閱讀問題Daylight saving time and time zone best practices。你的基本上是重複的。在UTC

服務器,通常服務器應該有自己的操作系統設置爲UTC的時區,如果沒有提供使用GMTReykjavík Iceland time zone。您的Java實現可能會將此設置作爲其當前的默認時區。

指定時區

但不依賴於時區被設置爲UTC。系統管理員可以改變它。並且任何JVM中的任何應用程序的任何線程中的任何Java代碼都可以通過調用TimeZone.setDefault在運行時更改JVM的當前默認時區。相反,習慣於通過在Java代碼中傳遞可選參數來始終指定期望的/預期的時區。

我認爲這是一個設計缺陷,任何日期 - 時間框架將使時區可選。隨意選擇會造成無窮無盡的混亂,因爲程序員和其他人一樣,無意識地按照自己的個人時區思考,除非得到提示。所以在日期時間工作中往往沒有注意到這個問題。添加JVM默認值變化的問題。順便說一句,同樣的問題,Locale同樣應該總是明確指定。

UTC

你的業務邏輯,數據存儲和數據交換應該總是在UTC完成。幾乎每個數據庫都有一個功能,用於調整UTC中的任何輸入並以UTC存儲。

向用戶呈現日期時間時,請調整到預期的時區。序列化日期時間值時,請使用ISO 8601字符串格式。具體請參見VickyArora的the Answer for Oracle(我是一個Postgres人)。請務必仔細閱讀文檔,並通過試驗來充分理解數據庫的行爲。在這方面,SQL規範並沒有詳細說明,行爲差異很大。

java。sql

請記住,使用Java和JDBC時,您將使用java.sql.Timestamp和相關數據類型。他們始終使用UTC,自動。未來希望更新JDBC驅動程序以直接使用Java 8及更高版本中構建的java.time框架中定義的新數據類型。

java.time

老班由java.time過時。 學習使用java.time,同時避免使用舊的java.util.Date/.Calendar並使編程生活更愉快。

在更新JDBC driver之前,您可以使用java.time中內置的轉換便利方法。接下來看例子,其中Instant是UTC的時刻,ZonedDateTime是瞬時調整爲time zone

Instant instant = myJavaSqlTimestamp.toInstant(); 
ZoneId zoneId = ZoneId.of("America/Montreal"); 
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant , zoneId); 

要走另一個方向。

java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from(zdt.toInstant()); 

如果您需要原始時區,其存儲

如果您的業務需求考慮原始輸入數據的時區是重要的,要記住,然後商店,明確在你的數據庫中一個單獨的列表。您可以使用offset-from-UTC,但不提供完整的信息。時區是偏移量過去,現在和將來處理異常的一組規則,如Daylight Saving Time。所以proper time zone name是最合適的,比如America/Montreal

日期,只是含糊

你說你收集許多日期僅值,沒有時間的天,沒有時區。 java.time中的類是LocalDate。與LocalTimeLocalDateTime一樣,「本地...」部分意味着沒有特定的位置,所以沒有時區,因此也不是時間軸上的一個點 - 沒有實際意義。

請注意,根據定義,僅限日期的值不明確。在任何特定時刻,日期都會在世界各地變化。例如,在Paris France的午夜之後是新的一天,但在Montréal Québec日期仍然是「昨天」。

通常在商業中某些時區是隱含的,甚至無意識地直覺。對數據點的無意識直覺從長遠來看並不適用,尤其是在軟件方面。更好地明確什麼時區是打算。您可以將預定區域與數據庫表中另一列的日期一起存儲,也可以在編程代碼中進行註釋。我相信它會更好更安全地存儲日期時間值。那麼我們如何將日期轉換爲日期?

通常,新的一天是午夜之後的時刻,即一天中的第一個時刻。您可能認爲這意味着時間爲00:00:00.0,但並非總是如此。 Daylight Saving Time (DST)和其他可能的異常可能會將第一時刻推到另一個wall-clock time。讓java.time確定正在經歷LocalDate類及其atStartOfDay方法的第一個時刻的正確時間。

ZoneId zoneId = ZoneId.of("America/Montreal"); 
LocalDate today = LocalDate.now(zoneId); 
ZonedDateTime todayStart = today.atStartOfDay(zoneId); 

在一些業務環境中,新的一天可能被定義(或假設)爲營業時間。例如,如果出版商New York表示他們在當地時間上午9點說「書籍草稿應在1月2日前到期」。讓我們在那個時區獲取該日期的那個時間。

ZoneId zoneId = ZoneId.of("America/New_York"); 
ZonedDateTime zdt = ZonedDateTime.of(2016 , 1 , 2 , 9 , 0 , 0 , 0 , zoneId); 

這是什麼意思了,筆者在New Zealand工作?通過調用withZoneSameInstant調整爲她的particular time zone以供演示。

ZoneId zoneId_Pacific_Auckland = ZoneId.of("Pacific/Auckland"); 
ZonedDateTime zdt_Pacific_Auckland = zdt.withZoneSameInstant(zoneId_Pacific_Auckland); 

數據庫

對於數據庫存儲我們轉變成一個Instant(一個在UTC的時間軸上的時刻),並通過作爲java.sql.Timestamp如前面上方看到。

java.sql.Timestamp ts = java.sql.Timestamp.from(zdt.toInstant()); 

從數據庫中檢索時,轉換回紐約日期時間。將java.sql.Timestamp轉換爲Instant,然後應用時區ZoneId以獲得ZonedDateTime

Instant instant = ts.toInstant(); 
ZoneId zoneId = ZoneId.of("America/New_York"); 
ZonedDateTime zdt = ZonedDateTime.ofInstant(instant , zoneId); 

如果您database driverJDBC 4.2或更高版本的規定,您可以通過/取java.time類型,而不是直接轉換到/自java.sql類型。嘗試使用PreparedStatement::setObjectResultSet::getObject方法。

+0

您會推薦爲您的本地/測試機器做些什​​麼?在我的情況下,它只是一個普通的計算機,所以將操作系統時間設置爲UTC並沒有什麼意義。另一方面,如果我沒有將操作系統時間設置爲UTC(特別是,我注意到類似resultSet.getTimestamp()的調用根據系統時間進行調整),測試將在本地機器上產生不同(和不正確)的結果。我應該在'ContextListener'中設置'TimeZone.setDefault()'爲UTC嗎? – theyuv

+0

@theyuv重新閱讀我的答案,搜索堆棧溢出,因爲你的問題已經解決了很多次。快速:永遠不要依賴於服務器操作系統或JVM的默認時區,總是通過傳遞可選的'ZoneId'參數在Java代碼中明確指定。切勿使用java.sql'日期時間類(如Timestamp),只使用帶有JDBC 4.2或更高版本驅動程序的java.time類。 *永遠不會*調用'TimeZone.setDefault',因爲這會在運行時(!)立即影響在該JVM中的所有應用程序的所有線程中運行的所有代碼。爲了測試,學習該類中內置的備用「時鐘」實現。 –

2

在這裏我澄清了以下具體問題。

問:大多數時候我們只捕獲日期,是否需要一直捕獲日期和時間以及時區?

A.

問:同時存儲日期和時間,我們需要在用戶本地時區轉換爲UTC在JavaScript/JAVA/ORACLE?

A.不能轉換過程中的數據保存,因爲它保存源日期+時間+區

問:雖然取的日期和時間,我們需要UTC轉換爲用戶 當地時區查詢本身/ java/java腳本?

答。總是轉換爲以當地時區或UTC格式顯示應用程序打開。

我們報告基於日期列今天如 顯示

問:許多地方/電流月/日range.how我們可以處理(輸入 - 用戶本地時區 - 在UTC數據庫)?

答:系統應該提供設置選項給用戶日期時間顯示,格式爲本地,應用程序打開時間或UTC。全部只在前端完成。

問:我們必須使用哪種數據類型作爲日期字段(日期/時間戳/帶時區/時間戳和本地時區的時間戳)?

A.時間戳

因此,在短期,保存源的時區datetime和轉換基於用戶偏好無論是在本地那裏打開的頁面或UTC格式。意思是,轉換將通過腳本完成,僅用於顯示。產品流行的地區也可以找到。

+1

多數民衆贊成好..非常簡化.. –

+1

是啊真的很好的解釋... ... - –

1

我想簡單地變換存儲在數據庫變成Long現有的日期,並持續(ETL過程)這個Long值,與已知的(或扣除)patternLocaleTimeZone(默認元)一起。只要使用默認元,就可以堅持任何新的Date

ETL例如

設說2015-11-29 10:07:49.500 UTC被存儲在DB:

// Known or deducted format of the persisted date 
String pattern = "yyyy-MM-dd HH:mm:ss.SSS"; 
Locale locale = Locale.ENGLISH; 
TimeZone zone = "UTC"; 

// Date to ms 
SimpleDateFormat sdf = new SimpleDateFormat(pattern, locale); 
sdf.setTimeZone(TimeZone.getTimeZone(zone)); 
Date date = sdf.parse(pattern); 

// ETL: Can now be persisted in Long, along with default META (pattern, Locale, TZ) 
Long dateL = date.getTime(); // for e.g. 1448827660720 
... 

的持續Long值也可以在任何其它格式轉換,如果需要的話

pattern     | locale | tz | result 
============================================ 
yyyy/MM/dd    | null  | null | 2015/11/29   
dd-M-yyyy hh:mm:ss  | null  | null | 29-11-2015 10:07:40 
dd MMMM yyyy zzzz  | ENGLISH | null | 29 November 2015 Central European Time 
yyyy-MM-dd HH:mm:ss.SSS | null  | UTC | 2015-11-29 10:07:49 UTC 
0

可行的和合乎邏輯的方法是;將用戶輸入的時間轉換爲GMT/UTC +00並將其存儲在帶有或不帶時區標識符的數據庫中,這並不重要。當你需要顯示用戶將java的GMT/UTC時間轉換爲用戶本地時間的時間時。

相關問題