Merge pull request 'fix: UTC 타임존 변환 + Daily 캐시 부분 fallback 추가' (#52) from feature/dashboard-phase-1 into develop

This commit is contained in:
htlee 2026-02-20 00:47:10 +09:00
커밋 f5738978ed
2개의 변경된 파일27개의 추가작업 그리고 2개의 파일을 삭제

파일 보기

@ -24,6 +24,7 @@ import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -327,7 +328,7 @@ public class GisServiceV2 {
Set<String> requestedMmsis = new HashSet<>(request.getVessels());
// 1. 캐시에서 조회 (캐시된 날짜)
// 1. 캐시에서 조회 (캐시된 날짜) + 누락 MMSI 부분 DB fallback
if (split.hasCachedData()) {
List<CompactVesselTrack> cachedTracks =
dailyTrackCacheManager.getCachedTracksMultipleDays(split.getCachedDates());
@ -343,6 +344,28 @@ public class GisServiceV2 {
allTracks.addAll(filteredCached);
log.debug("[CacheQuery] cached {} days -> {} tracks (filtered from {})",
split.getCachedDates().size(), filteredCached.size(), totalCachedCount);
// Daily 캐시에 없는 MMSI DB fallback (hourly/5min 계층 조회)
Set<String> cachedMmsis = filteredCached.stream()
.map(CompactVesselTrack::getVesselId)
.collect(Collectors.toSet());
Set<String> missingMmsis = new HashSet<>(requestedMmsis);
missingMmsis.removeAll(cachedMmsis);
if (!missingMmsis.isEmpty()) {
LocalDate minDate = split.getCachedDates().stream().min(Comparator.naturalOrder()).orElse(null);
LocalDate maxDate = split.getCachedDates().stream().max(Comparator.naturalOrder()).orElse(null);
if (minDate != null) {
LocalDateTime cacheStart = minDate.atStartOfDay().isBefore(startTime) ? startTime : minDate.atStartOfDay();
LocalDateTime cacheEnd = maxDate.plusDays(1).atStartOfDay().isAfter(endTime) ? endTime : maxDate.plusDays(1).atStartOfDay();
VesselTracksRequest fallbackReq = VesselTracksRequest.builder()
.startTime(cacheStart).endTime(cacheEnd)
.vessels(new ArrayList<>(missingMmsis)).build();
List<CompactVesselTrack> dbResult = gisService.getVesselTracks(fallbackReq);
allTracks.addAll(dbResult);
log.info("[CACHE-MONITOR] queryWithCache daily PARTIAL → DB fallback: cacheHit={}, cacheMiss={}, dbTracks={}",
cachedMmsis.size(), missingMmsis.size(), dbResult.size());
}
}
}
// 2. DB에서 조회 (캐시 미적중 과거 날짜)

파일 보기

@ -1,6 +1,7 @@
package gc.mda.signal_batch.global.util;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
@ -76,11 +77,12 @@ public class DateTimeParseUtil {
String trimmed = dateTimeString.trim();
// Try zoned formatters first for Z or offset patterns
// UTC/Offset 시스템 타임존(KST)으로 변환 LocalDateTime 추출
if (trimmed.contains("Z") || trimmed.matches(".*[+-]\\d{2}:\\d{2}$")) {
for (DateTimeFormatter formatter : ZONED_FORMATTERS) {
try {
ZonedDateTime zdt = ZonedDateTime.parse(trimmed, formatter);
return zdt.toLocalDateTime();
return zdt.withZoneSameInstant(ZoneId.systemDefault()).toLocalDateTime();
} catch (DateTimeParseException ignored) {
// Try next formatter
}