문서의 이전 판입니다!
java.util.Date
와 신규 Java 8 시간에 대한 처리java.util.Date
는 기본적으로 Unix timestamp(long 값)으로 표현된다.compile('com.fasterxml.jackson.datatype:jackson-datatype-jsr310') compile('com.fasterxml.jackson.datatype:jackson-datatype-jdk8')
@GetMapping("/dateTest") public MyClock dateTest2() { return new MyClock(); } @Getter public static class MyClock { private Date date; private LocalDateTime localDateTime; private LocalDate localDate; private LocalTime localTime; private OffsetDateTime offsetDateTime; private ZonedDateTime zonedDateTime; public MyClock() { Instant instant = Instant.now(); date = Date.from(instant); localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); localTime = localDateTime.toLocalTime(); localDate = localDateTime.toLocalDate(); offsetDateTime = OffsetDateTime.ofInstant(instant, ZoneId.systemDefault()); zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault()); } }
WRITE_DATES_AS_TIMESTAMPS=false
상태로 운영하는 것이다. application.yml
spring.jackson.serialization.write-dates-as-timestamps: false
java.util.Date
,java.time.*
모두 ISO 혹은 그 유사 포맷으로 직렬화된다.{ "date":"2018-07-18T06:16:33.647+0000", ## java.util.Date가 약간 다르게 출력됨. "localDateTime":"2018-07-18T15:16:33.647", "localDate":"2018-07-18", "localTime":"15:16:33.647", "offsetDateTime":"2018-07-18T15:16:33.647+09:00", "zonedDateTime":"2018-07-18T15:16:33.647+09:00" }
WRITE_DATES_AS_TIMESTAMPS
옵션을 변경할 경우 기존에 작동하던 java.util.Date
의 포맷이 변경되므로 프로젝트가 이미 운영중일 때는 java.util.Date
를 받는 모든 부분에 대해 기존 unix timestamp 받던것을 올바로 처리하게 변경해야만 한다.@SpringBootApplication public class DemoApplication implements Jackson2ObjectMapperBuilderCustomizer { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @Override public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) { LocalDateTimeSerializer localDateTimeSerializer = new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME); LocalDateSerializer localDateSerializer = new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE); LocalTimeSerializer localTimeSerializer = new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME); OffsetDateTimeSerializer offsetDateTimeSerializer = new CustomOffsetDateTimeSerializer(); ZonedDateTimeSerializer zonedDateTimeSerializer = new CustomZonedDateTimeSerializer(); jacksonObjectMapperBuilder .simpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX") .serializerByType(LocalDateTime.class, localDateTimeSerializer) .serializerByType(LocalDate.class, localDateSerializer) .serializerByType(LocalTime.class, localTimeSerializer) .serializerByType(OffsetDateTime.class, offsetDateTimeSerializer) .serializerByType(ZonedDateTime.class, zonedDateTimeSerializer); } public static class CustomOffsetDateTimeSerializer extends OffsetDateTimeSerializer { protected CustomOffsetDateTimeSerializer() { super(OffsetDateTimeSerializer.INSTANCE, false, DateTimeFormatter.ISO_OFFSET_DATE_TIME); } } public static class CustomZonedDateTimeSerializer extends ZonedDateTimeSerializer { public CustomZonedDateTimeSerializer() { // ISO_OFFSET_DATE_TIME 로 바꾸면 OffsetDateTime과 동일하게 출력됨. super(ZonedDateTimeSerializer.INSTANCE, false, DateTimeFormatter.ISO_DATE_TIME, true); } } }
{ "date":"2018-07-18T15:11:49.693+09:00", "localDateTime":"2018-07-18T15:11:49.693", "localDate":"2018-07-18", "localTime":"15:11:49.693", "offsetDateTime":"2018-07-18T15:11:49.693+09:00", "zonedDateTime":"2018-07-18T15:11:49.693+09:00[Asia/Seoul]" }
@EnableWebMvc
와 WebMvcConfigurerAdapter
를 사용하는 순간 더이상 SpringBoot가 아니고 Spring 이기 때문에 위의 설정이 먹지 않게 된다.
이때는 WebMvcConfigurerAdapter#configureMessageConverters
를 override 해야한다.
이것은 Jackson JSON 직렬화와는 다른 문제이므로 포맷을 지정해야한다.
@GetMapping("/test") public Result test(@RequestParam("datetime") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime datetime) { // ... } // 파라미터를 ?datetime=2018-07-11T20:22:55.123 형태로 호출