Post

(Java) LocalDateTime - 날짜 시간 처리 관련

Date ? Calendar? java.time? 뭘 써야 하나? : LocalDateTime

http://tcpschool.com/java/java_time_javaTime

https://d2.naver.com/helloworld/645609

LocalDateTime -> String
1
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
LocalDateTime Json, Spring mapping
1
2
3
4
5
6
7
8
// spring Controller에서 DATE\_FORMAT형식->LocalDate로 받고 싶을 때
@DateTimeFormat(pattern = DATE\_FORMAT)
private LocalDate fromUpdateDate;

// Jackson serialize/deserialize할 때 LocalDateTime<>DATE\_TIME\_FORMAT 형식 변환
@JsonFormat(pattern = DATE\_TIME\_FORMAT)
private LocalDateTime registrationDate;
// Thu, 21 Oct 2021 18:07:17 GMT 같은 형식 파싱할 때는 반드시 locale 지정한다. 현재 시스템이 KO 기준이면 "목, 21 10월..." 이렇게 파싱 시도한다.

DB에서 꺼낸 데이터가 LocalDateTime 타입 필드에 들어갈 때 에러나는 경우가 있음.

http://www.mybatis.org/mybatis-3/configuration.html#typeHandlers MyBatis 같은 경우 버전 3.4.5 이상은 MyBatis core에 LocalDateTimeTypeHandler 같은게 다 정의되어 있어서 자동으로 Timestamp로 변환이 되는 반면, 그 이전 버전은 Pre-defined Handler를 사용하기 위해서는 직접 dependency를 추가해주어야 한다. 아무튼 이런 Handler는 별도의 설정 없이 기본적으로 동작하도록 되어 있기 때문에(아마mybatis-spring-boot-starter일 듯?) LocalDateTime의 데이터를 맵에 넣어 DB에 INSERT 하거나 WHERE에 명시해도 잘 돌아간다. 그러나 DB에 저장되어 있는 날짜 데이터를 LocalDateTime 타입의 필드에 대입하는 경우(SELECT) 이런 에러가 발생한다.

1
2
3
4
java.lang.ClassNotFoundException: com.vividsolutions.jts.geom.Geometry

at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) ~[mybatis-3.5.1.jar:3.5.1]
at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) ~[mybatis-3.5.1.jar:3.5.1]

로그를 확인해보니 Handler는 잘 돌아가고 있으나 에러가 발생.

파라미터나 컬럼 네임을 아무리 바꿔보고 스택을 따라가봐도 원인을 모르겠다… 타입을 Date로 고치면 잘 된다. 그럼 LocalDateTime은 왜 안될까… 생각해보니 이게 Java8에서 추가된 클래스라 MyBatis나 JDBC같은게 Java8대응이 안되는 버전 이면 Class를 못찾는게 아닐까? 하는 생각이 든다. 아… 그러고 보니 H2를 올릴 때 몇 가지 이슈 때문에 옛날 버전 H2 를 사용하고 있었는데 이 것 때문이라는 느낌이 강하게 오는데 역시… H2 버전을 최신으로 올리고 다시 시도해보니 정상적으로 LocalDateTime에 매핑된다. 반나절 삽질의 결과…ㅠㅠ

Date format check

setter에서 데이터 넣기 전에 주로 체크.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public void setQueryDate(String queryDate) {
    Date date = null;
    SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
    try {
        date = format.parse(queryDate);
        if (!queryDate.equals(format.format(date))) {
            // 예를 들어 ss에 90이 들어오면 +1분 +30초로 자동으로 나뉘어지게 되는데, 이를 방지하기 위함.
            throw new ParseException(queryDate, 0);
        }
    } catch (ParseException e) {
        throw new RuntimeException(e);
    }
 
    if (queryDate.length() > 14)
        throw new StringIndexOutOfBoundsException();
    else
        this.queryDate = queryDate;
}

유틸리티로 따로 빼면

1
2
3
4
5
6
7
8
9
10
11
12
public class DateFormatChecker {
    public static boolean isValidFormat(String strFormat, String strDate) {
        SimpleDateFormat format = new SimpleDateFormat(strFormat);
        try {
            Date date = format.parse(strDate);
            // 예를 들어 ss가 90초이면 +1분 +30초로 자동으로 나뉘어지게 되는데, 이를 방지하기 위함.
            return strDate.equals(format.format(date));
        } catch (ParseException e) {
            return false;
        }
    }
}

@TelegramField(position = 111, length = 5)
이런 식으로 중복되는걸 setter가 아니라 annotation으로 빼면 더 좋다.
DateFormatCheck나 size같은거…

*** timestamp millis 반환. 어떻게? ( 시간 측정 ? )
시간 비교는 ChronoUnit이 제일 직관적

https://www.baeldung.com/java-date-difference

This post is licensed under CC BY 4.0 by the author.