티스토리 뷰
최근 spring boot 프로젝트에서 공무원 월급일자를 계산해야하는 일이 생겼습니다.
공무원의 경우 월급날이 공휴일이거나, 주말인 경우 월급을 앞당겨서 지급받기 때문에 특정년도의 공휴일을 계산해주는 계산기가 필요했습니다.
0. 라이브러리 추가
gradle project 에 음력달력을 사용하기 위한 라이브러리를 추가해줍니다.
dependencies {
// https://mvnrepository.com/artifact/com.ibm.icu/icu4j
implementation group: 'com.ibm.icu', name: 'icu4j', version: '4.0.1'
}
1. 공휴일 처리 클래스
Lunar2Solar 메서드를 이용하여 음력기준의 공휴일을 양력날자로 변환해준뒤, 대체 공휴일이 적용되는 경우 대체 공휴일까지 계산합니다.
저의 경우 올해의 공휴일만 계산하면 됐기 때문에 계산 결과를 LunarCalendar 의 map 필드에 저장했습니다.
만약 자주 사용하지 않는 년도의 공휴일을 계산하는 경우 map 필드에 저장되어 가비지 컬렉션에 의해 제거되지 않고 메모리를 잡아먹게 됩니다. 이런 경우에는 holidaySet 메서드에서 계산 결과를 map 에 저장하는 부분을 제거해야합니다.
import com.ibm.icu.util.ChineseCalendar;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class LunarCalendar {
public static final int LD_SUNDAY = 7;
public static final int LD_SATURDAY = 6;
public static final int LD_MONDAY = 1;
static Map<Integer, Set<LocalDate>> map = new HashMap<>();
private LocalDate Lunar2Solar(LocalDate lunar) {
ChineseCalendar cc = new ChineseCalendar();
cc.set(ChineseCalendar.EXTENDED_YEAR, lunar.getYear() + 2637); // 년, year + 2637
cc.set(ChineseCalendar.MONTH, lunar.getMonthValue() - 1); // 월, month -1
cc.set(ChineseCalendar.DAY_OF_MONTH, lunar.getDayOfMonth()); // 일
LocalDate solar = Instant.ofEpochMilli(cc.getTimeInMillis()).atZone(ZoneId.of("UTC")).toLocalDate();
return solar;
}
/**
* Return the set of holidays of input yaer
*
* <p>results of this method would be <i>saved</i> in static field {@code this.map}
* after the method calculate holidays of input year
*
* @param year target year
* @return set of holidays of input year
*/
public Set<LocalDate> holidaySet(int year) {
if (map.containsKey(year)) return map.get(year);
Set<LocalDate> holidaysSet = new HashSet<>();
// 양력 휴일
holidaysSet.add(LocalDate.of(year, 1, 1)); // 신정
holidaysSet.add(LocalDate.of(year, 3, 1)); // 삼일절
holidaysSet.add(LocalDate.of(year, 5, 5)); // 어린이날
holidaysSet.add(LocalDate.of(year, 6, 6)); // 현충일
holidaysSet.add(LocalDate.of(year, 8, 15)); // 광복절
holidaysSet.add(LocalDate.of(year, 10, 3)); // 개천절
holidaysSet.add(LocalDate.of(year, 10, 9)); // 한글날
holidaysSet.add(LocalDate.of(year, 12, 25)); // 성탄절
// 음력 휴일
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 1, 1)).minusDays(1)); // ""
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 1, 1))); // 설날
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 1, 2))); // ""
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 4, 8))); // 석탄일
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 8, 14))); // ""
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 8, 15))); // 추석
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 8, 16))); // ""
try {
// 어린이날 대체공휴일 검사 : 어린이날은 토요일, 일요일인 경우 그 다음 평일을 대체공유일로 지정
holidaysSet.add(substituteHoliday(LocalDate.of(year, 5, 5)));
// 삼일절, 광복절, 개천절, 한글날
holidaysSet.add(substituteHoliday(LocalDate.of(year, 3, 1)));
holidaysSet.add(substituteHoliday(LocalDate.of(year, 8, 15)));
holidaysSet.add(substituteHoliday(LocalDate.of(year, 10, 3)));
holidaysSet.add(substituteHoliday(LocalDate.of(year, 10, 9)));
// 설날 대체공휴일 검사
if (Lunar2Solar(LocalDate.of(year, 1, 1)).getDayOfWeek().getValue() == LD_SUNDAY) { // 일
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 1, 3)));
}
if (Lunar2Solar(LocalDate.of(year, 1, 1)).getDayOfWeek().getValue() == LD_MONDAY) { // 월
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 1, 3)));
}
if (Lunar2Solar(LocalDate.of(year, 1, 2)).getDayOfWeek().getValue() == LD_SUNDAY) { // 일
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 1, 3)));
}
// 추석 대체공휴일 검사
if (Lunar2Solar(LocalDate.of(year, 8, 14)).getDayOfWeek().getValue() == LD_SUNDAY) {
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 8, 17)));
}
if (Lunar2Solar(LocalDate.of(year, 8, 15)).getDayOfWeek().getValue() == LD_SUNDAY) {
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 8, 17)));
}
if (Lunar2Solar(LocalDate.of(year, 8, 16)).getDayOfWeek().getValue() == LD_SUNDAY) {
holidaysSet.add(Lunar2Solar(LocalDate.of(year, 8, 17)));
}
} catch (Exception e) {
e.printStackTrace();
}
map.put(year, holidaysSet);
return holidaysSet;
}
/**
* @param h holiday target of substitute holiday
* @return new LocalDate Object: substitute holiday of input value
*/
private LocalDate substituteHoliday(LocalDate h) {
if (h.getDayOfWeek().getValue() == LD_SUNDAY) { // 일요일
return h.plusDays(1);
}
if (h.getDayOfWeek().getValue() == LD_SATURDAY) { // 토요일
return h.plusDays(2);
}
return h;
}
}
'java' 카테고리의 다른 글
[JAVA] immutable object (불변객체) (0) | 2022.03.01 |
---|---|
[Intellij] Gradle project - out build 폴더 (0) | 2022.02.25 |
[Java] expo-server-sdk-java 를 이용한 push notification 구현 (1) (0) | 2022.02.20 |
[JAVA] 컬렉션 프레임워크 (collection framework) (0) | 2021.11.27 |
[JAVA] 람다식 (lambda expression) (0) | 2021.11.25 |
댓글