/** * lib/taipei-time.ts 測試(fix/console-truth-audit): * 1. server 版跨日案例——UTC 傍晚已是台北隔天(時區 bug 的核心場景)。 * 2. client 版(TAIPEI_CLIENT_JS,內嵌進 console 頁的 ES5 字串)用 new Function 求值, * 與 server 版逐案對照——兩份實作漂移會直接紅,這是「同一套 helper」的客觀證據。 * 3. leo 實測案例:leo21c /credentials 的 gitea_token created_at=1783349834(epoch 秒) * → 台北 2026-07-06 22:57(顯示 7/6 是真的,但原本只顯示日期且吃裝置時區——本修加時分固定台北)。 */ import { describe, it, expect } from 'vitest'; import { TAIPEI_CLIENT_JS, taipeiDayKey, taipeiDateStr, taipeiDateTimeStr, taipeiTimeStr, } from '../src/lib/taipei-time'; // client 版求值:跟頁面一樣把字串當 JS 跑起來,拿到同名函式 const client = new Function( `${TAIPEI_CLIENT_JS}; return { taipeiDayKey, taipeiDateStr, taipeiDateTimeStr, taipeiTimeStr, taipeiMonthDay };`, )() as { taipeiDayKey: (ms: number) => string; taipeiDateStr: (ms: number) => string; taipeiDateTimeStr: (ms: number) => string; taipeiTimeStr: (ms: number) => string; taipeiMonthDay: (ms: number) => { month: number; day: number }; }; describe('taipei-time — server 版', () => { it('UTC 16:30 已是台北隔天 00:30(跨日核心案例)', () => { const ms = Date.parse('2026-07-06T16:30:00Z'); expect(taipeiDayKey(ms)).toBe('2026-07-07'); expect(taipeiDateTimeStr(ms)).toBe('2026-07-07 00:30'); }); it('UTC 15:59 仍是台北同日 23:59(跨日邊界的另一側)', () => { const ms = Date.parse('2026-07-06T15:59:00Z'); expect(taipeiDayKey(ms)).toBe('2026-07-06'); expect(taipeiDateTimeStr(ms)).toBe('2026-07-06 23:59'); }); it('跨月/跨年也對:UTC 12-31 20:00 → 台北 01-01 04:00', () => { const ms = Date.parse('2026-12-31T20:00:00Z'); expect(taipeiDateStr(ms)).toBe('2027-01-01'); expect(taipeiTimeStr(ms)).toBe('04:00:00'); }); it('leo 實測值:credentials created_at=1783349834(epoch 秒)→ 台北 2026-07-06 22:57', () => { expect(taipeiDateTimeStr(1783349834 * 1000)).toBe('2026-07-06 22:57'); // 同一時刻 UTC 是 14:57——若顯示端誤用 UTC 或別的裝置時區,日期/時間就會漂 expect(new Date(1783349834 * 1000).toISOString().slice(0, 16)).toBe('2026-07-06T14:57'); }); }); describe('taipei-time — client 版(TAIPEI_CLIENT_JS)與 server 版等價', () => { const cases = [ Date.parse('2026-07-06T16:30:00Z'), // 跨日 Date.parse('2026-07-06T15:59:59Z'), // 跨日邊界前一秒 Date.parse('2026-12-31T20:00:00Z'), // 跨年 Date.parse('2026-02-28T17:00:00Z'), // 跨月(非閏年 2 月) 1783349834 * 1000, // leo 實測 credential created_at 0, // epoch 起點(1970-01-01 08:00 台北) ]; it('taipeiDayKey / DateStr / DateTimeStr / TimeStr 全案例一致', () => { for (const ms of cases) { expect(client.taipeiDayKey(ms)).toBe(taipeiDayKey(ms)); expect(client.taipeiDateStr(ms)).toBe(taipeiDateStr(ms)); expect(client.taipeiDateTimeStr(ms)).toBe(taipeiDateTimeStr(ms)); expect(client.taipeiTimeStr(ms)).toBe(taipeiTimeStr(ms)); } }); it('taipeiMonthDay(頁首中文日期用):跨日案例回台北的月/日', () => { expect(client.taipeiMonthDay(Date.parse('2026-07-06T16:30:00Z'))).toEqual({ month: 7, day: 7 }); expect(client.taipeiMonthDay(Date.parse('2026-12-31T20:00:00Z'))).toEqual({ month: 1, day: 1 }); }); });