UNPKG

edtf

Version:

Extended Date Time Format (EDTF) / ISO 8601-2 Parser and Library

138 lines (103 loc) 2.8 kB
import LC from '../locale-data/index.cjs' const { assign } = Object const noTime = { timeZone: 'UTC', timeZoneName: undefined, hour: undefined, minute: undefined, second: undefined } const DEFAULTS = [ {}, assign({ weekday: undefined, day: undefined, month: undefined }, noTime), assign({ weekday: undefined, day: undefined }, noTime), assign({}, noTime), ] function getCacheId(...args) { let id = [] for (let arg of args) { if (arg && typeof arg === 'object') { id.push(getOrderedProps(arg)) } else { id.push(arg) } } return JSON.stringify(id) } function getOrderedProps(obj) { let props = [] let keys = Object.getOwnPropertyNames(obj) for (let key of keys.sort()) { props.push({ [key]: obj[key] }) } return props } export function getFormat(date, locale, options) { let opts = {} switch (date.precision) { case 3: opts.day = 'numeric' // eslint-disable-next-line no-fallthrough case 2: opts.month = 'numeric' // eslint-disable-next-line no-fallthrough case 1: opts.year = 'numeric' break } assign(opts, options, DEFAULTS[date.precision]) let id = getCacheId(locale, opts) if (!format.cache.has(id)) { format.cache.set(id, new Intl.DateTimeFormat(locale, opts)) } return format.cache.get(id) } function getPatternsFor(fmt) { const { locale, weekday, month, year } = fmt.resolvedOptions() const lc = LC[locale] if (lc == null) return null const variant = (weekday || month === 'long') ? 'long' : (!month || year === '2-digit') ? 'short' : 'medium' return { approximate: lc.date.approximate[variant], uncertain: lc.date.uncertain[variant] } } function isDMY(type) { return type === 'day' || type === 'month' || type === 'year' } function mask(date, parts) { let string = '' for (let { type, value } of parts) { string += (isDMY(type) && date.unspecified.is(type)) ? value.replace(/./g, 'X') : value } return string } // eslint-disable-next-line complexity export function format(date, locale = 'en-US', options = {}) { const fmt = getFormat(date, locale, options) const pat = getPatternsFor(fmt) if (!date.isEDTF || pat == null) { return fmt.format(date) } if (date.type === 'Interval') { if (date.finite) { return fmt.formatRange(date.lower, date.upper) } else { throw new Error('cannot format infinite intervals') } } let string = (!date.unspecified.value || !fmt.formatToParts) ? fmt.format(date) : mask(date, fmt.formatToParts(date)) if (date.approximate.value) { string = pat.approximate.replace('%D', string) } if (date.uncertain.value) { string = pat.uncertain.replace('%D', string) } return string } format.cache = new Map()