- TIME_ZONE / TIME_ZONE_OFFSET_MINUTES 移到 packages/contract/src/time.ts,
前后端共用一份,不再各写一遍靠注释对齐。
- apps/api/src/time.ts 新增 localTime(列),替换散落 7 处的
`at time zone ${TIME_ZONE_SQL}`;ac-trend 的 where 复用同一个 year 表达式。
- /problems/:displayId/yearly-ac 漏写了时区、按 UTC 切年,被会话时区兜底掩盖;
改为按东八区切(只影响每年 12-31 北京 0–8 点的提交归年)。
- 删掉数据库连接的 TimeZone 和 Dockerfile 的 TZ:正确代码不依赖它们,
它们只会在线上掩盖漏写处、让 dev 与线上答案不同。
- time.ts:calendarDayYearsAgo/pad 并入 shiftMonthsByCalendar,startOfCalendarDay
并入 todayStart,localWeekday 改用 getUTCDay,删掉历史叙述注释。
- 前端 zonedParts 改为固定偏移 + getUTC*(与后端、日期选择器同一写法),
去掉 Intl formatToParts;10 万次 299ms → 11ms。zonedYear 去掉按浏览器时区的兜底。
- 两份 CLAUDE.md 同步;n-date-picker 那条过时说明改成现用法。
验证:新旧「近两年起点」21359 个时刻 0 差异、localWeekday 0 差异、
前端固定偏移与 Intl 在 America/New_York 下 47821 个时刻 0 差异;
localTime 在 select/group by/where 复用可用;fix-achievement-hours 预演仍为 148 / 60。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1d8B3f4SXJwDvUY625eQd
This commit is contained in:
@@ -21,7 +21,7 @@ import { db, schema } from "../db"
|
||||
import { astRequirements } from "../judge/ast"
|
||||
import { failure, success } from "../http"
|
||||
import { JudgeStatus } from "../judge/status"
|
||||
import { calendarDayYearsAgo, startOfCalendarDay } from "../time"
|
||||
import { localTime, shiftMonthsByCalendar, todayStart } from "../time"
|
||||
import { asFilterValue, countFailedSubmissions, objectValue as toObject, queryInteger, sampleUser } from "./helpers"
|
||||
|
||||
export const problemRoutes = new Hono<AppEnv>()
|
||||
@@ -179,9 +179,8 @@ problemRoutes.get("/problems/:id/beat-count", optionalAuth, async (c) => {
|
||||
inArray(schema.submission.result, [JudgeStatus.ACCEPTED, JudgeStatus.AST_CHECK_FAILED]),
|
||||
))
|
||||
if (!mine?.value) return success(c, "0")
|
||||
// 「近两年」按东八区日历算到当天零点。原先是 setFullYear/setHours,
|
||||
// 切的是进程时区的零点。
|
||||
const since = startOfCalendarDay(calendarDayYearsAgo(2)).toISOString()
|
||||
// 「近两年」按东八区日历算到当天零点
|
||||
const since = todayStart(shiftMonthsByCalendar(new Date(), -24))
|
||||
const [active, accepted] = await Promise.all([
|
||||
db.select({ value: count() }).from(schema.user).where(and(eq(schema.user.isDisabled, false), gte(schema.user.lastLogin, since))),
|
||||
db.select({ value: countDistinct(schema.submission.userId) }).from(schema.submission).where(and(
|
||||
@@ -217,7 +216,7 @@ problemRoutes.get("/problems/:displayId/yearly-ac", async (c) => {
|
||||
const [problem] = await db.select({ id: schema.problem.id }).from(schema.problem)
|
||||
.where(and(sql`lower(${schema.problem.displayId}) = lower(${c.req.param("displayId")})`, isNull(schema.problem.contestId), eq(schema.problem.visible, true))).limit(1)
|
||||
if (!problem) return failure(c, 404, "problem-not-found", "Problem does not exist")
|
||||
const year = sql<number>`extract(year from ${schema.submission.createTime})::int`
|
||||
const year = sql<number>`extract(year from ${localTime(schema.submission.createTime)})::int`
|
||||
const rows = await db.select({
|
||||
year,
|
||||
total: count(),
|
||||
|
||||
Reference in New Issue
Block a user