diff --git a/laf-cloud/functions/dailyTaskConfig.ts b/laf-cloud/functions/dailyTaskConfig.ts index 1edd9c6..940ebce 100644 --- a/laf-cloud/functions/dailyTaskConfig.ts +++ b/laf-cloud/functions/dailyTaskConfig.ts @@ -30,6 +30,7 @@ export type DailyWeeklyTaskData = { version: 2; dayKey: string; weekKey: string; + dayEndsAt: number; weekEndsAt: number; serverNow: number; dailyTasks: DailyTask[]; diff --git a/laf-cloud/functions/dailyTaskService.ts b/laf-cloud/functions/dailyTaskService.ts index 230f858..533b1c5 100644 --- a/laf-cloud/functions/dailyTaskService.ts +++ b/laf-cloud/functions/dailyTaskService.ts @@ -12,6 +12,10 @@ export function getDayKey(nowMs = Date.now()): string { return new Date(nowMs + SHANGHAI_OFFSET_MS).toISOString().slice(0, 10); } +export function getDayEndsAt(nowMs = Date.now()): number { + return Date.parse(`${getDayKey(nowMs)}T00:00:00+08:00`) + DAY_MS; +} + export function getWeekKey(nowMs = Date.now()): string { const shifted = new Date(nowMs + SHANGHAI_OFFSET_MS); const day = shifted.getUTCDay() || 7; @@ -61,6 +65,7 @@ export function refreshTaskData( ): { data: DailyWeeklyTaskData; changed: boolean } { const dayKey = getDayKey(nowMs); const weekKey = getWeekKey(nowMs); + const dayEndsAt = getDayEndsAt(nowMs); const weekEndsAt = getWeekEndsAt(nowMs); const parsed = typeof stored === "string" ? safeParse(stored) : stored; const valid = parsed && (parsed as DailyWeeklyTaskData).version === 2 @@ -72,7 +77,8 @@ export function refreshTaskData( const newDay = !old || old.dayKey !== dayKey; if (!newDay && !newWeek) { - const changed = old.weekEndsAt !== weekEndsAt; + const changed = old.dayEndsAt !== dayEndsAt || old.weekEndsAt !== weekEndsAt; + old.dayEndsAt = dayEndsAt; old.weekEndsAt = weekEndsAt; old.serverNow = nowMs; applyLocks(old.dailyTasks); @@ -85,6 +91,7 @@ export function refreshTaskData( version: 2, dayKey, weekKey, + dayEndsAt, weekEndsAt, serverNow: nowMs, dailyTasks: selectDailyTasks(uid, dayKey, Math.max(1, level), previousTaskIds), diff --git a/laf-cloud/tests/daily-task-v2.test.mjs b/laf-cloud/tests/daily-task-v2.test.mjs index cd8974b..fc4d493 100644 --- a/laf-cloud/tests/daily-task-v2.test.mjs +++ b/laf-cloud/tests/daily-task-v2.test.mjs @@ -12,11 +12,12 @@ registerHooks({ }, }); -const { getDayKey, getWeekKey, getWeekEndsAt, refreshTaskData, mergeClientProgress, claimDaily, claimWeekly } = await import(serviceUrl); +const { getDayKey, getDayEndsAt, getWeekKey, getWeekEndsAt, refreshTaskData, mergeClientProgress, claimDaily, claimWeekly } = await import(serviceUrl); test("uses Shanghai natural day and Monday week keys", () => { assert.equal(getDayKey(Date.parse("2026-09-06T15:59:59Z")), "2026-09-06"); assert.equal(getDayKey(Date.parse("2026-09-06T16:00:00Z")), "2026-09-07"); + assert.equal(getDayEndsAt(Date.parse("2026-09-06T16:00:00Z")), Date.parse("2026-09-08T00:00:00+08:00")); assert.equal(getWeekKey(Date.parse("2026-09-06T16:00:00Z")), "2026-09-07"); assert.equal(getWeekEndsAt(Date.parse("2026-09-06T16:00:00Z")), Date.parse("2026-09-14T00:00:00+08:00")); }); @@ -28,6 +29,7 @@ test("returns current server time and refreshes it on repeated reads", () => { const second = refreshTaskData(JSON.stringify(first), "user-time", 20, secondNow); assert.equal(second.changed, false); assert.equal(second.data.serverNow, secondNow); + assert.equal(second.data.dayEndsAt, Date.parse("2026-09-08T00:00:00+08:00")); assert.equal(second.data.weekEndsAt, Date.parse("2026-09-14T00:00:00+08:00")); });