Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,13 @@ List<Events> findHolidaysInRange(

/**
* 공휴일 중복 삽입 방지를 위해 존재 여부를 확인합니다.
* (Native Query를 사용하여 @SQLRestriction을 무시하고 Soft Delete 된 일정까지 완벽히 검사합니다)
*/
@Query("""
SELECT COUNT(e) > 0
FROM Events e
WHERE e.sourceType = com.tryna.domain.event.enums.SourceType.HOLIDAY
AND e.externalEventId = :externalEventId
AND e.deletedAt IS NULL
""")
@Query(value = """
SELECT COUNT(*) > 0
FROM events
WHERE source_type = 'HOLIDAY'
AND external_event_id = :externalEventId
""", nativeQuery = true)
boolean existsHolidayByExternalEventId(@Param("externalEventId") String externalEventId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,16 @@ public void syncAppleKoreanHolidays() {
CalendarBuilder builder = new CalendarBuilder();
Calendar calendar = builder.build(is);

// 1. 공휴일 탐색 범위를 서비스 전체 범위로 확장
java.util.Calendar calStart = java.util.Calendar.getInstance();
calStart.set(1970, java.util.Calendar.JANUARY, 1);
java.util.Calendar calEnd = java.util.Calendar.getInstance();
calEnd.set(2100, java.util.Calendar.DECEMBER, 31);

net.fortuna.ical4j.model.DateTime startPeriod = new net.fortuna.ical4j.model.DateTime(calStart.getTime());
net.fortuna.ical4j.model.DateTime endPeriod = new net.fortuna.ical4j.model.DateTime(calEnd.getTime());
net.fortuna.ical4j.model.Period searchPeriod = new net.fortuna.ical4j.model.Period(startPeriod, endPeriod);

log.info("애플 공휴일 캘린더 파싱 시작...");

for (Object component : calendar.getComponents(Component.VEVENT)) {
Expand All @@ -80,19 +90,30 @@ public void syncAppleKoreanHolidays() {
continue;
}

String uid = event.getUid().getValue();
String baseUid = event.getUid().getValue();
String title = event.getSummary().getValue();
String dateStr = event.getStartDate().getValue();

LocalDate startDate;
try {
// 공휴일 포맷인 yyyyMMdd 만 파싱 시도
startDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyyMMdd"));
} catch (Exception e) {
continue; // 날짜 포맷이 이상하면 조용히 무시하고 다음 일정으로
}

parsedHolidays.add(new ParsedHolidayDto(title, startDate, uid));
// 2. RRULE(반복 규칙)을 분석하여 검색 기간 내의 모든 날짜로 펼치기 (단일 일정도 1개로 정상 반환됨)
net.fortuna.ical4j.model.PeriodList occurrences = event.calculateRecurrenceSet(searchPeriod);

for (Object p : occurrences) {
net.fortuna.ical4j.model.Period occurrence = (net.fortuna.ical4j.model.Period) p;

// ical4j의 날짜 포맷(yyyyMMdd 또는 yyyyMMddTHHmmss)에서 날짜 8자리만 추출
String dateStr = occurrence.getStart().toString().substring(0, 8);

try {
LocalDate occurrenceDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyyMMdd"));

// 3. 기존 UID에 연도를 붙여 DB에서 각각 독립적인 공휴일로 인식되도록 처리
String uniqueUid = baseUid + "-" + occurrenceDate.getYear();

parsedHolidays.add(new ParsedHolidayDto(title, occurrenceDate, uniqueUid));
} catch (Exception e) {
// 날짜 파싱이 실패하면 해당 건만 조용히 넘김
log.debug("공휴일 날짜 파싱 실패 (무시됨): {}", dateStr);
}
}
}
}

Expand Down
Loading