java日期時區問題


Java時區問題小記

問題是在公司項目中出現的,為了簡單描述問題,我簡單寫了下demo,只描述問題部分。

基本情況

項目為微服務架構,我們的服務A接收第三方的報文(字符串)。解析后,傳入自己的服務B,服務B在校驗身份證和出生日期的時候。提示“出生日期和身份證號不符”。檢查發現是生日字段出現問題。當時推斷為時區問題,導致時間錯位,日期減一。

時區問題初現

一開始項目代碼中沒做時區配置。唯一一處是數據庫鏈接url上(這里有用,后面再說)

jdbc:mysql://127.0.0.1:3306/date_cdt?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

首先創建一個項目中DTO對象

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;

import java.util.Date;

@Data
public class DateCDT {

    /**
     * 這里用字符串接收postman傳入的日期信息,然后手動解析,保存到date字段。
     */
    private String dateStr;

    /**
     * 一開始只配置了日期格式,未配置時區
     */
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date date;
}

這里模擬服務A和服務B。

服務A端口:9090

服務B端口:9091

服務A的Controller:


import com.itlaonong.demo.datecdt.client.LastDateClient;
import com.itlaonong.demo.datecdt.dto.DateCDT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@RestController
@RequestMapping("/date")
public class DateController {
    @Autowired
    private LastDateClient lastDateClient;

    @PostMapping
    public DateCDT test(@RequestBody DateCDT dateCDT) throws ParseException {
        String dateStr = dateCDT.getDateStr();
        //第一步獲取日期字符串轉成Date對象
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
        Date date = simpleDateFormat.parse(dateStr);
        dateCDT.setDate(date);
        // 轉換后調用服務B
        return lastDateClient.test(dateCDT);
    }
}

服務B的Controller:

import com.itlaonong.demo.datecdt.dao.DateTestRepository;
import com.itlaonong.demo.datecdt.dto.DateCDT;
import com.itlaonong.demo.datecdt.entity.DateTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

@RestController
@RequestMapping("/date")
public class DateController {

    @Autowired
    private DateTestRepository dateTestRepository;

    @PostMapping
    public DateCDT test(@RequestBody DateCDT dateCDT) {
        //轉成內部的EO后保存數據庫
        Date date = dateCDT.getDate();
        DateTest dateTest = new DateTest();
        dateTest.setDate(date);
        dateTest = dateTestRepository.save(dateTest);
        dateCDT.setDate(dateTest.getDate());
        //這里原先為調用其他服務進行校驗,現在直接返回,可以通過postman中結果查看
        return dateCDT;
    }
}

postman測試情況

date_cdt_2.png

可以看到傳入的是19911103,返回的卻是1991-11-02,出現的日期錯誤的情況。

當時用的方案是給DTO加上時區配置,如下:

@Data
public class DateCDT {

    private String dateStr;

    @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
    private Date date;
}

重新測試

date_cdt_3.png

現在發現日期沒有問題了。

問題再現

前面貌似解決了時區導致日期錯亂問題,但是測試中發現還是會出現部分日期錯亂問題。

date_cdt_1.png

這次通過debug代碼,發現出問題的日期 我們在服務A解析字符串轉換成Date對象時時區顯示為CDT,正常的為CST。查找資料發現,這個是夏令時問題,我國在1986-1991年期間實行過夏令時。

網上尋找解決辦法,找到這篇博客

采用博客中的方案,我給啟動類加入了如下代碼:

TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));

於是啟動代碼為:

public static void main(String[] args) {
    TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
    SpringApplication.run(Application.class, args);
}

然后發現,結果又正常了。

date_cdt_4.png

問題又又又出現了。

結果過了一段時間,問題又出現了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM