引言
=這幾天參與公司新項目,新項目存在多時區問題,新手上路一臉懵逼,特此總結一下。
服務器時區
多時區項目解決爲了時間上的統一,服務器統一UTC時間方案。
在本地敲代碼的時候,修改本地設置爲UTC環境。
IDEA使用的時候可以通過設置右上角的Edit Configurations…在Environment選項下的VM options一欄內加上VM設置:
-Duser.timezone=GMT+0
因此在項目內只能通過時間戳來進行時間處理。客戶端將時間戳轉化爲對應的客戶端機器所在地區的時間來展示給用戶即可。
數據庫時區問題
在MySQL數據庫,時間存儲有date,datetime,timestamp幾種常用。
datetime
- 佔用8個字節
- 允許爲空值,可以自定義值,系統不會自動修改其值。
- 實際格式儲存(Just stores what you have stored and retrieves the same thing which you have stored.)
- 與時區無關(It has nothing to deal with the TIMEZONE and Conversion.)
- 可以在指定datetime字段的值的時候使用now()變量來自動插入系統的當前時間。
結論:datetime類型適合用來記錄數據的原始的創建時間,因爲無論你怎麼更改記錄中其他字段的值,datetime字段的值都不會改變,除非你手動更改它。
timestamp
- 佔用4個字節
- 允許爲空值,但是不可以自定義值,所以爲空值時沒有任何意義。
- TIMESTAMP值不能早於1970或晚於2037。這說明一個日期,例如’1968-01-01’,雖然對於DATETIME或DATE值是有效的,但對於TIMESTAMP值卻無效,如果分配給這樣一個對象將被轉換爲0。
- 值以UTC格式保存( it stores the number of milliseconds)
- 時區轉化 ,存儲時對當前的時區進行轉換,檢索時再轉換回當前的時區。
- 默認值爲CURRENT_TIMESTAMP(),其實也就是當前的系統時間。
- 數據庫會自動修改其值,所以在插入記錄時不需要指定timestamp字段的名稱和timestamp字段的值,你只需要在設計表的時候添加一個timestamp字段即可,插入後該字段的值會自動變爲當前系統時間。
- 默認情況下以後任何時間修改表中的記錄時,對應記錄的timestamp值會自動被更新爲當前的系統時間。
- 如果需要可以設置timestamp不自動更新。通過設置DEFAULT CURRENT_TIMESTAMP 可以實現。
TIMESTAMP和DATETIME的相同點:
兩者都可用來表示YYYY-MM-DD HH:MM:SS[.fraction]類型的日期。
TIMESTAMP和DATETIME的不同點:
兩者的存儲方式不一樣
對於TIMESTAMP,它把客戶端插入的時間從當前時區轉化爲UTC(世界標準時間)進行存儲。查詢時,將其又轉化爲客戶端當前時區進行返回。
而對於DATETIME,不做任何改變,基本上是原樣輸入和輸出。
兩者所能存儲的時間範圍不一樣
timestamp所能存儲的時間範圍爲:‘1970-01-01 00:00:01.000000’ 到 ‘2038-01-19 03:14:07.999999’。畢竟是時間戳嘛。
datetime所能存儲的時間範圍爲:‘1000-01-01 00:00:00.000000’ 到 ‘9999-12-31 23:59:59.999999’。
所以我覺得datetime要好用些。不過也看具體業務情況吧。
代碼中轉化問題
字符串接收時間參數
在spring項目裏面,可以通過以下設置來接收,但是這種方式就是相當於服務器的時區固定。
1.在需要設置時區的屬性上加註解@JsonFormat(pattern=“yyyy-MM-dd HH:mm:ss”,timezone=“GMT+0”),這隻針對單個屬性字段.
2.全局設置
在 application.properties 文件裏面添加 spring.jackson.time-zone=GMT+0.
@RequestMapping(value = "/xxx", method = RequestMethod.GET)
public CommonResponse getXxx(@RequestParam(value = "beginTime") String beginTimeText,
@RequestParam(value = "endTime") String endTimeText) {
DateTime beginTime = DateTime.parse(beginTimeText).withZone(DateTimeZone.UTC);
DateTime endTime = DateTime.parse(endTimeText).withZone(DateTimeZone.UTC);
...
}
後面再繼續寫吧,累了