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()로 인해 잘못된 기준을 사용한 문제를 피하고, 명확한 기준으로 날짜를 관리함으로써 오류를 해결하였습니다.
'TIL,일일 회고' 카테고리의 다른 글
[TIL, 일일 회고] 2024.10.22 - S3 확장자 에러 처리하기 (0) | 2024.10.22 |
---|---|
[TIL, 일일 회고] 2024.10.21 - Spring boot 스케줄러 @Schduled (0) | 2024.10.21 |
[TIL, 일일 회고] 2024.10.19 - 데이터베이스 스키마 추가하기 (0) | 2024.10.19 |
[TIL, 일일 회고] 2024.10.18 - 서버 사이드 렌더링 적용하기 (0) | 2024.10.18 |
[TIL, 일일 회고] 2024.10.17 - Spring Data JPA의 명명 규칙 (0) | 2024.10.17 |