UNPKG

@burglekitt/gmt

Version:

Temporal-based date and time utilities with timezone support and polyfill integration

123 lines (122 loc) 4.92 kB
import { Temporal } from "@js-temporal/polyfill"; import { isValidDateTimeUnit } from "../../plain/index.js"; import { isValidUnixUnit } from "../../unix/validate/isValidUnixUnit.js"; import { getSystemTimeZone } from "../../zoned/get/index.js"; import { isValidTimeZone } from "../../zoned/validate/index.js"; export function startOrEndOfUnix(value, unit, options, isEnd) { const epochUnit = options.epochUnit ?? "milliseconds"; const timeZone = options.timeZone ?? getSystemTimeZone(); const weekStartsOn = options.weekStartsOn ?? "monday"; const disambiguation = options.disambiguation ?? "compatible"; const offset = options.offset ?? "ignore"; if (!timeZone || !isValidDateTimeUnit(unit) || !isValidTimeZone(timeZone) || !isValidUnixUnit(epochUnit)) { return null; } if (!Number.isFinite(value) || !Number.isInteger(value)) { return null; } try { const epochMs = epochUnit === "seconds" ? value * 1000 : value; const instant = Temporal.Instant.fromEpochMilliseconds(epochMs); const source = instant.toZonedDateTimeISO(timeZone); const timeFields = isEnd ? { hour: 23, minute: 59, second: 59, millisecond: 999, microsecond: 999, nanosecond: 999, } : { hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0, }; let result; switch (unit) { case "year": result = isEnd ? source.with({ month: 12, day: 31, ...timeFields }, { disambiguation, offset }) : source.with({ month: 1, day: 1, ...timeFields }, { disambiguation, offset }); break; case "month": { const lastDay = Temporal.PlainDate.from({ year: source.year, month: source.month, day: 1, }).daysInMonth; result = isEnd ? source.with({ day: lastDay, ...timeFields }, { disambiguation, offset }) : source.with({ day: 1, ...timeFields }, { disambiguation, offset }); break; } case "week": { const daysToSubtract = weekStartsOn === "monday" ? source.dayOfWeek - 1 : source.dayOfWeek % 7; const weekAnchor = source.subtract({ days: daysToSubtract }); result = isEnd ? weekAnchor .add({ days: 6 }) .with({ ...timeFields }, { disambiguation, offset }) : weekAnchor.with({ ...timeFields }, { disambiguation, offset }); break; } case "day": result = source.with({ ...timeFields }, { disambiguation, offset }); break; case "hour": result = source.with({ minute: timeFields.minute, second: timeFields.second, millisecond: timeFields.millisecond, microsecond: timeFields.microsecond, nanosecond: timeFields.nanosecond, }, { disambiguation, offset }); break; case "minute": result = source.with({ second: timeFields.second, millisecond: timeFields.millisecond, microsecond: timeFields.microsecond, nanosecond: timeFields.nanosecond, }, { disambiguation, offset }); break; case "second": result = source.with({ millisecond: timeFields.millisecond, microsecond: timeFields.microsecond, nanosecond: timeFields.nanosecond, }, { disambiguation, offset }); break; case "millisecond": result = source.with({ microsecond: timeFields.microsecond, nanosecond: timeFields.nanosecond, }, { disambiguation, offset }); break; case "microsecond": result = source.with({ nanosecond: timeFields.nanosecond }, { disambiguation, offset }); break; case "nanosecond": result = source; break; default: return null; } const epoch = epochUnit === "seconds" ? Math.floor(result.epochMilliseconds / 1000) : result.epochMilliseconds; return epoch; } catch { return null; } }