fix(时区): 日历口径收回东八区,读出的时刻统一成 ISO 并保留微秒
旧栈 Django 按 Asia/Shanghai 算日历,OJ2 重写时这个锚点丢了:容器和数据库会话 都是 UTC,于是「今日提交」在北京时间 0–8 点是空的,「凌晨/早起提交次数」整体偏 8 小时,热力图、AC 趋势年份、近两年活跃人数也各按进程时区切。 - 新增 apps/api/src/time.ts 作为唯一锚点(固定 +8 偏移,不依赖进程 TZ / tzdata), todayStart、成就小时/日期键、热力图、月份平移、年份夹逼全部改走它; SQL 里按日历切的一律显式 at time zone。 - db/index.ts:连接会话时区设为东八区(兜底);给 timestamptz(1184) 挂 parser, 读出统一成 ISO 8601 UTC,撤掉为拿 PG 文本形状写的 ::text。parser 保留微秒 —— 生产库 12.3 万条提交几乎全带微秒,截成毫秒会让翻页分界行和班级 AC 排名的 <= min(create_time) 把自己排除(翻页每页丢一条、排名少 1)。 - 前端 parseTime/zonedParts/zonedYear 按 Asia/Shanghai 渲染,n-date-picker 做 toPickerValue/fromPickerValue 平移,站内不再按浏览器时区取时间部件。 - Dockerfile 设 TZ=Asia/Shanghai 作为第二道兜底。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K1d8B3f4SXJwDvUY625eQd
This commit is contained in:
1 parent
6e63866cc9
commit
4c0c38445c
23 files changed
+491
-106
No files matched your search
@@ -69,7 +69,11 @@ async function recoverable(links: ProblemLink[], progresses: (typeof schema.prob
|
||||
const rows = await db.select({
|
||||
userId: schema.submission.userId,
|
||||
problemId: schema.submission.problemId,
|
||||
solvedAt: sql<string>`min(${schema.submission.createTime})::text`,
|
||||
// 和 recoverable 上面那段同口径。不加 `::text`:OID 1184 由 db/index.ts 统一转成
|
||||
// ISO 8601 UTC,比 PG 文本更稳定(PG 文本的形状跟着会话时区走)。
|
||||
// 注:这个值写进 progress_detail.submit_time,而那个字段没有任何读取方,
|
||||
// 存量里还混着 Django 的 `...+00:00`,所以形状变化只影响 backfill 自己的差异比对。
|
||||
solvedAt: sql<string>`min(${schema.submission.createTime})`,
|
||||
}).from(schema.submission).where(and(
|
||||
inArray(schema.submission.userId, [...new Set(gaps.map((g) => g.userId))]),
|
||||
inArray(schema.submission.problemId, [...new Set(gaps.map((g) => g.problemId))]),
|
||||
|
||||
Reference in new issue
Block a user