[Java] LocalDateTime toString() 00초 일 때 발생한 문제

2024. 1. 5. 23:36☕️ Java

 

문제 상황

알림 메시지 테스트 중 발견한 문제.

가장 최근도착한 알림의 활동 시간(ex. n초 전, n시간 전)이 업데이트되지 않는 현상을 발견했다.

문제의 0초 전

 

앱을 껐다 켜도 여전히 가장 최신 알림의 0초 전은 변하지 않았다.

곧바로 해당 알림이 적재된 테이블을 확인했다. 해당 시간은 테이블의 데이터가 생성되는 순간(created_date) 를 기준으로 표시된다.

 

문제의 데이터

위의 하이라이트 된 부분이 문제의 알림 데이터다.

해당 데이터베이스는 mysql 을 사용중이고 created_date 컬럼은 datetime 타입이다.

솔직히 해당 데이터의 초단위(00)를 보자마자 느낌이 싸했다. 설마..

 

해당 데이터가 api response 로는 어떤 형태로 나가는지 확인하면, 대충 아래 이미지다.

 

 

초가 생략된 문자열이 나가기 때문에, 이를 표시해주는 클라이언트 단()에서 적절한 datetime 을 표시하지 못한것이라 추론했다.

그렇담 00초일땐 왜 초가 생략된 데이터로 출력되는지 확인해보자.

 

// createDate 를 문자열로 파싱하는 부분
public String getCreatedDate() {
    return this.createdDateTime.toString();
}

 

코드 상으로 의심되는 부분은 toString() 메서드다. 확인해보자.

 

LocalDateTime.java 의 toString() 메서드

    /**
     * Outputs this date-time as a {@code String}, such as {@code 2007-12-03T10:15:30}.
     * <p>
     * The output will be one of the following ISO-8601 formats:
     * <ul>
     * <li>{@code uuuu-MM-dd'T'HH:mm}</li>
     * <li>{@code uuuu-MM-dd'T'HH:mm:ss}</li>
     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSS}</li>
     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSS}</li>
     * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li>
     * </ul>
     * The format used will be the shortest that outputs the full value of
     * the time where the omitted parts are implied to be zero.
     *
     * @return a string representation of this date-time, not null
     */
    @Override
    public String toString() {
        return date.toString() + 'T' + time.toString();
    }

 

위 주석에 초가 생략된 이유가 숨어있다.

format used will be the shortest ... omitted parts are implied to be zero

즉 0으로 암시되는 시간이라면 가장 짧은(shortest)형태로 표시된다. 때문에 2023-11-28T13:14:00 처럼 0초의 시간 표현은 축약된 형태로 출력되기 때문에 2023-11-28T13:14 으로 출력된 것이다.

 

해결

간단하게 toString() 메서드를 제거하여 해결했다.

Springboot 에서는 DTO를 통해 클라이언트에 데이터를 전송할 때 LocalDateTime을 문자열로 변환하는 것은 직렬화 설정을 어떻게 했느냐에 따라 달라진다. 현재는 기본 직렬화 설정(Default Serialization)으로 @JsonFormat 어노테이션이나 글로벌 설정을 하지 않았다. 그렇다면 Jackson 라이브러리는 ISO-8601 포맷을 사용해 LocalDateTime 을 직렬화 한다. ISO-8601은 날짜와 시간을 표현하는 국제 표준으로, JSON 직렬화를 비롯한 다양한 애플리케이션에서 널리 사용되고 있다.

 

ISO-8601에서 날짜와 시간을 표현하는 형식은 다음과 같다.

YYYY-MM-DDTHH:mm:ss

 

따라서 "2023-11-28T13:14:00"를 나타내는 LocalDateTime 객체는 ISO-8601 형식의 문자열 "2023-11-28T13:14:00"로 직렬화 된다.

"2023-11-28T13:14:00"