728x90

 

문제 상황

한달에 한번 자동으로 정산을 진행하도록 스케줄러를 통하여 구현을 하는 과정에서 지난 달의 첫날 마지막 날을 정확하게 구해야 했습니다.

LocalDateTime now = LocalDateTime.now();
            LocalDateTime endDate = now.withDayOfMonth(1).minusNanos(1); 
            LocalDateTime startDate = endDate.minusMonths(1).withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
            Long settlementTime = endDate.getYear() * 100L + endDate.getMonthValue(); // YYYYMM 형식

            log.info("Settlement period - Start: {}, End: {}", startDate, endDate);
Settlement period - Start: 2024-09-01T00:00, End: 2024-10-01T23:13:00.010603999

 

그러나 위와 같이 마지막날의 값이 이상하게 들어가는 것을 확인했습니다.

 

문제 이유

1. LocalDateTime.now() 사용

  • LocalDateTime.now()현재 날짜시간을 반환합니다.
  • 예를 들어, 만약 현재 날짜가 2024년 10월 23일이라면, now는 2024-10-23 14:30:00.000000과 같은 값이 됩니다.

2. withDatOfMonth(1)과 minusNanos(1)

 

  • endDate = now.withDayOfMonth(1).minusNanos(1)의 경우, now의 날짜를 1일로 바꾼 후 1나노초를 빼게 되면, endDate는 2024년 10월 1일의 23:59:59.999999999가 됩니다.
  • 이는 결과적으로 endDate가 10월의 마지막 날이 아닌, 9월의 마지막 날이 아니라는 점에서 혼동을 초래하게 됩니다.

3. startDate 계산

  • startDate는 endDate에서 한 달을 빼고 첫 날로 설정하는 과정에서, 결국 잘못된 endDate기준으로 계산되므로 올바르지 않은 결과가 나옵니다.

 

문제 해결 방법 (LocalDate 사용)

올바른 코드는 아래와 같이 LocalDate를 사용하여 lastMonth를 정확히 계산하는 것입니다.

 

LocalDate today = LocalDate.now();
            LocalDate lastMonth = today.minusMonths(1);
            LocalDateTime startDate = lastMonth.withDayOfMonth(1).atStartOfDay(); // 지난 달의 첫 날 00:00:00
            LocalDateTime endDate = lastMonth.withDayOfMonth(lastMonth.lengthOfMonth()).atTime(LocalTime.MAX); // 지난 달의 마지막 날 23:59:59.999999999

            Long settlementTime = lastMonth.getYear() * 100L + lastMonth.getMonthValue(); // YYYYMM 형식


            log.info("Settlement period - Start: {}, End: {}",
                    startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
                    endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

 

위 코드의 각 단계별로 설명을 하자면 다음과 같습니다.

1. 현재 날짜 가져오기

LocalDate today = LocalDate.now();
  • LocalDate.now()를 사용하여 현재 날짜를 가져옵니다.
  • 예를 들어, 2024년 10월 23일이라면, today는 2024-10-23이 됩니다.

2. 지난 달 날짜 계산

LocalDate lastMonth = today.minusMonths(1);
  • minusMonths(1) 메서드를 사용하여 현재 날짜에서 한 달을 빼줍니다.

3. 지난 달의 첫 날 구하기

LocalDateTime startDate = lastMonth.withDayOfMonth(1).atStartOfDay();
  • withDayOfMonth(1)을 호출하여 lastMonth 1일로 설정하고, atStartOfDay()를 사용하여 해당 날짜의 시작 시간00:00:00으로 설정합니다. 결과적으로 startDate는 2024-09-01T00:00:00이 됩니다.

4. 지난달의 마지막 날 구하기 

LocalDateTime endDate = lastMonth.withDayOfMonth(lastMonth.lengthOfMonth()).atTime(LocalTime.MAX);
  • lengthOfMonth() 메서드를 사용하여 지난 달의 마지막 날짜를 얻습니다.
  • 9월의 경우 30일이므로, withDayOfMonth(30)이 호출되어 endDate는 2024-09-30T23:59:59.999999999가 됩니다. atTime(LocalTime.MAX)는 해당 날짜의 마지막 시간을 설정합니다.

 

  • 정확한 날짜 계산
    • LocalDate를 사용하여 날짜를 계산함으로써, 연도와 월에 기반한 올바른 값을 유지하며, LocalDateTime으로 변환하여 시간 정보를 추가함으로써 원하는 결과를 얻을 수 있습니다.
    • 이전 코드의 LocalDateTime.now()로 인해 잘못된 기준을 사용한 문제를 피하고, 명확한 기준으로 날짜를 관리함으로써 오류를 해결하였습니다.