zoukankan      html  css  js  c++  java
  • 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

    问题又又又出现了。

    结果过了一段时间,问题又出现了。

  • 相关阅读:
    [JavaScript-PHP]无刷新Ajax+POST使用阿里云短信平台发送短信
    [PHP]开源php拼音库的使用方法
    redis远程连接不上解决办法
    ServiceStack.Redis连接阿里云redis服务时使用连接池出现的(密码验证)问题
    .Net使用Redis详解之ServiceStack.Redis
    Windows下Redis的使用
    axios文件流下载(excel文件)
    生成线上用https证书,支持通配符和多域名,初学Let's Encrypt用于IIS,纯本地手动
    什么是TXT记录?如何设置、检测TXT记录
    v-cloak 的用法
  • 原文地址:https://www.cnblogs.com/jimmyfan/p/14090538.html
Copyright © 2011-2022 走看看