[Spring] 날짜/시간 처리하기 (@DateTimeFormat vs @JsonFormat)

2025. 1. 8. 18:53·spring

스프링부트

 

스프링 애플리케이션을 개발하다 보면, 클라이언트로부터 날짜/시간을 파라미터나 JSON으로 입력받거나, 다시 응답으로 내려주는 경우가 자주 있습니다.
이때 Spring MVC와 Jackson(스프링에서 기본적으로 사용하는 JSON 직렬화 라이브러리)에서 제공하는 어노테이션인

  • @DateTimeFormat
  • @JsonFormat

을 활용하면, 날짜/시간을 특정 포맷으로 편리하게 다룰 수 있습니다.

그렇지만 둘의 역할이 미묘하게 달라 의도치 않은 혼란이 생길 수도 있습니다.


1. 예시 코드

1.1. 컨트롤러

@RestController
@RequestMapping("/date")
public class DateFormatController {
	@GetMapping("/body")
	public DateDto getDateBody(@RequestBody DateDto dateDto) {
		System.out.println(dateDto);
		return dateDto;
	}
	
	@GetMapping("/query")
	public DateDto getDateQuery(@ModelAttribute DateDto dateDto) {
		System.out.println(dateDto);
		return dateDto;
	}
}

 

1.2. DTO

@Data
@NoArgsConstructor
public class DateDto {
	private String data;
	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
	@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
	private LocalDateTime localDateTime;
	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private LocalDate localDate;
}

여기서 @DateTimeFormat와 @JsonFormat을 같이 사용하면 에러가 발생해 둘중 1개만 사용!!


2. @DateTimeFormat은 언제 쓰는 걸까?

Spring MVC(특히 Controller 레벨)에서 쿼리 파라미터, PathVariable, Form 데이터 등으로 들어오는 문자열을
Java의 날짜 타입(LocalDate, LocalDateTime 등)으로 변환할 때 쓰입니다.

 

예시)

 

GET /date/query?data=test&localDateTime=2025-01-01 10:05:30&localDate=2025-01-01

와 같은 쿼리 파라미터를 보내면

 

  • localDateTime -> LocalDateTime("2025-01-01T10:10:10")
  • localDate -> LocalDate("2025-01-01")
    로 매핑됩니다.

 

쿼리 파라미터 요청

 

중요: @DateTimeFormat은 JSON 직렬화/역직렬화 관점에서는 관여하지 않습니다.
즉, JSON Body로 요청을 받을 때(예: @RequestBody),
@DateTimeFormat만으로는 포맷 지정이 안 될 수 있으며, Jackson의 내부 기본 전략에 따라 처리됩니다.


3. @JsonFormat은 언제 쓰는 걸까?

Jackson(스프링에서 JSON 직렬화에 사용)에 의해 JSON -> 객체 또는 객체 -> JSON 변환 시,
날짜/시간 포맷을 지정하고 싶을 때 사용합니다.

 

예시)

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;

라고 하면,

 

 

  • 클라이언트에서 {"localDateTime": "2025-01-01 10:05:30"}라는 JSON을 전송할 때 Jackson이 해당 문자열을 LocalDateTime으로 파싱
  • 서버에서 응답을 보낼 때도 "yyyy-MM-dd HH:mm:ss" 포맷의 문자열로 직렬화

 

하지만 스프링 MVC의 쿼리 파라미터 바인딩과는 무관하며, 오직 JSON 변환에만 관여합니다.


4. 그럼 동시에 쓰면 어떻게 될까?

예를 들어,

@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;

와 같이 동일 필드에 @DateTimeFormat과 @JsonFormat을 함께 지정하는 경우,

  • 내부 매핑 로직에서 충돌이 발생하거나
  • Jackson이 자기 방식대로 포맷을 처리하는 등
    에러를 일으킬 수 있습니다.

특히 Spring Boot 버전, Jackson 버전 등에 따라 처리가 다르게 동작하기도 하고,
@RequestBody로 JSON을 받을 때와 @ModelAttribute로 파라미터를 받을 때 적용 경로가 달라지므로,
예기치 않은 문제가 생길 가능성이 높습니다.

따라서 동일 필드에는 보통 한 가지 어노테이션만 적용하는 게 안전하며,
JSON 전용이면 @JsonFormat, 쿼리 파라미터 전용이면 @DateTimeFormat 을 사용합니다.


5. 마무리: ZonedDateTime, 타임존까지 고려해야 한다면?

만약 날짜/시간을 다룰 때 특정 타임존(예: Asia/Seoul)이 필요한 경우,

  • @JsonFormat(timezone = "Asia/Seoul")
  • ZonedDateTime / OffsetDateTime 사용
    등을 통해 더 세밀하게 핸들링할 수 있습니다.

다만 본 포스팅에서는 자세히 다루지 않았고, 프로젝트 요구사항에 따라 UTC 고정, 또는 사용자별 타임존 지원 등을 설계해야 합니다.


6. 정리

  • @DateTimeFormat:
    • Spring MVC(GET 파라미터, PathVariable, Form 데이터)에서 문자열 -> 날짜 타입 변환
    • JSON 직렬화/역직렬화에는 영향을 주지 않음
  • @JsonFormat:
    • Jackson에서 JSON (역)직렬화 시 날짜 포맷 지정
    • 쿼리 파라미터 처리에는 관여하지 않음

동일 필드에 두 어노테이션을 동시에 달면 충돌이나 에러가 발생할 수 있으니 주의!

최종적으로, 어떤 방식으로 날짜가 오고 가는지(쿼리 vs JSON) 구분하여 어노테이션을 적용하면,
안정적으로 날짜/시간 변환을 처리할 수 있습니다.

'spring' 카테고리의 다른 글
  • [Spring]파일 업로드 하기
  • [Spring] 이벤트 시스템으로 느슨한 결합 구현하기
  • [Spring] DTO 유효성 검사(Validation) : @Valid로 처리하기
  • [Spring] profile 환경 분리하기
당훈이
당훈이
당훈이 님의 블로그 입니다.
  • 당훈이
    당훈IT
    당훈이
  • 전체
    오늘
    어제
    • 분류 전체보기 (40)
      • spring (7)
      • vue.js (8)
      • docker (1)
      • javascript (1)
      • aws (21)
      • database (1)
        • oracle (1)
      • nuxt (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    route53
    nuxt vue
    aws spring
    aws 스프링
    AWS ELB
    ec2 nodejs
    AWS
    ec2 spring 배포
    스프링 배포
    AWS EC2
    nuxt fetch
    중복요청
    aws route53
    nuxt dedupe
    spring boot
    스프링부트
    vue3
    ec2 domain
    EC2
    nuxt cache
    aws domain
    Vue
    ec2 route53
    Spring
    스프링
    nodejs 배포
    elb
    배포
    aws dns
    nuxt usefetch
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
당훈이
[Spring] 날짜/시간 처리하기 (@DateTimeFormat vs @JsonFormat)
상단으로

티스토리툴바