들어가기 전에
만약 LocalDate 클래스를 사용하고 계신다면 아래 포스팅을 참고해 주세요 :)
https://hojun-dev.tistory.com/entry/JAVA-LocalDate-한국식-월-주차-구하기
개요
매주 보고서 데이터를 엑셀로 출력하여 전달해야 하는 시스템을 만드는 등 특정 날짜가 몇 월의 몇 주차인지 계산해야 하는 경우가 있다.
필자의 경우도 그랬는데, 구글링을 해도 정보가 잘 없는 내용이기도 했고 누군가 만든 코드를 가져다가 사용했다가 에러가 발생했던 경우가 있어 직접 구상하여 월 주차 구하는 코드를 만들어 사용했다.
작성일 기준으로 정확히 사용한 지 1년이 되었는데 오류가 발생하지 않고 잘 동작했기 때문에 동일한 개발이 필요한 사람들에게 도움이 되고자 포스팅을 남긴다.
월 주차 계산법
우리나라에서의 월 주차 계산법을 간단히 설명하면 아래와 같다.
한 주의 시작은 월요일이고, 해당 월에서 4일 이상이 존재하는 첫 번째 주를 해당 월의 첫 주로 계산한다.
말이 조금 어려울 수 있는데, 쉽게 설명하면 한 주가 7일이므로 과반수, 즉 4일 이상이 존재하면 한 주 취급하는 것이다.
시작이 월요일이므로 순서 상 4번째인 목요일이 해당 주차에 존재하는지로 계산할 수도 있다.
위의 계산법으로 첫 주를 계산했으니 이 다음 주들은 맞춰서 주차를 계산하면 된다.
마지막 주도 마찬가지로 목요일이 다음 월로 넘어갔다면 해당 주는 다음 월의 첫 주가 된다.
위 계산법을 잘 생각하면서 코드를 작성해 보자.
Calendar
예전엔 Java에서 날짜를 더하거나 빼는 등 날짜를 다룰 때 Calendar 클래스를 많이 사용했다.
요즘은 java.time 라이브러리를 많이 사용하지만 해당 라이브러리에서 적용하는 방법은 다음 포스팅에서 소개하도록 하고 일단 이 포스팅에서는 Calendar 클래스를 이용한 방법을 소개한다.
Calendar 클래스에서 주차를 구할 때 유용한 메소드가 존재한다.
Calendar calendar = Calendar.getInstance(Locale.KOREA);
// 한 주의 시작 요일 설정
calendar.setFirstDayOfWeek(Calendar.MONDAY);
// 첫 주를 계산할 때 최소로 있어야 하는 날짜 수 설정
calendar.setMinimalDaysInFirstWeek(4);
// 해당 월의 몇 주차인지 계산
int weekOfMonth = calendar.get(Calendar.WEEK_OF_MONTH);
월 주차 계산법에서 말한 내용에 해당하는 메소드들이 다 존재한다.
한국식으로 주차를 계산하기 위해 한 주의 시작을 월요일로 설정하고,
해당 월에서 4일 이상 존재하는 주를 첫 번째 주로 설정하자.
이후 고려해야 할 점이 몇 가지 더 있다.
weekOfMonth 값을 가져올 때 기준 날짜가 포함된 월에서의 주차 값을 반환하므로 get(Calendar.DAY_OF_WEEK)
을 통해 주차 값을 가져올 때 기준 날짜가 해당 월의 첫날이 포함된 주일 때 해당 주에 4일 이상 존재하지 않으면 0으로 반환한다.
또한 계산할 날짜가 해당 월의 마지막 날이 포함된 주일 때 해당 주에 4일 이상 존재하지 않더라도 다른 주와 동일하게 카운트를 하나 추가하여 반환한다.
따라서 위의 내용을 바탕으로 주차를 계산하는 코드를 작성해 보자.
월 주차 구하기
완성된 코드는 아래와 같다.
public static String getCurrentWeekOfMonth(Date date) {
Calendar calendar = Calendar.getInstance(Locale.KOREA);
calendar.setTime(date);
int month = calendar.get(Calendar.MONTH) + 1; // calendar에서의 월은 0부터 시작
int day = calendar.get(Calendar.DATE);
// 한 주의 시작은 월요일이고, 첫 주에 4일이 포함되어있어야 첫 주 취급 (목/금/토/일)
calendar.setFirstDayOfWeek(Calendar.MONDAY);
calendar.setMinimalDaysInFirstWeek(4);
int weekOfMonth = calendar.get(Calendar.WEEK_OF_MONTH);
// 첫 주에 해당하지 않는 주의 경우 전 달 마지막 주차로 계산
if (weekOfMonth == 0) {
calendar.add(Calendar.DATE, -day); // 전 달의 마지막 날 기준
return getCurrentWeekOfMonth(calendar.getTime());
}
// 마지막 주차의 경우
if (weekOfMonth == calendar.getActualMaximum(Calendar.WEEK_OF_MONTH)) {
calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE)); // 이번 달의 마지막 날
int lastDaysDayOfWeek = calendar.get(Calendar.DAY_OF_WEEK); // 이번 달 마지막 날의 요일
// 마지막 날이 월~수 사이이면 다음달 1주차로 계산
if (lastDaysDayOfWeek >= Calendar.MONDAY && lastDaysDayOfWeek <= Calendar.WEDNESDAY) {
calendar.add(Calendar.DATE, 1); // 마지막 날 + 1일 => 다음달 1일
return getCurrentWeekOfMonth(calendar.getTime());
}
}
return month + "월 " + weekOfMonth + "주차";
}
월 주차 계산법에 따라 첫 주에 해당하지 않으면 전 월의 마지막 날 기준으로 다시 계산하고,
마지막 주에 해당하지 않으면 다음 월의 첫날을 기준으로 계산한다.
첫 주에 해당하지 않거나 마지막 주에 해당하지 않는 경우는 해당 주에 4일이 존재하지 않는다(목요일이 포함되어 있지 않다)는 것을 의미하므로 월을 바꾼 기준일자로 다시 계산한다면 해당 날짜의 주차에는 무조건 4일 이상이 존재한다(목요일이 포함되어 있다)는 것을 의미하므로 메소드를 다시 호출한다 해서 무한 루프에 빠질 위험은 없다.
실행 결과
2023년 7월을 기준으로 위의 달력 사진에서 표현한 내용과 동일하게 출력되었다.
마무리
ISO 8601 국제 표준도 월요일이 한 주의 시작으로 되어있는데 Calendar 기본값은 왜 일요일일까?
아마 미국의 한 주 시작일이 일요일이기 때문이겠다.
이 외에도 한글이나 타임존 등등 우리나라 기준으로 코딩할 때에는 항상 추가적으로 설정해야 할 게 많아서 귀찮음이 따른다.
하지만 어쩔 수 있나. 영어 공부 열심히 하자.
참고) https://samulgoongi.com/2061
'Java & Spring' 카테고리의 다른 글
[JAVA] 내부 resource 파일 활용하기 (0) | 2023.07.29 |
---|---|
[JAVA] LocalDate로 한국식 월 주차 구하기 (6) | 2023.07.27 |
[JAVA] Lombok Builder, SuperBuilder와 Generic 사용하기 (0) | 2023.07.21 |
[Spring] JPA 중복 Insert 방지하기 (0) | 2023.07.18 |
[JAVA] poi에서 SXSSFWorkbook 사용 시 NullPointerException이 발생하는 경우 (0) | 2023.04.28 |