SpringBoot中 Jackson 日期的時區和日期格式問題

目錄

1、使用場景

1.1、數據庫MySQL也是有時區的概念的。

1.2、系統時區意味着與計算機的操作系統時區相同。

1.2、SpringBoot默認的Json視圖轉換框架Jackson也有時區概念

2、代碼實現

2.1、解決方案一下在每個帶有日期地方加上註解

2.2、只需要配置一個bean實現整體修改

2.3、使用SpringBoot的配置方式

3、成果展現

4、總結


1、使用場景

        因爲最近項目需要國際化,需要能夠支持多種國際化語言,目前需要支持三種(法語、英語、簡體中文)。我們的項目部署環境爲使用阿里雲(德國)節點。以前我們項目主要用戶在中國國內。一部署到德國服務器節點就出現一個問題了。數據返回的時間不對,存儲的時間也有時差了。此文章僅僅與UTC標準時間與北京時間(東八區時間)作爲實際例子。最後跟蹤發現,如下幾點原因:

1.1、數據庫MySQL也是有時區的概念的。

     通過如下命令可以查詢MySQL的時區

 show variables like "%time_zone%";

如果未做任何修改會顯示如下:

+------------------+--------+
| Variable_name  | Value |
+------------------+--------+
| system_time_zone | CST  |
| time_zone    | SYSTEM |
+------------------+--------+
2 rows in set (0.00 sec)
#time_zone說明mysql使用system的時區,system_time_zone說明system使用CST時區

1.2、系統時區意味着與計算機的操作系統時區相同。

以下是我們北京時間使用MySQL時區

 set global time_zone = '+8:00'; ##修改mysql全局時區爲北京時間,即我們所在的東8區
> set time_zone = '+8:00'; ##修改當前會話時區
> flush privileges; #立即生效

或者通過修改MySQL的 my.cnf配置文件來修改時區
# vim /etc/my.cnf ##在[mysqld]區域中加上
default-time_zone = '+8:00'
# /etc/init.d/mysqld restart ##重啓mysql使新時區生效

1.2、SpringBoot默認的Json視圖轉換框架Jackson也有時區概念

     Jackson日期反序列化時區問題,Jackson裏 JsonFormat的源碼

/**
 * Value that indicates that default {@link java.util.TimeZone}
 * (from deserialization or serialization context) should be used:
 * annotation does not define value to use.
 *<p>
 * NOTE: default here does NOT mean JVM defaults but Jackson databindings
 * default, usually UTC, but may be changed on <code>ObjectMapper</code>.
 */
public final static String DEFAULT_TIMEZONE = "##default";

值,該值指示默認{@鏈接java.util.TimeZone}

(來自反序列化或序列化上下文)應使用:

註釋未定義要使用的值。

注意:這裏的默認值並不意味着JVM默認值,而是Jackson數據綁定。

默認值,通常爲UTC,但可以在<code>objectmapper<code>上更改。

那個註釋已經說明默認情況下會將 時區設置爲UTC ,Jackson反序列化時間類型的底層實際上調用的是Java的 SimpleDateFormat#parse() 方法,而JVM中的時區則會根據你的操作系統來獲取,所以JVM認爲你的時區應該是 GMT+8 時區,
而要將 UTC 時區的時間轉成 GMT+8 時區的時間,就會將你傳進來的時間+8個小時。

2、代碼實現

2.1、解決方案一下在每個帶有日期地方加上註解

日期類型的字段上的 @JsonFormat 加上屬性 timezone="GMT+8"

@NotNull
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
@JsonProperty("start_time")
private Date startTime;

此類方法需要在包含日期地方都加上註解屬性,比較繁瑣。

2.2、只需要配置一個bean實現整體修改

@Bean
    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
        return jacksonObjectMapperBuilder ->
                jacksonObjectMapperBuilder.timeZone(TimeZone.getTimeZone("GMT+8"));
    }

參考文章:Jackson日期反序列化時區問題

2.3、使用SpringBoot的配置方式

spring.jackson.default-property-inclusion=NON_NULL
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

第一個設置就是使用24小時的時間格式;第二個設置就是設置時區爲東八區。

但是配置時候需要注意

Finally, if you opt out of the Spring Boot default MVC configuration by providing your own @EnableWebMvc configuration, you can take control completely and do everything manually by using getMessageConverters from WebMvcConfigurationSupport.

《Spring Boot Reference Guide》 

需要去掉

@EnableWebMvc

參考文章:

           SpringBoot全局Jackson配置未生效  

           spring boot中jackson時間格式和東八區的設置

           自定義jackson解析時間格式yyy-MM-dd HH:mm:ss

3、成果展現

        經過轉換配置轉換之後;能夠正確的獲得和存取對應的時間,建議使用

        2.2、只需要配置一個bean實現整體修改 或者使用 2.3、使用SpringBoot的配置方式 方式比較通用性。

其中如果使用FastJson轉換也可能遇見同樣的問題,可以參考文章

springmvc 中使用fastjson 反序列化json,導致時區相差的問題

4、總結

       在SpringBoot開發應用之中設計日期轉換需要特別注意,能夠主要目標能夠是的存儲和返回的日期能夠對應上自己的本地時區。同時能夠使用較爲通用的轉換方式解決相關問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章