UNPKG

datezone

Version:

A lightweight and comprehensive date and timeZone utility library for JavaScript.

278 lines 9.15 kB
import { getCachedFormatterLocale } from "./cache.js"; import { calendarToTimestamp, timestampToCalendar } from "./calendar.pub.js"; import { getUTCtoTimezoneOffsetMinutes } from "./offset.pub.js"; import { isDST, isUTC } from "./timezone.pub.js"; import { isLeapYearBase } from "./year.pub.js"; /** * Add days. * * @param ts - The timestamp. * @param days - The number of days to add. * @param timeZone - The timezone. * @returns The new timestamp. * @see https://datezone.dev/docs/reference/day#adddays */ export function addDays(ts, days, timeZone) { // Fast path: local time if (timeZone === null) { const d = new Date(ts); d.setDate(d.getDate() + days); return d.getTime(); } // Fast path: UTC or fixed offset (no DST) if (isUTC(timeZone) || !isDST(timeZone)) { return ts + days * 86400000; } // For DST zones, check if offset changes const offsetStart = getUTCtoTimezoneOffsetMinutes(ts, timeZone); const tsEnd = ts + days * 86400000; const offsetEnd = getUTCtoTimezoneOffsetMinutes(tsEnd, timeZone); if (offsetStart === offsetEnd) { return tsEnd; } // Fallback: full calendar conversion (handles DST transitions) const { year, month, day, hour, minute, second, millisecond } = timestampToCalendar(ts, timeZone); return calendarToTimestamp(year, month, day + days, hour, minute, second, millisecond, timeZone); } /** * Subtract days. * * @param ts - The timestamp. * @param days - The number of days to subtract. * @param timeZone - The timezone. * @returns The new timestamp. * @see https://datezone.dev/docs/reference/day#subdays */ export function subDays(ts, days, timeZone) { return addDays(ts, -days, timeZone); } /** * Start of day. * * @param ts - The timestamp. * @param timeZone - The timezone. * @returns The timestamp for the start of the day. * @see https://datezone.dev/docs/reference/day#startofday */ export function startOfDay(ts, timeZone) { if (timeZone === null) { const d = new Date(ts); d.setHours(0, 0, 0, 0); return d.getTime(); } if (timeZone !== null && (isUTC(timeZone) || !isDST(timeZone))) { const offset = getUTCtoTimezoneOffsetMinutes(ts, timeZone); const d = new Date(ts + offset * 60000); return (Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), 0, 0, 0, 0) - offset * 60000); } // For DST zones, check if offset changes const offsetStart = getUTCtoTimezoneOffsetMinutes(ts, timeZone); const { year, month, day } = timestampToCalendar(ts, timeZone); const startOfDayTs = calendarToTimestamp(year, month, day, 0, 0, 0, 0, timeZone); const offsetDayStart = getUTCtoTimezoneOffsetMinutes(startOfDayTs, timeZone); if (offsetStart === offsetDayStart) { return startOfDayTs; } // Fallback: full calendar conversion return startOfDayTs; } /** * End of day. * * @param ts - The timestamp. * @param timeZone - The timezone. * @returns The timestamp for the end of the day. * @see https://datezone.dev/docs/reference/day#endofday */ export function endOfDay(ts, timeZone) { // Fast path: local time if (timeZone === null) { const d = new Date(ts); d.setHours(23, 59, 59, 999); return d.getTime(); } // Fast path: UTC or fixed offset (no DST) if (isUTC(timeZone) || !isDST(timeZone)) { const offset = getUTCtoTimezoneOffsetMinutes(ts, timeZone); const d = new Date(ts + offset * 60000); return (Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), 23, 59, 59, 999) - offset * 60000); } // For DST zones, check if offset changes const offsetStart = getUTCtoTimezoneOffsetMinutes(ts, timeZone); const { year, month, day } = timestampToCalendar(ts, timeZone); const endOfDayTs = calendarToTimestamp(year, month, day, 23, 59, 59, 999, timeZone); const offsetDayEnd = getUTCtoTimezoneOffsetMinutes(endOfDayTs, timeZone); if (offsetStart === offsetDayEnd) { return endOfDayTs; } // Fallback: full calendar conversion return endOfDayTs; } /** * Day of month. * * @param ts - The timestamp. * @param timeZone - The timezone. * @returns The day of the month. * @see https://datezone.dev/docs/reference/day#dayofmonth */ export function dayOfMonth(ts, timeZone) { return timestampToCalendar(ts, timeZone).day; } /** * Get day of week using Javascript Standard 0 = Sunday, 6 = Saturday * * @deprecated Use {@link dayOfWeek} instead that follows ISO standard. * @param ts - The timestamp. * @param timeZone - The timezone. * @returns The JavaScript day of the week (0=Sunday, 6=Saturday). * @see https://datezone.dev/docs/reference/day#getday */ export function getDay(ts, timeZone) { const isoDay = dayOfWeek(ts, timeZone); // Convert ISO day (1=Monday, 7=Sunday) to JS day (0=Sunday, 6=Saturday) return isoDay % 7; } /** * Day of week. * * @param ts - The timestamp. * @param timeZone - The timezone. * @returns The ISO day of the week. * @see https://datezone.dev/docs/reference/day#dayofweek */ export function dayOfWeek(ts, timeZone) { // Fast path: local time if (timeZone === null) { const d = new Date(ts); const jsDay = d.getDay(); return jsDay === 0 ? 7 : jsDay; } // Fast path: UTC or fixed offset (no DST) if (isUTC(timeZone) || !isDST(timeZone)) { const offset = getUTCtoTimezoneOffsetMinutes(ts, timeZone); const d = new Date(ts + offset * 60000); const jsDay = d.getDay(); return ((jsDay + 6) % 7) + 1; } // For DST zones, check if offset changes const offsetStart = getUTCtoTimezoneOffsetMinutes(ts, timeZone); const { year, month, day } = timestampToCalendar(ts, timeZone); const dayOfWeekTs = calendarToTimestamp(year, month, day, 0, 0, 0, 0, timeZone); const offsetDayOfWeek = getUTCtoTimezoneOffsetMinutes(dayOfWeekTs, timeZone); if (offsetStart === offsetDayOfWeek) { return dayOfWeekBase(year, month, day); } // Fallback: full calendar conversion return dayOfWeekBase(year, month, day); } /** * Day of week base. * * @param year - The year. * @param month - The month (1-12). * @param day - The day (1-31). * @returns The ISO day of the week. * @see https://datezone.dev/docs/reference/day#dayofweekbase */ export function dayOfWeekBase(year, month, day) { // Zeller's congruence, ISO: 1=Monday, 7=Sunday let m = month; let y = year; if (m < 3) { m += 12; y -= 1; } const K = y % 100; const J = Math.floor(y / 100); const h = (day + Math.floor((13 * (m + 1)) / 5) + K + Math.floor(K / 4) + Math.floor(J / 4) + 5 * J) % 7; // Zeller's: 0=Saturday, 1=Sunday, 2=Monday, ..., 6=Friday // ISO: 1=Monday, ..., 7=Sunday return ((h + 5) % 7) + 1; } /** * Day of year. * * @param ts - The timestamp. * @param timeZone - The timezone. * @returns The day of the year. * @see https://datezone.dev/docs/reference/day#dayofyear */ export function dayOfYear(ts, timeZone) { // Fast path: local time if (timeZone === null) { const d = new Date(ts); const startOfYear = new Date(d.getFullYear(), 0, 1); const diff = ts - startOfYear.getTime(); return Math.floor(diff / 86400000) + 1; } const { year, month, day } = timestampToCalendar(ts, timeZone ?? null); return dayOfYearBase(year, month, day); } export function dayOfYearBase(year, month, day) { const monthDays = [ 31, isLeapYearBase(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, ]; let doy = 0; for (let i = 0; i < month - 1; i++) { doy += monthDays[i]; } doy += day; return doy; } /** * Week day name. * * @param locale - The locale string. * @param type - The format of the name ("long", "short", or "narrow"). * @param day - The ISO day of the week (1=Monday, 7=Sunday). * @returns The localized weekday name. * @see https://datezone.dev/docs/reference/day#weekdayname */ export function weekDayName(locale, type, day) { const fmt = getCachedFormatterLocale(locale, { timeZone: "UTC", weekday: type, }); // Convert from ISO (1=Monday) to JS (0=Sunday) const jsDay = (day - 1 + 7) % 7; return fmt.format(new Date(Date.UTC(2000, 0, jsDay + 3))); } /** * Get day period. * * @param locale The locale string. * @param hour The hour (0-23). * @returns The localized day period string. * @see https://datezone.dev/docs/reference/day#getdayperiod */ export function getDayPeriod(locale, hour) { const fmt = getCachedFormatterLocale(locale, { hour: "numeric", hour12: true, timeZone: "UTC", }); const parts = fmt.formatToParts(new Date(Date.UTC(2000, 0, 1, hour))); return (parts.find((p) => p.type === "dayPeriod")?.value || (hour < 12 ? "AM" : "PM")); } //# sourceMappingURL=day.pub.js.map