UNPKG

@formatjs/intl-datetimeformat

Version:
267 lines (266 loc) 9.77 kB
import { CanonicalizeLocaleList, CanonicalizeTimeZoneName, IsValidTimeZoneName, OrdinaryHasInstance, SupportedLocales, ToNumber, defineProperty, invariant } from "@formatjs/ecma402-abstract"; import Decimal from "decimal.js"; import { FormatDateTime } from "./abstract/FormatDateTime.js"; import { FormatDateTimeRange } from "./abstract/FormatDateTimeRange.js"; import { FormatDateTimeRangeToParts } from "./abstract/FormatDateTimeRangeToParts.js"; import { FormatDateTimeToParts } from "./abstract/FormatDateTimeToParts.js"; import { InitializeDateTimeFormat } from "./abstract/InitializeDateTimeFormat.js"; import { parseDateTimeSkeleton } from "./abstract/skeleton.js"; import { DATE_TIME_PROPS } from "./abstract/utils.js"; import links from "./data/links.generated.js"; import getInternalSlots from "./get_internal_slots.js"; import { unpack } from "./packer.js"; import "./types.js"; const UPPERCASED_LINKS = Object.keys(links).reduce((all, l) => { all[l.toUpperCase()] = links[l]; return all; }, {}); const RESOLVED_OPTIONS_KEYS = [ "locale", "calendar", "numberingSystem", "dateStyle", "timeStyle", "timeZone", "hourCycle", "weekday", "era", "year", "month", "day", "hour", "minute", "second", "timeZoneName" ]; const formatDescriptor = { enumerable: false, configurable: true, get() { if (typeof this !== "object" || !OrdinaryHasInstance(DateTimeFormat, this)) { throw TypeError("Intl.DateTimeFormat format property accessor called on incompatible receiver"); } const internalSlots = getInternalSlots(this); // eslint-disable-next-line @typescript-eslint/no-this-alias const dtf = this; let boundFormat = internalSlots.boundFormat; if (boundFormat === undefined) { // https://tc39.es/proposal-unified-intl-numberformat/section11/numberformat_diff_out.html#sec-number-format-functions boundFormat = (date) => { let x; if (date === undefined) { x = new Decimal(Date.now()); } else { x = ToNumber(date); } return FormatDateTime(dtf, x, { getInternalSlots, localeData: DateTimeFormat.localeData, tzData: DateTimeFormat.tzData, getDefaultTimeZone: DateTimeFormat.getDefaultTimeZone }); }; try { // https://github.com/tc39/test262/blob/master/test/intl402/NumberFormat/prototype/format/format-function-name.js Object.defineProperty(boundFormat, "name", { configurable: true, enumerable: false, writable: false, value: "" }); } catch {} internalSlots.boundFormat = boundFormat; } return boundFormat; } }; try { // https://github.com/tc39/test262/blob/master/test/intl402/NumberFormat/prototype/format/name.js Object.defineProperty(formatDescriptor.get, "name", { configurable: true, enumerable: false, writable: false, value: "get format" }); } catch {} export const DateTimeFormat = function(locales, options) { // Cannot use `new.target` bc of IE11 & TS transpiles it to something else if (!this || !OrdinaryHasInstance(DateTimeFormat, this)) { return new DateTimeFormat(locales, options); } InitializeDateTimeFormat(this, locales, options, { tzData: DateTimeFormat.tzData, uppercaseLinks: UPPERCASED_LINKS, availableLocales: DateTimeFormat.availableLocales, relevantExtensionKeys: DateTimeFormat.relevantExtensionKeys, getDefaultLocale: DateTimeFormat.getDefaultLocale, getDefaultTimeZone: DateTimeFormat.getDefaultTimeZone, getInternalSlots, localeData: DateTimeFormat.localeData }); /** IMPL START */ const internalSlots = getInternalSlots(this); const dataLocale = internalSlots.dataLocale; const dataLocaleData = DateTimeFormat.localeData[dataLocale]; invariant(dataLocaleData !== undefined, `Cannot load locale-dependent data for ${dataLocale}.`); /** IMPL END */ }; // Static properties defineProperty(DateTimeFormat, "supportedLocalesOf", { value: function supportedLocalesOf(locales, options) { return SupportedLocales(DateTimeFormat.availableLocales, CanonicalizeLocaleList(locales), options); } }); defineProperty(DateTimeFormat.prototype, "resolvedOptions", { value: function resolvedOptions() { if (typeof this !== "object" || !OrdinaryHasInstance(DateTimeFormat, this)) { throw TypeError("Method Intl.DateTimeFormat.prototype.resolvedOptions called on incompatible receiver"); } const internalSlots = getInternalSlots(this); const ro = {}; for (const key of RESOLVED_OPTIONS_KEYS) { let value = internalSlots[key]; if (key === "hourCycle") { const hour12 = value === "h11" || value === "h12" ? true : value === "h23" || value === "h24" ? false : undefined; if (hour12 !== undefined) { ro.hour12 = hour12; } } if (DATE_TIME_PROPS.indexOf(key) > -1) { if (internalSlots.dateStyle !== undefined || internalSlots.timeStyle !== undefined) { value = undefined; } } if (value !== undefined) { ro[key] = value; } } return ro; } }); defineProperty(DateTimeFormat.prototype, "formatToParts", { value: function formatToParts(date) { let x; if (date === undefined) { x = new Decimal(Date.now()); } else { x = ToNumber(date); } return FormatDateTimeToParts(this, x, { getInternalSlots, localeData: DateTimeFormat.localeData, tzData: DateTimeFormat.tzData, getDefaultTimeZone: DateTimeFormat.getDefaultTimeZone }); } }); defineProperty(DateTimeFormat.prototype, "formatRangeToParts", { value: function formatRangeToParts(startDate, endDate) { // oxlint-disable-next-line no-this-alias const dtf = this; invariant(typeof dtf === "object", "receiver is not an object", TypeError); invariant(startDate !== undefined && endDate !== undefined, "startDate/endDate cannot be undefined", TypeError); return FormatDateTimeRangeToParts(dtf, ToNumber(startDate), ToNumber(endDate), { getInternalSlots, localeData: DateTimeFormat.localeData, tzData: DateTimeFormat.tzData, getDefaultTimeZone: DateTimeFormat.getDefaultTimeZone }); } }); defineProperty(DateTimeFormat.prototype, "formatRange", { value: function formatRange(startDate, endDate) { // oxlint-disable-next-line no-this-alias const dtf = this; invariant(typeof dtf === "object", "receiver is not an object", TypeError); invariant(startDate !== undefined && endDate !== undefined, "startDate/endDate cannot be undefined", TypeError); return FormatDateTimeRange(dtf, ToNumber(startDate), ToNumber(endDate), { getInternalSlots, localeData: DateTimeFormat.localeData, tzData: DateTimeFormat.tzData, getDefaultTimeZone: DateTimeFormat.getDefaultTimeZone }); } }); const DEFAULT_TIMEZONE = "UTC"; DateTimeFormat.__setDefaultTimeZone = (timeZone) => { if (timeZone !== undefined) { timeZone = String(timeZone); if (!IsValidTimeZoneName(timeZone, { zoneNamesFromData: Object.keys(DateTimeFormat.tzData), uppercaseLinks: UPPERCASED_LINKS })) { throw new RangeError("Invalid timeZoneName"); } timeZone = CanonicalizeTimeZoneName(timeZone, { zoneNames: Object.keys(DateTimeFormat.tzData), uppercaseLinks: UPPERCASED_LINKS }); } else { timeZone = DEFAULT_TIMEZONE; } DateTimeFormat.__defaultTimeZone = timeZone; }; DateTimeFormat.relevantExtensionKeys = [ "nu", "ca", "hc" ]; DateTimeFormat.__defaultTimeZone = DEFAULT_TIMEZONE; DateTimeFormat.getDefaultTimeZone = () => DateTimeFormat.__defaultTimeZone; DateTimeFormat.__addLocaleData = function __addLocaleData(...data) { for (const { data: d, locale } of data) { const { dateFormat, timeFormat, dateTimeFormat, formats, intervalFormats, ...rawData } = d; const processedData = { ...rawData, dateFormat: { full: parseDateTimeSkeleton(dateFormat.full), long: parseDateTimeSkeleton(dateFormat.long), medium: parseDateTimeSkeleton(dateFormat.medium), short: parseDateTimeSkeleton(dateFormat.short) }, timeFormat: { full: parseDateTimeSkeleton(timeFormat.full), long: parseDateTimeSkeleton(timeFormat.long), medium: parseDateTimeSkeleton(timeFormat.medium), short: parseDateTimeSkeleton(timeFormat.short) }, dateTimeFormat: { full: parseDateTimeSkeleton(dateTimeFormat.full).pattern, long: parseDateTimeSkeleton(dateTimeFormat.long).pattern, medium: parseDateTimeSkeleton(dateTimeFormat.medium).pattern, short: parseDateTimeSkeleton(dateTimeFormat.short).pattern }, intervalFormatFallback: intervalFormats.intervalFormatFallback, formats: {} }; for (const calendar in formats) { processedData.formats[calendar] = Object.keys(formats[calendar]).map((skeleton) => parseDateTimeSkeleton(skeleton, formats[calendar][skeleton], intervalFormats[skeleton], intervalFormats.intervalFormatFallback)); } const minimizedLocale = new Intl.Locale(locale).minimize().toString(); DateTimeFormat.localeData[locale] = DateTimeFormat.localeData[minimizedLocale] = processedData; DateTimeFormat.availableLocales.add(locale); DateTimeFormat.availableLocales.add(minimizedLocale); if (!DateTimeFormat.__defaultLocale) { DateTimeFormat.__defaultLocale = minimizedLocale; } } }; Object.defineProperty(DateTimeFormat.prototype, "format", formatDescriptor); DateTimeFormat.__defaultLocale = ""; DateTimeFormat.localeData = {}; DateTimeFormat.availableLocales = new Set(); DateTimeFormat.getDefaultLocale = () => { return DateTimeFormat.__defaultLocale; }; DateTimeFormat.polyfilled = true; DateTimeFormat.tzData = {}; DateTimeFormat.__addTZData = function(d) { DateTimeFormat.tzData = unpack(d); }; try { if (typeof Symbol !== "undefined") { Object.defineProperty(DateTimeFormat.prototype, Symbol.toStringTag, { value: "Intl.DateTimeFormat", writable: false, enumerable: false, configurable: true }); } Object.defineProperty(DateTimeFormat.prototype.constructor, "length", { value: 1, writable: false, enumerable: false, configurable: true }); } catch {}