mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 16:05:39 +00:00
55 lines
2.2 KiB
TypeScript
55 lines
2.2 KiB
TypeScript
// Date helpers for the vacation responder. RFC 8621 `VacationResponse.fromDate`
|
|
// / `toDate` are UTCDate values ("2026-03-01T09:00:00Z"); the user types a
|
|
// local wall-clock time. Mirrors the webmail, which feeds a datetime-local
|
|
// input through `new Date(local).toISOString()` and displays with
|
|
// `utcToLocalDatetime`.
|
|
|
|
const pad = (n: number) => String(n).padStart(2, '0');
|
|
|
|
/** Accepts "YYYY-MM-DD", "YYYY-MM-DD HH:MM", "YYYY-MM-DDTHH:MM[:SS]". */
|
|
export function parseLocalInput(input: string): Date | null {
|
|
const trimmed = input.trim();
|
|
if (!trimmed) return null;
|
|
const m = /^(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2})(?::(\d{2}))?)?$/.exec(trimmed);
|
|
if (!m) return null;
|
|
const [, y, mo, d, hh = '0', mm = '0', ss = '0'] = m;
|
|
const date = new Date(Number(y), Number(mo) - 1, Number(d), Number(hh), Number(mm), Number(ss));
|
|
// Reject overflowed fields such as 2026-13-45.
|
|
if (
|
|
date.getFullYear() !== Number(y) ||
|
|
date.getMonth() !== Number(mo) - 1 ||
|
|
date.getDate() !== Number(d) ||
|
|
date.getHours() !== Number(hh) ||
|
|
date.getMinutes() !== Number(mm)
|
|
) {
|
|
return null;
|
|
}
|
|
return date;
|
|
}
|
|
|
|
/** Local wall-clock input -> JMAP UTCDate ISO string (or null when empty). */
|
|
export function localInputToUtcIso(input: string): string | null {
|
|
const date = parseLocalInput(input);
|
|
return date ? date.toISOString() : null;
|
|
}
|
|
|
|
/** Whether a non-empty input is syntactically valid. Empty is valid (unset). */
|
|
export function isValidLocalInput(input: string): boolean {
|
|
return !input.trim() || parseLocalInput(input) !== null;
|
|
}
|
|
|
|
/** JMAP UTCDate -> "YYYY-MM-DD HH:MM" in the device's local time zone. */
|
|
export function utcIsoToLocalInput(iso: string | null | undefined): string {
|
|
if (!iso) return '';
|
|
const d = new Date(iso);
|
|
if (Number.isNaN(d.getTime())) return '';
|
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
}
|
|
|
|
/** Normalise a stored date for change detection (null when unset/invalid). */
|
|
export function normalizeUtcIso(iso: string | null | undefined): string | null {
|
|
if (!iso) return null;
|
|
const d = new Date(iso);
|
|
return Number.isNaN(d.getTime()) ? null : d.toISOString();
|
|
}
|