84 lines
2.8 KiB
TypeScript
84 lines
2.8 KiB
TypeScript
export const TZ = 'America/Toronto'
|
|
|
|
/** YYYY-MM-DD for right now in Toronto */
|
|
export function todayToronto(): string {
|
|
return toDateToronto(new Date())
|
|
}
|
|
|
|
/** YYYY-MM-DD in Toronto for any Date */
|
|
export function toDateToronto(date: Date): string {
|
|
return new Intl.DateTimeFormat('en-CA', { timeZone: TZ }).format(date)
|
|
}
|
|
|
|
/**
|
|
* Add n calendar days to a YYYY-MM-DD string.
|
|
* Uses noon UTC so the shift is always exactly 24 h and never crosses
|
|
* a Toronto DST boundary ambiguously.
|
|
*/
|
|
export function addDays(isoDate: string, n: number): string {
|
|
const d = new Date(isoDate + 'T12:00:00Z')
|
|
d.setUTCDate(d.getUTCDate() + n)
|
|
return d.toISOString().slice(0, 10)
|
|
}
|
|
|
|
/** HH:MM in Toronto for a UTC ISO string */
|
|
export function fmtTime(utcIso: string): string {
|
|
return new Date(utcIso).toLocaleTimeString('en-CA', {
|
|
timeZone: TZ,
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false,
|
|
})
|
|
}
|
|
|
|
/** "Wednesday, April 20" style label for a YYYY-MM-DD string */
|
|
export function fmtDateLong(isoDate: string): string {
|
|
return new Date(isoDate + 'T12:00:00Z').toLocaleDateString('en-CA', {
|
|
timeZone: TZ,
|
|
weekday: 'long',
|
|
month: 'long',
|
|
day: 'numeric',
|
|
})
|
|
}
|
|
|
|
/** { weekday: "Wed", short: "Apr 20" } for a YYYY-MM-DD string */
|
|
export function fmtDayHeader(isoDate: string): { weekday: string; short: string } {
|
|
const d = new Date(isoDate + 'T12:00:00Z')
|
|
return {
|
|
weekday: d.toLocaleDateString('en-CA', { timeZone: TZ, weekday: 'short' }),
|
|
short: d.toLocaleDateString('en-CA', { timeZone: TZ, month: 'short', day: 'numeric' }),
|
|
}
|
|
}
|
|
|
|
/**
|
|
* YYYY-MM-DD of the Monday that starts the ISO week containing isoDate.
|
|
* Uses the en-CA weekday name to determine day-of-week in Toronto.
|
|
*/
|
|
export function weekMonday(isoDate: string): string {
|
|
const d = new Date(isoDate + 'T12:00:00Z')
|
|
const wd = new Intl.DateTimeFormat('en-CA', { timeZone: TZ, weekday: 'short' }).format(d)
|
|
const offsets: Record<string, number> = { Mon: 0, Tue: 1, Wed: 2, Thu: 3, Fri: 4, Sat: 5, Sun: 6 }
|
|
const offset = offsets[wd] ?? 0
|
|
const monday = new Date(d)
|
|
monday.setUTCDate(d.getUTCDate() - offset)
|
|
return monday.toISOString().slice(0, 10)
|
|
}
|
|
|
|
/** All 7 YYYY-MM-DD strings for the ISO week containing isoDate (Mon → Sun) */
|
|
export function weekDates(isoDate: string): string[] {
|
|
const mon = weekMonday(isoDate)
|
|
return Array.from({ length: 7 }, (_, i) => addDays(mon, i))
|
|
}
|
|
|
|
/**
|
|
* UTC range string pair that safely covers all Toronto-local timestamps
|
|
* falling within the isoFrom…isoTo date range.
|
|
* Adds a 1-day buffer on each side so client-side date filtering is authoritative.
|
|
*/
|
|
export function utcRange(isoFrom: string, isoTo: string): { from: string; to: string } {
|
|
return {
|
|
from: addDays(isoFrom, -1) + 'T00:00:00Z',
|
|
to: addDays(isoTo, +1) + 'T23:59:59Z',
|
|
}
|
|
}
|