UNPKG

@burglekitt/gmt

Version:

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

46 lines (45 loc) 1.84 kB
import { Temporal } from "@js-temporal/polyfill"; import { isValidZonedDateTime } from "../validate/index.js"; /** * Return the number of hours in the calendar day a zoned datetime falls on. * * - Accounts for DST transitions: a spring-forward day is 23 hours, a fall-back * day is 25 hours, and a normal day is 24 hours. Zones whose DST shift isn't * a whole hour (e.g. `Australia/Lord_Howe`'s 30-minute shift) return a * fractional value instead, such as 23.5 or 24.5. * - The calculation is based on the local calendar day of the input, not the * UTC instant. * - Returns null for invalid input. * * @param value zoned ISO 8601 datetime string * @returns number of hours in the day (usually 23, 24, or 25; fractional for * non-whole-hour DST shifts), or null on invalid input * * @example getHoursInZonedDay("2024-03-10T12:00:00-04:00[America/New_York]") // 23 * @example getHoursInZonedDay("2024-11-03T12:00:00-05:00[America/New_York]") // 25 * @example getHoursInZonedDay("2024-02-29T12:00:00+00:00[UTC]") // 24 * @example getHoursInZonedDay("2024-10-06T12:00:00+11:00[Australia/Lord_Howe]") // 23.5 * @example getHoursInZonedDay("invalid") // null */ export function getHoursInZonedDay(value) { if (!isValidZonedDateTime(value)) { return null; } try { const zonedDateTime = Temporal.ZonedDateTime.from(value); const startOfDay = zonedDateTime.with({ hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0, }); const nextDay = startOfDay.add({ days: 1 }); const duration = startOfDay.until(nextDay); return duration.total({ unit: "hours" }); } catch { return null; } }