From d15039ce182c192805df6fcfa9c97427c0322e7e Mon Sep 17 00:00:00 2001 From: htlee Date: Thu, 2 Apr 2026 05:53:14 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20vessel=5Fstore=20=5Flast=5Fbucket=20?= =?UTF-8?q?=ED=83=80=EC=9E=84=EC=A1=B4=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit snpdb time_bucket은 tz-naive KST인데 UTC tzinfo를 강제 부여하여 incremental fetch WHERE time_bucket > %s 비교 시 미래 시간으로 해석, 항상 0 rows 반환 → 1h 어구 그룹이 점진적으로 소멸하는 버그. tz-naive 그대로 유지하도록 수정 (load_initial, merge_incremental 3곳). Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/RELEASE-NOTES.md | 1 + prediction/cache/vessel_store.py | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/RELEASE-NOTES.md b/docs/RELEASE-NOTES.md index 114ee98..f834229 100644 --- a/docs/RELEASE-NOTES.md +++ b/docs/RELEASE-NOTES.md @@ -6,6 +6,7 @@ ### 수정 - 1h 활성 판정을 parent_name 전체 합산 기준으로 변경 (서브클러스터 분리 후 개별 소수 문제 해결) +- vessel_store의 _last_bucket 타임존 오류 수정 (tz-naive KST → UTC 잘못 변환 → incremental fetch 0건) ## [2026-04-01.2] diff --git a/prediction/cache/vessel_store.py b/prediction/cache/vessel_store.py index b79f031..e73fea4 100644 --- a/prediction/cache/vessel_store.py +++ b/prediction/cache/vessel_store.py @@ -114,19 +114,20 @@ class VesselStore: self._tracks[str(mmsi)] = group.reset_index(drop=True) # last_bucket 설정 — incremental fetch 시작점 + # snpdb time_bucket은 tz-naive KST이므로 UTC 변환하지 않고 그대로 유지 if 'time_bucket' in df_all.columns and not df_all['time_bucket'].dropna().empty: max_bucket = pd.to_datetime(df_all['time_bucket'].dropna()).max() if hasattr(max_bucket, 'to_pydatetime'): max_bucket = max_bucket.to_pydatetime() - if isinstance(max_bucket, datetime) and max_bucket.tzinfo is None: - max_bucket = max_bucket.replace(tzinfo=timezone.utc) + if isinstance(max_bucket, datetime) and max_bucket.tzinfo is not None: + max_bucket = max_bucket.replace(tzinfo=None) self._last_bucket = max_bucket elif 'timestamp' in df_all.columns and not df_all['timestamp'].dropna().empty: max_ts = pd.to_datetime(df_all['timestamp'].dropna()).max() if hasattr(max_ts, 'to_pydatetime'): max_ts = max_ts.to_pydatetime() - if isinstance(max_ts, datetime) and max_ts.tzinfo is None: - max_ts = max_ts.replace(tzinfo=timezone.utc) + if isinstance(max_ts, datetime) and max_ts.tzinfo is not None: + max_ts = max_ts.replace(tzinfo=None) self._last_bucket = max_ts vessel_count = len(self._tracks) @@ -171,8 +172,8 @@ class VesselStore: if new_buckets: latest = max(new_buckets) - if isinstance(latest, datetime) and latest.tzinfo is None: - latest = latest.replace(tzinfo=timezone.utc) + if isinstance(latest, datetime) and latest.tzinfo is not None: + latest = latest.replace(tzinfo=None) if self._last_bucket is None or latest > self._last_bucket: self._last_bucket = latest