1986年4月,中国中央有关部门发出“在全国范围内实行夏时制的通知”,具体做法是:每年从四月中旬第一个星期日的凌晨2时整(北京时间),将时钟拨快一小时,即将表针由2时拨至3时,夏令时开始;到九月中旬第一个星期日的凌晨2时整(北京夏令时),再将时钟拨回一小时,即将表针由2时拨至1时,夏令时结束。从1986年到1991年的六个年度,除1986年因是实行夏时制的第一年,从5月4日开始到9月14日结束外,其它年份均按规定的时段施行。在夏令时开始和结束前几天,新闻媒体均刊登有关部门的通告。1992年起,夏令时暂停实行。

夏令时具体时间分布

开始时间-结束时间
1986年5月4日至9月14日(1986年因是实行夏令时的第一年,从5月4日开始到9月14日结束)
1987年4月12日至9月13日
1988年4月10日至9月11日
1989年4月16日至9月17日
1990年4月15日至9月16日
1991年4月14日至9月15日

问题复现

创建实体

我们先创建一个简单的实体类,并只有一个Date类型的属性用于示范

public class Test implements Serializable {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date date;
    
    public Date getDate() {
        return date;
    }
    
    public void setDate(Date date) {
        this.date = date;
    }
}

创建controller

@RestController
public class TestController {
    @RequestMapping("/test")
    public Test test(){
        // 1986-09-14
        Date date = new Date(527007600000L);
        Test test = new Test();
        test.setDate(date);
        return test;
    }
}

发送请求测试

url:http://127.0.0.1:8080/test

响应报文:

{
    "date": "1986-09-13 23:00:00"
}

在使用GMT+8时区时,因为夏令时原因会导致相对于正确的时间会少一个小时

解决方案

将注解上的时区改为 Asia/Shanghai

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "Asia/Shanghai")

修改springboot项目全局时区为 Asia/Shanghai

spring:
  jackson:
    time-zone: Asia/Shanghai
    date-format: yyyy-MM-dd HH:mm:ss

项目启动时注入本机时区

@Configuration
public class JackSonConfig {
    /**
     * 时区配置
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
    {
        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
    }
}