- Add GETTING_STARTED.md with quick start guide and development modes - Add INSTALL.sh automated installation script - Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md - Add QUICK_REFERENCE.md for common commands - Add SETUP_GUIDE.md with detailed setup instructions - Update README.md with improved project overview - Add did-wallet app dependencies and node_modules
559 lines
20 KiB
TypeScript
559 lines
20 KiB
TypeScript
import * as ES from './ecmascript';
|
|
import { GetIntrinsic } from './intrinsicclass';
|
|
import {
|
|
GetSlot,
|
|
ISO_YEAR,
|
|
ISO_MONTH,
|
|
ISO_DAY,
|
|
ISO_HOUR,
|
|
ISO_MINUTE,
|
|
ISO_SECOND,
|
|
ISO_MILLISECOND,
|
|
ISO_MICROSECOND,
|
|
ISO_NANOSECOND,
|
|
CALENDAR
|
|
} from './slots';
|
|
import type { Temporal, Intl } from '..';
|
|
import type { DateTimeFormatParams as Params, DateTimeFormatReturn as Return } from './internaltypes';
|
|
|
|
const DATE = Symbol('date');
|
|
const YM = Symbol('ym');
|
|
const MD = Symbol('md');
|
|
const TIME = Symbol('time');
|
|
const DATETIME = Symbol('datetime');
|
|
const INST = Symbol('instant');
|
|
const ORIGINAL = Symbol('original');
|
|
const TZ_RESOLVED = Symbol('timezone');
|
|
const CAL_ID = Symbol('calendar-id');
|
|
const LOCALE = Symbol('locale');
|
|
const OPTIONS = Symbol('options');
|
|
|
|
const descriptor = <T extends (...args: any[]) => any>(value: T) => {
|
|
return {
|
|
value,
|
|
enumerable: true,
|
|
writable: false,
|
|
configurable: true
|
|
};
|
|
};
|
|
|
|
const IntlDateTimeFormat = globalThis.Intl.DateTimeFormat;
|
|
const ObjectAssign = Object.assign;
|
|
const ObjectHasOwnProperty = Object.prototype.hasOwnProperty;
|
|
const ReflectApply = Reflect.apply;
|
|
|
|
interface CustomFormatters {
|
|
[DATE]: typeof dateAmend | globalThis.Intl.DateTimeFormat;
|
|
[YM]: typeof yearMonthAmend | typeof globalThis.Intl.DateTimeFormat;
|
|
[MD]: typeof monthDayAmend | typeof globalThis.Intl.DateTimeFormat;
|
|
[TIME]: typeof timeAmend | typeof globalThis.Intl.DateTimeFormat;
|
|
[DATETIME]: typeof datetimeAmend | typeof globalThis.Intl.DateTimeFormat;
|
|
[INST]: typeof instantAmend | typeof globalThis.Intl.DateTimeFormat;
|
|
}
|
|
|
|
interface PrivateProps extends CustomFormatters {
|
|
[ORIGINAL]: globalThis.Intl.DateTimeFormat;
|
|
[TZ_RESOLVED]: string | Temporal.TimeZoneProtocol;
|
|
[CAL_ID]: globalThis.Intl.ResolvedDateTimeFormatOptions['calendar'];
|
|
[LOCALE]: globalThis.Intl.ResolvedDateTimeFormatOptions['locale'];
|
|
[OPTIONS]: Intl.DateTimeFormatOptions;
|
|
}
|
|
|
|
type OptionsAmenderFunction = (options: Intl.DateTimeFormatOptions) => globalThis.Intl.DateTimeFormatOptions;
|
|
type FormatterOrAmender = globalThis.Intl.DateTimeFormat | OptionsAmenderFunction;
|
|
|
|
// Construction of built-in Intl.DateTimeFormat objects is sloooooow,
|
|
// so we'll only create those instances when we need them.
|
|
// See https://bugs.chromium.org/p/v8/issues/detail?id=6528
|
|
function getPropLazy<T extends PrivateProps, P extends keyof CustomFormatters>(
|
|
obj: T,
|
|
prop: P
|
|
): globalThis.Intl.DateTimeFormat {
|
|
let val = obj[prop] as FormatterOrAmender;
|
|
if (typeof val === 'function') {
|
|
// If we get here, `val` is an "amender function". It will take the user's
|
|
// options and transform them into suitable options to be passed into the
|
|
// built-in (non-polyfill) Intl.DateTimeFormat constructor. These options
|
|
// will vary depending on the Temporal type, so that's why we store separate
|
|
// formatters in separate props on the polyfill's DateTimeFormat instances.
|
|
// The efficiency happens because we don't create an (expensive) formatter
|
|
// until the user calls toLocaleString for that Temporal type.
|
|
val = new IntlDateTimeFormat(obj[LOCALE], val(obj[OPTIONS]));
|
|
// TODO: can this be typed more cleanly?
|
|
(obj[prop] as globalThis.Intl.DateTimeFormat) = val;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
type DateTimeFormatImpl = Intl.DateTimeFormat & PrivateProps;
|
|
|
|
function DateTimeFormatImpl(
|
|
this: Intl.DateTimeFormat & PrivateProps,
|
|
locale: Params['constructor'][0] = undefined,
|
|
optionsParam: Params['constructor'][1] = {}
|
|
) {
|
|
if (!(this instanceof DateTimeFormatImpl)) {
|
|
type Construct = new (
|
|
locale: Params['constructor'][0],
|
|
optionsParam: Params['constructor'][1]
|
|
) => Intl.DateTimeFormat;
|
|
return new (DateTimeFormatImpl as unknown as Construct)(locale, optionsParam);
|
|
}
|
|
const hasOptions = typeof optionsParam !== 'undefined';
|
|
const options = hasOptions ? ObjectAssign({}, optionsParam) : {};
|
|
// TODO: remove type assertion after Temporal types land in TS lib types
|
|
const original = new IntlDateTimeFormat(locale, options as globalThis.Intl.DateTimeFormatOptions);
|
|
const ro = original.resolvedOptions();
|
|
|
|
// DateTimeFormat instances are very expensive to create. Therefore, they will
|
|
// be lazily created only when needed, using the locale and options provided.
|
|
// But it's possible for callers to mutate those inputs before lazy creation
|
|
// happens. For this reason, we clone the inputs instead of caching the
|
|
// original objects. To avoid the complexity of deep cloning any inputs that
|
|
// are themselves objects (e.g. the locales array, or options property values
|
|
// that will be coerced to strings), we rely on `resolvedOptions()` to do the
|
|
// coercion and cloning for us. Unfortunately, we can't just use the resolved
|
|
// options as-is because our options-amending logic adds additional fields if
|
|
// the user doesn't supply any unit fields like year, month, day, hour, etc.
|
|
// Therefore, we limit the properties in the clone to properties that were
|
|
// present in the original input.
|
|
if (hasOptions) {
|
|
const clonedResolved = ObjectAssign({}, ro);
|
|
for (const prop in clonedResolved) {
|
|
if (!ReflectApply(ObjectHasOwnProperty, options, [prop])) {
|
|
delete clonedResolved[prop as keyof typeof clonedResolved];
|
|
}
|
|
}
|
|
this[OPTIONS] = clonedResolved as Intl.DateTimeFormatOptions;
|
|
} else {
|
|
this[OPTIONS] = options;
|
|
}
|
|
|
|
this[LOCALE] = ro.locale;
|
|
this[ORIGINAL] = original;
|
|
this[TZ_RESOLVED] = ro.timeZone;
|
|
this[CAL_ID] = ro.calendar;
|
|
this[DATE] = dateAmend;
|
|
this[YM] = yearMonthAmend;
|
|
this[MD] = monthDayAmend;
|
|
this[TIME] = timeAmend;
|
|
this[DATETIME] = datetimeAmend;
|
|
this[INST] = instantAmend;
|
|
return undefined; // TODO: I couldn't satisfy TS without adding this. Is there another way?
|
|
}
|
|
|
|
Object.defineProperty(DateTimeFormatImpl, 'name', {
|
|
writable: true,
|
|
value: 'DateTimeFormat'
|
|
});
|
|
|
|
DateTimeFormatImpl.supportedLocalesOf = function (
|
|
locales: Params['supportedLocalesOf'][0],
|
|
options: Params['supportedLocalesOf'][1]
|
|
) {
|
|
return IntlDateTimeFormat.supportedLocalesOf(locales, options as globalThis.Intl.DateTimeFormatOptions);
|
|
};
|
|
|
|
const propertyDescriptors: Partial<Record<keyof Intl.DateTimeFormat, PropertyDescriptor>> = {
|
|
resolvedOptions: descriptor(resolvedOptions),
|
|
format: descriptor(format),
|
|
formatRange: descriptor(formatRange)
|
|
};
|
|
|
|
if ('formatToParts' in IntlDateTimeFormat.prototype) {
|
|
propertyDescriptors.formatToParts = descriptor(formatToParts);
|
|
}
|
|
|
|
if ('formatRangeToParts' in IntlDateTimeFormat.prototype) {
|
|
propertyDescriptors.formatRangeToParts = descriptor(formatRangeToParts);
|
|
}
|
|
|
|
DateTimeFormatImpl.prototype = Object.create(IntlDateTimeFormat.prototype, propertyDescriptors);
|
|
|
|
// Ensure that the prototype isn't writeable.
|
|
Object.defineProperty(DateTimeFormatImpl, 'prototype', {
|
|
writable: false,
|
|
enumerable: false,
|
|
configurable: false
|
|
});
|
|
|
|
export const DateTimeFormat = DateTimeFormatImpl as unknown as typeof Intl.DateTimeFormat;
|
|
|
|
function resolvedOptions(this: DateTimeFormatImpl): Return['resolvedOptions'] {
|
|
return this[ORIGINAL].resolvedOptions();
|
|
}
|
|
|
|
// TODO: investigate why there's a rest parameter here. Does this function really need to accept extra params?
|
|
// And if so, why doesn't formatRange also accept extra params?
|
|
function format<P extends readonly unknown[]>(
|
|
this: DateTimeFormatImpl,
|
|
datetime: Params['format'][0],
|
|
...rest: P
|
|
): Return['format'] {
|
|
let { instant, formatter } = extractOverrides(datetime, this);
|
|
if (instant && formatter) {
|
|
return formatter.format(instant.epochMilliseconds);
|
|
}
|
|
// Support spreading additional args for future expansion of this Intl method
|
|
type AllowExtraParams = (datetime: Parameters<Intl.DateTimeFormat['format']>[0], ...rest: P) => Return['format'];
|
|
return (this[ORIGINAL].format as unknown as AllowExtraParams)(datetime, ...rest);
|
|
}
|
|
|
|
function formatToParts<P extends readonly unknown[]>(
|
|
this: DateTimeFormatImpl,
|
|
datetime: Params['formatToParts'][0],
|
|
...rest: P
|
|
): Return['formatToParts'] {
|
|
let { instant, formatter } = extractOverrides(datetime, this);
|
|
if (instant && formatter) {
|
|
return formatter.formatToParts(instant.epochMilliseconds);
|
|
}
|
|
// Support spreading additional args for future expansion of this Intl method
|
|
type AllowExtraParams = (
|
|
datetime: Parameters<Intl.DateTimeFormat['formatToParts']>[0],
|
|
...rest: P
|
|
) => Return['formatToParts'];
|
|
return (this[ORIGINAL].formatToParts as unknown as AllowExtraParams)(datetime, ...rest);
|
|
}
|
|
|
|
function formatRange(this: DateTimeFormatImpl, a: Params['formatRange'][0], b: Params['formatRange'][1]) {
|
|
if (isTemporalObject(a) || isTemporalObject(b)) {
|
|
if (!sameTemporalType(a, b)) {
|
|
throw new TypeError('Intl.DateTimeFormat.formatRange accepts two values of the same type');
|
|
}
|
|
const { instant: aa, formatter: aformatter } = extractOverrides(a as unknown as TypesWithToLocaleString, this);
|
|
const { instant: bb, formatter: bformatter } = extractOverrides(b as unknown as TypesWithToLocaleString, this);
|
|
if (aa && bb && aformatter && bformatter && aformatter === bformatter) {
|
|
// TODO: Remove type assertion after this method lands in TS lib types
|
|
return (aformatter as Intl.DateTimeFormat).formatRange(aa.epochMilliseconds, bb.epochMilliseconds);
|
|
}
|
|
}
|
|
// TODO: Remove type assertion after this method lands in TS lib types
|
|
return (this[ORIGINAL] as Intl.DateTimeFormat).formatRange(a, b);
|
|
}
|
|
|
|
function formatRangeToParts(
|
|
this: DateTimeFormatImpl,
|
|
a: Params['formatRangeToParts'][0],
|
|
b: Params['formatRangeToParts'][1]
|
|
) {
|
|
if (isTemporalObject(a) || isTemporalObject(b)) {
|
|
if (!sameTemporalType(a, b)) {
|
|
throw new TypeError('Intl.DateTimeFormat.formatRangeToParts accepts two values of the same type');
|
|
}
|
|
const { instant: aa, formatter: aformatter } = extractOverrides(a, this);
|
|
const { instant: bb, formatter: bformatter } = extractOverrides(b, this);
|
|
if (aa && bb && aformatter && bformatter && aformatter === bformatter) {
|
|
// TODO: Remove type assertion after this method lands in TS lib types
|
|
return (aformatter as Intl.DateTimeFormat).formatRangeToParts(aa.epochMilliseconds, bb.epochMilliseconds);
|
|
}
|
|
}
|
|
// TODO: Remove type assertion after this method lands in TS lib types
|
|
return (this[ORIGINAL] as Intl.DateTimeFormat).formatRangeToParts(a, b);
|
|
}
|
|
|
|
// "false" is a signal to delete this option
|
|
type MaybeFalseOptions = {
|
|
[K in keyof Intl.DateTimeFormatOptions]?: Intl.DateTimeFormatOptions[K] | false;
|
|
};
|
|
|
|
function amend(optionsParam: Intl.DateTimeFormatOptions = {}, amended: MaybeFalseOptions = {}) {
|
|
const options = ObjectAssign({}, optionsParam);
|
|
for (const opt of [
|
|
'year',
|
|
'month',
|
|
'day',
|
|
'hour',
|
|
'minute',
|
|
'second',
|
|
'weekday',
|
|
'dayPeriod',
|
|
'timeZoneName',
|
|
'dateStyle',
|
|
'timeStyle'
|
|
] as const) {
|
|
// TODO: can this be typed more cleanly?
|
|
type OptionMaybeFalse = typeof options[typeof opt] | false;
|
|
(options[opt] as OptionMaybeFalse) = opt in amended ? amended[opt] : options[opt];
|
|
if ((options[opt] as OptionMaybeFalse) === false || options[opt] === undefined) delete options[opt];
|
|
}
|
|
return options as globalThis.Intl.DateTimeFormatOptions;
|
|
}
|
|
|
|
type OptionsType<T extends TypesWithToLocaleString> = NonNullable<Parameters<T['toLocaleString']>[1]>;
|
|
|
|
function timeAmend(optionsParam: OptionsType<Temporal.PlainTime>) {
|
|
let options = amend(optionsParam, {
|
|
year: false,
|
|
month: false,
|
|
day: false,
|
|
weekday: false,
|
|
timeZoneName: false,
|
|
dateStyle: false
|
|
});
|
|
if (!hasTimeOptions(options)) {
|
|
options = ObjectAssign({}, options, {
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
second: 'numeric'
|
|
});
|
|
}
|
|
return options;
|
|
}
|
|
|
|
function yearMonthAmend(optionsParam: OptionsType<Temporal.PlainYearMonth>) {
|
|
let options = amend(optionsParam, {
|
|
day: false,
|
|
hour: false,
|
|
minute: false,
|
|
second: false,
|
|
weekday: false,
|
|
dayPeriod: false,
|
|
timeZoneName: false,
|
|
dateStyle: false,
|
|
timeStyle: false
|
|
});
|
|
if (!('year' in options || 'month' in options)) {
|
|
options = ObjectAssign(options, { year: 'numeric', month: 'numeric' });
|
|
}
|
|
return options;
|
|
}
|
|
|
|
function monthDayAmend(optionsParam: OptionsType<Temporal.PlainMonthDay>) {
|
|
let options = amend(optionsParam, {
|
|
year: false,
|
|
hour: false,
|
|
minute: false,
|
|
second: false,
|
|
weekday: false,
|
|
dayPeriod: false,
|
|
timeZoneName: false,
|
|
dateStyle: false,
|
|
timeStyle: false
|
|
});
|
|
if (!('month' in options || 'day' in options)) {
|
|
options = ObjectAssign({}, options, { month: 'numeric', day: 'numeric' });
|
|
}
|
|
return options;
|
|
}
|
|
|
|
function dateAmend(optionsParam: OptionsType<Temporal.PlainDate>) {
|
|
let options = amend(optionsParam, {
|
|
hour: false,
|
|
minute: false,
|
|
second: false,
|
|
dayPeriod: false,
|
|
timeZoneName: false,
|
|
timeStyle: false
|
|
});
|
|
if (!hasDateOptions(options)) {
|
|
options = ObjectAssign({}, options, {
|
|
year: 'numeric',
|
|
month: 'numeric',
|
|
day: 'numeric'
|
|
});
|
|
}
|
|
return options;
|
|
}
|
|
|
|
function datetimeAmend(optionsParam: OptionsType<Temporal.PlainDateTime>) {
|
|
let options = amend(optionsParam, { timeZoneName: false });
|
|
if (!hasTimeOptions(options) && !hasDateOptions(options)) {
|
|
options = ObjectAssign({}, options, {
|
|
year: 'numeric',
|
|
month: 'numeric',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
second: 'numeric'
|
|
});
|
|
}
|
|
return options;
|
|
}
|
|
|
|
function instantAmend(optionsParam: OptionsType<Temporal.Instant>) {
|
|
let options = optionsParam;
|
|
if (!hasTimeOptions(options) && !hasDateOptions(options)) {
|
|
options = ObjectAssign({}, options, {
|
|
year: 'numeric',
|
|
month: 'numeric',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
second: 'numeric'
|
|
});
|
|
}
|
|
return options;
|
|
}
|
|
|
|
function hasDateOptions(options: OptionsType<TypesWithToLocaleString>) {
|
|
return 'year' in options || 'month' in options || 'day' in options || 'weekday' in options || 'dateStyle' in options;
|
|
}
|
|
|
|
function hasTimeOptions(options: OptionsType<TypesWithToLocaleString>) {
|
|
return (
|
|
'hour' in options || 'minute' in options || 'second' in options || 'timeStyle' in options || 'dayPeriod' in options
|
|
);
|
|
}
|
|
|
|
function isTemporalObject(
|
|
obj: unknown
|
|
): obj is
|
|
| Temporal.PlainDate
|
|
| Temporal.PlainTime
|
|
| Temporal.PlainDateTime
|
|
| Temporal.ZonedDateTime
|
|
| Temporal.PlainYearMonth
|
|
| Temporal.PlainMonthDay
|
|
| Temporal.Instant {
|
|
return (
|
|
ES.IsTemporalDate(obj) ||
|
|
ES.IsTemporalTime(obj) ||
|
|
ES.IsTemporalDateTime(obj) ||
|
|
ES.IsTemporalZonedDateTime(obj) ||
|
|
ES.IsTemporalYearMonth(obj) ||
|
|
ES.IsTemporalMonthDay(obj) ||
|
|
ES.IsTemporalInstant(obj)
|
|
);
|
|
}
|
|
|
|
function sameTemporalType(x: unknown, y: unknown) {
|
|
if (!isTemporalObject(x) || !isTemporalObject(y)) return false;
|
|
if (ES.IsTemporalTime(x) && !ES.IsTemporalTime(y)) return false;
|
|
if (ES.IsTemporalDate(x) && !ES.IsTemporalDate(y)) return false;
|
|
if (ES.IsTemporalDateTime(x) && !ES.IsTemporalDateTime(y)) return false;
|
|
if (ES.IsTemporalZonedDateTime(x) && !ES.IsTemporalZonedDateTime(y)) return false;
|
|
if (ES.IsTemporalYearMonth(x) && !ES.IsTemporalYearMonth(y)) return false;
|
|
if (ES.IsTemporalMonthDay(x) && !ES.IsTemporalMonthDay(y)) return false;
|
|
if (ES.IsTemporalInstant(x) && !ES.IsTemporalInstant(y)) return false;
|
|
return true;
|
|
}
|
|
|
|
type TypesWithToLocaleString =
|
|
| Temporal.PlainDateTime
|
|
| Temporal.PlainDate
|
|
| Temporal.PlainTime
|
|
| Temporal.PlainYearMonth
|
|
| Temporal.PlainMonthDay
|
|
| Temporal.ZonedDateTime
|
|
| Temporal.Instant;
|
|
|
|
function extractOverrides(temporalObj: Params['format'][0], main: DateTimeFormatImpl) {
|
|
const DateTime = GetIntrinsic('%Temporal.PlainDateTime%');
|
|
|
|
if (ES.IsTemporalTime(temporalObj)) {
|
|
const hour = GetSlot(temporalObj, ISO_HOUR);
|
|
const minute = GetSlot(temporalObj, ISO_MINUTE);
|
|
const second = GetSlot(temporalObj, ISO_SECOND);
|
|
const millisecond = GetSlot(temporalObj, ISO_MILLISECOND);
|
|
const microsecond = GetSlot(temporalObj, ISO_MICROSECOND);
|
|
const nanosecond = GetSlot(temporalObj, ISO_NANOSECOND);
|
|
const datetime = new DateTime(1970, 1, 1, hour, minute, second, millisecond, microsecond, nanosecond, main[CAL_ID]);
|
|
return {
|
|
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
|
|
formatter: getPropLazy(main, TIME)
|
|
};
|
|
}
|
|
|
|
if (ES.IsTemporalYearMonth(temporalObj)) {
|
|
const isoYear = GetSlot(temporalObj, ISO_YEAR);
|
|
const isoMonth = GetSlot(temporalObj, ISO_MONTH);
|
|
const referenceISODay = GetSlot(temporalObj, ISO_DAY);
|
|
const calendar = ES.ToTemporalCalendarIdentifier(GetSlot(temporalObj, CALENDAR));
|
|
if (calendar !== main[CAL_ID]) {
|
|
throw new RangeError(
|
|
`cannot format PlainYearMonth with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`
|
|
);
|
|
}
|
|
const datetime = new DateTime(isoYear, isoMonth, referenceISODay, 12, 0, 0, 0, 0, 0, calendar);
|
|
return {
|
|
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
|
|
formatter: getPropLazy(main, YM)
|
|
};
|
|
}
|
|
|
|
if (ES.IsTemporalMonthDay(temporalObj)) {
|
|
const referenceISOYear = GetSlot(temporalObj, ISO_YEAR);
|
|
const isoMonth = GetSlot(temporalObj, ISO_MONTH);
|
|
const isoDay = GetSlot(temporalObj, ISO_DAY);
|
|
const calendar = ES.ToTemporalCalendarIdentifier(GetSlot(temporalObj, CALENDAR));
|
|
if (calendar !== main[CAL_ID]) {
|
|
throw new RangeError(
|
|
`cannot format PlainMonthDay with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`
|
|
);
|
|
}
|
|
const datetime = new DateTime(referenceISOYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0, calendar);
|
|
return {
|
|
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
|
|
formatter: getPropLazy(main, MD)
|
|
};
|
|
}
|
|
|
|
if (ES.IsTemporalDate(temporalObj)) {
|
|
const isoYear = GetSlot(temporalObj, ISO_YEAR);
|
|
const isoMonth = GetSlot(temporalObj, ISO_MONTH);
|
|
const isoDay = GetSlot(temporalObj, ISO_DAY);
|
|
const calendar = ES.ToTemporalCalendarIdentifier(GetSlot(temporalObj, CALENDAR));
|
|
if (calendar !== 'iso8601' && calendar !== main[CAL_ID]) {
|
|
throw new RangeError(`cannot format PlainDate with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`);
|
|
}
|
|
const datetime = new DateTime(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0, main[CAL_ID]);
|
|
return {
|
|
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
|
|
formatter: getPropLazy(main, DATE)
|
|
};
|
|
}
|
|
|
|
if (ES.IsTemporalDateTime(temporalObj)) {
|
|
const isoYear = GetSlot(temporalObj, ISO_YEAR);
|
|
const isoMonth = GetSlot(temporalObj, ISO_MONTH);
|
|
const isoDay = GetSlot(temporalObj, ISO_DAY);
|
|
const hour = GetSlot(temporalObj, ISO_HOUR);
|
|
const minute = GetSlot(temporalObj, ISO_MINUTE);
|
|
const second = GetSlot(temporalObj, ISO_SECOND);
|
|
const millisecond = GetSlot(temporalObj, ISO_MILLISECOND);
|
|
const microsecond = GetSlot(temporalObj, ISO_MICROSECOND);
|
|
const nanosecond = GetSlot(temporalObj, ISO_NANOSECOND);
|
|
const calendar = ES.ToTemporalCalendarIdentifier(GetSlot(temporalObj, CALENDAR));
|
|
if (calendar !== 'iso8601' && calendar !== main[CAL_ID]) {
|
|
throw new RangeError(
|
|
`cannot format PlainDateTime with calendar ${calendar} in locale with calendar ${main[CAL_ID]}`
|
|
);
|
|
}
|
|
let datetime = temporalObj;
|
|
if (calendar === 'iso8601') {
|
|
datetime = new DateTime(
|
|
isoYear,
|
|
isoMonth,
|
|
isoDay,
|
|
hour,
|
|
minute,
|
|
second,
|
|
millisecond,
|
|
microsecond,
|
|
nanosecond,
|
|
main[CAL_ID]
|
|
);
|
|
}
|
|
return {
|
|
instant: ES.GetInstantFor(main[TZ_RESOLVED], datetime, 'compatible'),
|
|
formatter: getPropLazy(main, DATETIME)
|
|
};
|
|
}
|
|
|
|
if (ES.IsTemporalZonedDateTime(temporalObj)) {
|
|
throw new TypeError(
|
|
'Temporal.ZonedDateTime not supported in DateTimeFormat methods. Use toLocaleString() instead.'
|
|
);
|
|
}
|
|
|
|
if (ES.IsTemporalInstant(temporalObj)) {
|
|
return {
|
|
instant: temporalObj,
|
|
formatter: getPropLazy(main, INST)
|
|
};
|
|
}
|
|
|
|
return {};
|
|
}
|