feat(expiry): KST util — todayInKstString + nextKstMidnightMs (#5 v0.2.3)
This commit is contained in:
28
src/main/util/kstDate.ts
Normal file
28
src/main/util/kstDate.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
const KST_OFFSET_MS = 9 * 60 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* Calendar date (YYYY-MM-DD) in Asia/Seoul timezone for the given instant.
|
||||
*
|
||||
* v0.2.3 #5 — used by NoteRepository.findExpiredCandidates to compare against
|
||||
* notes.due_date (also stored as YYYY-MM-DD per slice §F1).
|
||||
*/
|
||||
export function todayInKstString(now: Date): string {
|
||||
const k = new Date(now.getTime() + KST_OFFSET_MS);
|
||||
return new Date(
|
||||
Date.UTC(k.getUTCFullYear(), k.getUTCMonth(), k.getUTCDate())
|
||||
).toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Epoch ms of the next 00:00 KST strictly after `now`.
|
||||
*
|
||||
* v0.2.3 #5 — used by store.snoozeExpired to compute the in-memory snooze
|
||||
* deadline ("오늘 그만").
|
||||
*/
|
||||
export function nextKstMidnightMs(now: number): number {
|
||||
const kstNow = now + KST_OFFSET_MS;
|
||||
// Floor to KST midnight, then add one day.
|
||||
const kstMidnightFloor = Math.floor(kstNow / 86_400_000) * 86_400_000;
|
||||
const nextKstMidnight = kstMidnightFloor + 86_400_000;
|
||||
return nextKstMidnight - KST_OFFSET_MS;
|
||||
}
|
||||
37
tests/unit/kstDate.test.ts
Normal file
37
tests/unit/kstDate.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { todayInKstString, nextKstMidnightMs } from '@main/util/kstDate.js';
|
||||
|
||||
describe('todayInKstString', () => {
|
||||
it('returns KST calendar date as YYYY-MM-DD', () => {
|
||||
// 2026-05-01 12:00 UTC = 2026-05-01 21:00 KST
|
||||
expect(todayInKstString(new Date('2026-05-01T12:00:00Z'))).toBe('2026-05-01');
|
||||
});
|
||||
|
||||
it('handles UTC→KST date rollover (UTC 23:30 → KST next day 08:30)', () => {
|
||||
expect(todayInKstString(new Date('2026-05-01T23:30:00Z'))).toBe('2026-05-02');
|
||||
});
|
||||
|
||||
it('handles KST midnight exactly (UTC 15:00 = KST 00:00 next day)', () => {
|
||||
expect(todayInKstString(new Date('2026-05-01T15:00:00Z'))).toBe('2026-05-02');
|
||||
});
|
||||
});
|
||||
|
||||
describe('nextKstMidnightMs', () => {
|
||||
it('returns the next KST 00:00 epoch ms (UTC 12:00 → +12h to KST midnight)', () => {
|
||||
// 2026-05-01 12:00 UTC = 2026-05-01 21:00 KST → 다음 KST 자정 = 2026-05-02 00:00 KST
|
||||
// = 2026-05-01 15:00 UTC
|
||||
const now = Date.parse('2026-05-01T12:00:00Z');
|
||||
const next = nextKstMidnightMs(now);
|
||||
expect(new Date(next).toISOString()).toBe('2026-05-01T15:00:00.000Z');
|
||||
});
|
||||
|
||||
it('returns 24h-from-now-ish when called shortly after KST midnight', () => {
|
||||
// 2026-05-01 15:01 UTC = 2026-05-02 00:01 KST → 다음 KST 자정 = 2026-05-03 00:00 KST
|
||||
// = 2026-05-02 15:00 UTC (≈ 23h59m later)
|
||||
const now = Date.parse('2026-05-01T15:01:00Z');
|
||||
const next = nextKstMidnightMs(now);
|
||||
expect(new Date(next).toISOString()).toBe('2026-05-02T15:00:00.000Z');
|
||||
expect(next - now).toBeGreaterThan(23 * 60 * 60 * 1000);
|
||||
expect(next - now).toBeLessThan(24 * 60 * 60 * 1000);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user