fix: compare platform message history cutoff in UTC

platform_message_history.created_at stores UTC wall-clock values
(written via TimestampMixin's datetime.now(timezone.utc)), but
delete_platform_message_offset computed the cutoff from naive local
datetime.now(). On hosts outside UTC the comparison was shifted by the
local offset, so the wrong slice of history was deleted.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
ping
2026-09-27 23:00:55 +08:00
committed by Soulter
co-authored by Devin
parent 8d5dd15f34
commit aefce70a2e
2 changed files with 56 additions and 2 deletions
+2 -1
View File
@@ -851,7 +851,8 @@ class SQLiteDatabase(BaseDatabase):
async with self.get_db() as session:
session: AsyncSession
async with session.begin():
now = datetime.now()
# created_at stores UTC wall-clock values, so compare in UTC.
now = datetime.now(timezone.utc)
cutoff_time = now - timedelta(seconds=offset_sec)
await session.execute(
delete(PlatformMessageHistory).where(
+54 -1
View File
@@ -7,7 +7,13 @@ import pytest
from sqlalchemy import Column, DateTime, MetaData, create_engine, literal, select
from sqlmodel import SQLModel
from astrbot.core.db.po import ConversationV2, PlatformStat
import astrbot.core.db.sqlite as sqlite_module
from astrbot.core.db.po import (
ConversationV2,
PlatformMessageHistory,
PlatformStat,
)
from astrbot.core.db.sqlite import SQLiteDatabase
from astrbot.core.db.vec_db.faiss_impl.document_storage import BaseDocModel, Document
from astrbot.core.knowledge_base.models import BaseKBModel, KnowledgeBase
@@ -95,3 +101,50 @@ def test_existing_datetime_rows_keep_naive_reads_and_filters(
assert result.isoformat() == "2024-01-02T03:04:05.123456"
finally:
engine.dispose()
@pytest.mark.asyncio
async def test_delete_platform_message_offset_compares_in_utc(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
):
"""The history cutoff must match the UTC wall time stored in created_at.
Args:
tmp_path: Temporary directory for the database file.
monkeypatch: Fixture used to simulate a host in a non-UTC timezone.
"""
now_utc = datetime.now(timezone.utc)
inside_window = (now_utc - timedelta(hours=20)).replace(tzinfo=None)
outside_window = (now_utc - timedelta(hours=30)).replace(tzinfo=None)
db = SQLiteDatabase(str(tmp_path / "history.db"))
await db.initialize()
try:
async with db.get_db() as session:
async with session.begin():
for created_at in (inside_window, outside_window):
session.add(
PlatformMessageHistory(
platform_id="p1",
user_id="u1",
content={},
created_at=created_at,
)
)
class LocalTime(datetime):
"""Simulate a host whose local timezone is UTC+8."""
@classmethod
def now(cls, tz=None):
if tz is None:
return now_utc.replace(tzinfo=None) + timedelta(hours=8)
return now_utc.astimezone(tz)
monkeypatch.setattr(sqlite_module, "datetime", LocalTime)
await db.delete_platform_message_offset("p1", "u1", offset_sec=86400)
rows = await db.get_platform_message_history("p1", "u1")
assert [row.created_at for row in rows] == [outside_window]
finally:
await db.engine.dispose()