网站Logo 苏叶的belog

SpringBoot时间格式化问题

wdadwa
0
2026-03-05

一、为什么需要统一时间处理

在后端开发中,时间处理经常出现问题,例如:

常见问题:

1 前端传来的时间解析失败
2 GET 参数时间解析失败
3 返回给前端的时间格式不统一
4 LocalDateTime 无法解析
5 时区错乱(+8 / UTC)
6 Jackson 返回时间戳

根本原因是:

SpringBoot 中时间处理是由多个组件协同完成的

主要涉及三个组件:

组件作用
SpringMVC处理请求参数
JacksonJSON 序列化 / 反序列化
JDK 时间 APIDate / LocalDateTime

二、SpringBoot 时间处理完整流程

在 Spring Boot 中,时间处理分为 三种场景

场景示例处理组件
GET 请求参数/test?time=2026-03-05SpringMVC
POST JSON{time:"2026-03-05"}Jackson
返回 JSONreturn objectJackson

完整流程:

请求 → Controller

GET参数
URL → SpringMVC → ConversionService → Java对象

POST JSON
JSON → Jackson → Java对象

返回JSON
Java对象 → Jackson → JSON

所以:

GET 参数 → @DateTimeFormat
JSON 解析 → @JsonFormat

三、SpringBoot 支持的时间类型

企业开发推荐使用 JDK8 时间 API

类型是否推荐说明
Date不推荐老 API
Calendar不推荐复杂
LocalDate推荐日期
LocalTime推荐时间
LocalDateTime推荐日期+时间
Instant推荐时间戳

推荐:

LocalDateTime

原因:

线程安全
API 更清晰
支持时区

四、常用时间注解

SpringBoot 时间解析常用两个注解。

@DateTimeFormat

作用:用于 SpringMVC 参数绑定

适用于:

GET
Query参数
Form表单

示例:

public class TestDate {

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime time;

}

请求:

GET /test?time=2026-03-05 12:00:00

@JsonFormat

作用:用于 JSON 序列化 / 反序列化

由 Jackson 处理。

示例:

public class TestDate {

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime time;

}

请求:

{
  "time":"2026-03-05 12:00:00"
}

五、SpringBoot 默认时间格

SpringBoot 默认:LocalDateTime

返回:2026-03-05T12:00:00

因为:ISO-8601 标准

但企业通常要求:

yyyy-MM-dd HH:mm:ss

所以需要 全局配置

六、全局时间格式配置

企业开发推荐:

统一全局时间格式
避免每个字段写注解

application.yml 配置

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      WRITE_DATES_AS_TIMESTAMPS: false

作用:

配置作用
date-formatDate 类型格式
time-zone时区
WRITE_DATES_AS_TIMESTAMPS禁止时间戳

注意:

这个配置只影响 java.util.Date

不会影响:LocalDateTime

JDK8 时间全局配置

需要自定义 Jackson 配置。

@Configuration
public class JacksonConfig {

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {

        return builder -> {

            JavaTimeModule module = new JavaTimeModule();

            DateTimeFormatter dateTimeFormatter =
                    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

            DateTimeFormatter dateFormatter =
                    DateTimeFormatter.ofPattern("yyyy-MM-dd");

            DateTimeFormatter timeFormatter =
                    DateTimeFormatter.ofPattern("HH:mm:ss");

            module.addSerializer(LocalDateTime.class,
                    new LocalDateTimeSerializer(dateTimeFormatter));

            module.addDeserializer(LocalDateTime.class,
                    new LocalDateTimeDeserializer(dateTimeFormatter));

            module.addSerializer(LocalDate.class,
                    new LocalDateSerializer(dateFormatter));

            module.addDeserializer(LocalDate.class,
                    new LocalDateDeserializer(dateFormatter));

            module.addSerializer(LocalTime.class,
                    new LocalTimeSerializer(timeFormatter));

            module.addDeserializer(LocalTime.class,
                    new LocalTimeDeserializer(timeFormatter));

            builder.modules(module);

            builder.timeZone(TimeZone.getTimeZone("GMT+8"));
        };
    }
}

七、GET 请求时间全局配置

GET 参数由 SpringMVC 解析。

可以全局配置:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {

        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();

        registrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        registrar.setDateTimeFormatter(
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

        registrar.registerFormatters(registry);
    }
}

这样:

GET /test?time=2026-03-05 12:00:00

即可自动解析。

八、实体类示例

推荐写法:

public class TestDate {

    private Integer id;

    private LocalDateTime time;

}

Controller:

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping("/get")
    public TestDate get(TestDate date){
        return date;
    }

    @PostMapping("/post")
    public TestDate post(@RequestBody TestDate date){
        return date;
    }

}

返回结果:

{
  "id":1,
  "time":"2026-03-05 12:00:00"
}

九、推荐规范

项目一般遵循以下规范:

  1. 时间类型

    统一使用:

    LocalDateTime
    

    禁止:

    Date
    Calendar
    
  2. 时间格式

    统一格式:

    yyyy-MM-dd HH:mm:ss
    
  3. 时区

    统一使用

    GMT+8
    

    或者

    UTC
    
  4. 统一 JSON 序列化

    JacksonConfig
    

十、常见时间坑

10.1 返回时间戳

错误:

1700000000000

原因:

WRITE_DATES_AS_TIMESTAMPS = true

解决:

WRITE_DATES_AS_TIMESTAMPS: false

10.2 LocalDateTime 无法解析

原因:

未配置 JavaTimeModule

解决:

JacksonConfig

10.3 GET 参数解析失败

错误:

Failed to convert value

原因:

没有 @DateTimeFormat

或未配置 Formatter。

10.4 时区错乱

表现:

数据库时间正确
接口返回时间 +8 小时

原因:

Jackson 默认 UTC

解决:

spring.jackson.time-zone=GMT+8

十一、时间处理架构

最终架构:

                请求
                 │
                 ▼
           Controller
          /           \
         /             \
 GET 参数解析        JSON解析
   │                   │
SpringMVC         Jackson
ConversionService ObjectMapper
         \             /
          \           /
           ▼         ▼
             Java对象
                 │
                 ▼
             返回JSON
                 │
                 ▼
              Jackson
动物装饰