![[Spring] java.time.format.DateTimeParseException: Text '2024-05-25 14:33:07.049436' could not be parsed at index 10](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbsezm2%2FbtsIup9RJmU%2FL9Sj8vLTMA3gTzGaq5M8qk%2Fimg.jpg)
[Spring] java.time.format.DateTimeParseException: Text '2024-05-25 14:33:07.049436' could not be parsed at index 10legacy/Spring2024. 7. 9. 23:55
Table of Contents
Redis
Redis에서는 마지막으로 알림이 조회된 시간을 저장한다.
hget Notification:notification lastNotificationTime
"2024-07-09T23:39:39.101337"
@Getter
@RedisHash("Notification")
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class NotificationRedis {
@Id
private String notification; // key
private LocalDateTime lastNotificationTime; // value
public static NotificationRedis of(String notification, LocalDateTime lastNotificationTime) {
return new NotificationRedis(notification, lastNotificationTime);
}
}
서비스 레이어
@Service
@RequiredArgsConstructor
@Slf4j
public class NotificationService {
private final NotificationRepository notificationRepository;
private final NotificationRedisRepository redisRepository;
private final UserRepository userRepository;
private static final String NOTIFICATION = "notification";
@Transactional(readOnly = true)
public List<GetNotificationResponseDto> getNotifications() {
// 알림 조회
NotificationRedis notificationRedis = findNotification();
// Redis에 현재 시간(마지막으로 조회한) 시간을 저장
NotificationRedis notification = createNotification();
redisRepository.save(notification);
return convertDto(notificationRedis);
}
private NotificationRedis findNotification() {
return redisRepository.findById(NOTIFICATION)
.orElse(createNotification());
}
private static NotificationRedis createNotification() {
return NotificationRedis.of(NOTIFICATION, LocalDateTime.now());
}
private List<GetNotificationResponseDto> convertDto(NotificationRedis notificationRedis) {
return notificationRepository.findByIsReadOrCreatedDateAfter(
NotificationStatus.UNREAD, notificationRedis.getLastNotificationTime()).stream()
.map(GetNotificationResponseDto::of)
.toList();
}
}
오류 메시지
분명 로컬 환경에서 API를 작성하고 테스트할 때는 오류가 발생하지 않았는데, 배포된 스웨거를 통해 호출하면 400 오류가 발생하던 것이다. 우리 프로젝트의 경우 액추에이터(Actuator)를 사용하여 에러 로그를 확인하고 있다.
에러 로그를 확인하니 DateTimeParseException 예외가 발생하는데 String -> LocalDateTime으로 파싱하는 과정에서 문제가 있음을 확인했다.
Caused by: java.time.format.DateTimeParseException: Text '2024-05-25 14:33:07.049436' could not be parsed at index 10
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2052) ~[na:na]
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1954) ~[na:na]
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:494) ~[na:na]
at java.base/java.time.LocalDateTime.parse(LocalDateTime.java:479) ~[na:na]
at org.springframework.data.redis.core.convert.Jsr310Converters$BytesToLocalDateTimeConverter.convert(Jsr310Converters.java:104) ~[spring-data-redis-3.2.3.jar!/:3.2.3]
at org.springframework.data.redis.core.convert.Jsr310Converters$BytesToLocalDateTimeConverter.convert(Jsr310Converters.java:100) ~[spring-data-redis-3.2.3.jar!/:3.2.3]
at org.springframework.core.convert.support.GenericConversionService$ConverterAdapter.convert(GenericConversionService.java:358) ~[spring-core-6.1.4.jar!/:6.1.4]
at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41) ~[spring-core-6.1.4.jar!/:6.1.4]
... 188 common frames omitted
해결 방법
몇 시간동안 삽질을 하고 있었는데... 서버에 배포된 redis를 확인해보니 value에 "2024-05-25 14:33:07.049436" 형태로 저장되어 있었다. 서비스 레이어 코드에서 알 수 있듯이 DateTimeFormatter.ISO_LOCAL_DATE_TIME를 사용하고 있는데 이는 "yyyy-MM-ddTHH:mm:ss" 형태로 저장하게 된다.
"2024-05-25 14:33:07.049436"는 "yyyy-MM-ddTHH:mm:ss" 형태에서 'T'가 빠진 포맷이다. 따라서 오류가 발생했던 것이다...
따라서 서버에 배포된 Redis에 저장된 value 값을 ISO_LOCAL_DATE_TIME 형태에 맞도록 저장하면 된다.
근데... 왜 서버에서 사용 중인 Redis에 다른 형태의 날짜가 저장되어 있었던 것인지.... 참 삽질을 많이 했다;;