UNPKG

@js-temporal/polyfill

Version:

Polyfill for Temporal (https://github.com/tc39/proposal-temporal), an ECMA TC39 Stage 3 proposal

275 lines (261 loc) 12.1 kB
import * as ES from './ecmascript'; import { MakeIntrinsicClass } from './intrinsicclass'; import { CALENDAR, GetSlot, ISO_DATE_TIME } from './slots'; import type { Temporal } from '..'; import { DateTimeFormat } from './intl'; import type { CalendarDateRecord, PlainDateTimeParams as Params, PlainDateTimeReturn as Return } from './internaltypes'; export class PlainDateTime implements Temporal.PlainDateTime { constructor( isoYear: Params['constructor'][0], isoMonth: Params['constructor'][1], isoDay: Params['constructor'][2], hourParam: Params['constructor'][3] = 0, minuteParam: Params['constructor'][4] = 0, secondParam: Params['constructor'][5] = 0, millisecondParam: Params['constructor'][6] = 0, microsecondParam: Params['constructor'][7] = 0, nanosecondParam: Params['constructor'][8] = 0, calendarParam: Params['constructor'][9] = 'iso8601' ) { const year = ES.ToIntegerWithTruncation(isoYear); const month = ES.ToIntegerWithTruncation(isoMonth); const day = ES.ToIntegerWithTruncation(isoDay); const hour = hourParam === undefined ? 0 : ES.ToIntegerWithTruncation(hourParam); const minute = minuteParam === undefined ? 0 : ES.ToIntegerWithTruncation(minuteParam); const second = secondParam === undefined ? 0 : ES.ToIntegerWithTruncation(secondParam); const millisecond = millisecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(millisecondParam); const microsecond = microsecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(microsecondParam); const nanosecond = nanosecondParam === undefined ? 0 : ES.ToIntegerWithTruncation(nanosecondParam); const calendar = ES.CanonicalizeCalendar(calendarParam === undefined ? 'iso8601' : ES.RequireString(calendarParam)); ES.RejectDateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond); ES.CreateTemporalDateTimeSlots( this, { isoDate: { year, month, day }, time: { hour, minute, second, millisecond, microsecond, nanosecond } }, calendar ); } get calendarId(): Return['calendarId'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); return GetSlot(this, CALENDAR); } get year(): Return['year'] { return getCalendarProperty(this, 'year'); } get month(): Return['month'] { return getCalendarProperty(this, 'month'); } get monthCode(): Return['monthCode'] { return getCalendarProperty(this, 'monthCode'); } get day(): Return['day'] { return getCalendarProperty(this, 'day'); } get hour(): Return['hour'] { return getTimeProperty(this, 'hour'); } get minute(): Return['minute'] { return getTimeProperty(this, 'minute'); } get second(): Return['second'] { return getTimeProperty(this, 'second'); } get millisecond(): Return['millisecond'] { return getTimeProperty(this, 'millisecond'); } get microsecond(): Return['microsecond'] { return getTimeProperty(this, 'microsecond'); } get nanosecond(): Return['nanosecond'] { return getTimeProperty(this, 'nanosecond'); } get era(): Return['era'] { return getCalendarProperty(this, 'era'); } get eraYear(): Return['eraYear'] { return getCalendarProperty(this, 'eraYear'); } get dayOfWeek(): Return['dayOfWeek'] { return getCalendarProperty(this, 'dayOfWeek'); } get dayOfYear(): Return['dayOfYear'] { return getCalendarProperty(this, 'dayOfYear'); } get weekOfYear(): Return['weekOfYear'] { return getCalendarProperty(this, 'weekOfYear')?.week; } get yearOfWeek(): Return['yearOfWeek'] { return getCalendarProperty(this, 'weekOfYear')?.year; } get daysInWeek(): Return['daysInWeek'] { return getCalendarProperty(this, 'daysInWeek'); } get daysInYear(): Return['daysInYear'] { return getCalendarProperty(this, 'daysInYear'); } get daysInMonth(): Return['daysInMonth'] { return getCalendarProperty(this, 'daysInMonth'); } get monthsInYear(): Return['monthsInYear'] { return getCalendarProperty(this, 'monthsInYear'); } get inLeapYear(): Return['inLeapYear'] { return getCalendarProperty(this, 'inLeapYear'); } with(temporalDateTimeLike: Params['with'][0], options: Params['with'][1] = undefined): Return['with'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); if (!ES.IsObject(temporalDateTimeLike)) { throw new TypeError('invalid argument'); } ES.RejectTemporalLikeObject(temporalDateTimeLike); const calendar = GetSlot(this, CALENDAR); const isoDateTime = GetSlot(this, ISO_DATE_TIME); let fields = { ...ES.ISODateToFields(calendar, isoDateTime.isoDate), ...isoDateTime.time }; const partialDateTime = ES.PrepareCalendarFields( calendar, temporalDateTimeLike, ['year', 'month', 'monthCode', 'day'], ['hour', 'minute', 'second', 'millisecond', 'microsecond', 'nanosecond'], 'partial' ); fields = ES.CalendarMergeFields(calendar, fields, partialDateTime); const overflow = ES.GetTemporalOverflowOption(ES.GetOptionsObject(options)); const newDateTime = ES.InterpretTemporalDateTimeFields(calendar, fields, overflow); return ES.CreateTemporalDateTime(newDateTime, calendar); } withPlainTime(temporalTime: Params['withPlainTime'][0] = undefined): Return['withPlainTime'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); const time = ES.ToTimeRecordOrMidnight(temporalTime); const isoDateTime = ES.CombineISODateAndTimeRecord(GetSlot(this, ISO_DATE_TIME).isoDate, time); return ES.CreateTemporalDateTime(isoDateTime, GetSlot(this, CALENDAR)); } withCalendar(calendarParam: Params['withCalendar'][0]): Return['withCalendar'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); const calendar = ES.ToTemporalCalendarIdentifier(calendarParam); return ES.CreateTemporalDateTime(GetSlot(this, ISO_DATE_TIME), calendar); } add(temporalDurationLike: Params['add'][0], options: Params['add'][1] = undefined): Return['add'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); return ES.AddDurationToDateTime('add', this, temporalDurationLike, options); } subtract( temporalDurationLike: Params['subtract'][0], options: Params['subtract'][1] = undefined ): Return['subtract'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); return ES.AddDurationToDateTime('subtract', this, temporalDurationLike, options); } until(other: Params['until'][0], options: Params['until'][1] = undefined): Return['until'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); return ES.DifferenceTemporalPlainDateTime('until', this, other, options); } since(other: Params['since'][0], options: Params['since'][1] = undefined): Return['since'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); return ES.DifferenceTemporalPlainDateTime('since', this, other, options); } round(roundToParam: Params['round'][0]): Return['round'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); if (roundToParam === undefined) throw new TypeError('options parameter is required'); const roundTo = typeof roundToParam === 'string' ? (ES.CreateOnePropObject('smallestUnit', roundToParam) as Exclude<typeof roundToParam, string>) : ES.GetOptionsObject(roundToParam); const roundingIncrement = ES.GetTemporalRoundingIncrementOption(roundTo); const roundingMode = ES.GetRoundingModeOption(roundTo, 'halfExpand'); const smallestUnit = ES.GetTemporalUnitValuedOption(roundTo, 'smallestUnit', 'time', ES.REQUIRED, ['day']); const maximumIncrements = { day: 1, hour: 24, minute: 60, second: 60, millisecond: 1000, microsecond: 1000, nanosecond: 1000 }; const maximum = maximumIncrements[smallestUnit]; const inclusive = maximum === 1; ES.ValidateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive); const isoDateTime = GetSlot(this, ISO_DATE_TIME); if (roundingIncrement === 1 && smallestUnit === 'nanosecond') { return ES.CreateTemporalDateTime(isoDateTime, GetSlot(this, CALENDAR)); } const result = ES.RoundISODateTime(isoDateTime, roundingIncrement, smallestUnit, roundingMode); return ES.CreateTemporalDateTime(result, GetSlot(this, CALENDAR)); } equals(otherParam: Params['equals'][0]): Return['equals'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); const other = ES.ToTemporalDateTime(otherParam); if (ES.CompareISODateTime(GetSlot(this, ISO_DATE_TIME), GetSlot(other, ISO_DATE_TIME)) !== 0) return false; return ES.CalendarEquals(GetSlot(this, CALENDAR), GetSlot(other, CALENDAR)); } toString(options: Params['toString'][0] = undefined): string { ES.CheckReceiver(this, ES.IsTemporalDateTime); const resolvedOptions = ES.GetOptionsObject(options); const showCalendar = ES.GetTemporalShowCalendarNameOption(resolvedOptions); const digits = ES.GetTemporalFractionalSecondDigitsOption(resolvedOptions); const roundingMode = ES.GetRoundingModeOption(resolvedOptions, 'trunc'); const smallestUnit = ES.GetTemporalUnitValuedOption(resolvedOptions, 'smallestUnit', 'time', undefined); if (smallestUnit === 'hour') throw new RangeError('smallestUnit must be a time unit other than "hour"'); const { precision, unit, increment } = ES.ToSecondsStringPrecisionRecord(smallestUnit, digits); const result = ES.RoundISODateTime(GetSlot(this, ISO_DATE_TIME), increment, unit, roundingMode); ES.RejectDateTimeRange(result); return ES.ISODateTimeToString(result, GetSlot(this, CALENDAR), precision, showCalendar); } toJSON(): Return['toJSON'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); return ES.ISODateTimeToString(GetSlot(this, ISO_DATE_TIME), GetSlot(this, CALENDAR), 'auto'); } toLocaleString( locales: Params['toLocaleString'][0] = undefined, options: Params['toLocaleString'][1] = undefined ): string { ES.CheckReceiver(this, ES.IsTemporalDateTime); return new DateTimeFormat(locales, options).format(this); } valueOf(): never { ES.ValueOfThrows('PlainDateTime'); } toZonedDateTime( temporalTimeZoneLike: Params['toZonedDateTime'][0], options: Params['toZonedDateTime'][1] = undefined ): Return['toZonedDateTime'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); const timeZone = ES.ToTemporalTimeZoneIdentifier(temporalTimeZoneLike); const resolvedOptions = ES.GetOptionsObject(options); const disambiguation = ES.GetTemporalDisambiguationOption(resolvedOptions); const epochNs = ES.GetEpochNanosecondsFor(timeZone, GetSlot(this, ISO_DATE_TIME), disambiguation); return ES.CreateTemporalZonedDateTime(epochNs, timeZone, GetSlot(this, CALENDAR)); } toPlainDate(): Return['toPlainDate'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); return ES.CreateTemporalDate(GetSlot(this, ISO_DATE_TIME).isoDate, GetSlot(this, CALENDAR)); } toPlainTime(): Return['toPlainTime'] { ES.CheckReceiver(this, ES.IsTemporalDateTime); return ES.CreateTemporalTime(GetSlot(this, ISO_DATE_TIME).time); } static from(item: Params['from'][0], options: Params['from'][1] = undefined): Return['from'] { return ES.ToTemporalDateTime(item, options); } static compare(oneParam: Params['compare'][0], twoParam: Params['compare'][1]): Return['compare'] { const one = ES.ToTemporalDateTime(oneParam); const two = ES.ToTemporalDateTime(twoParam); return ES.CompareISODateTime(GetSlot(one, ISO_DATE_TIME), GetSlot(two, ISO_DATE_TIME)); } [Symbol.toStringTag]!: 'Temporal.PlainDateTime'; } MakeIntrinsicClass(PlainDateTime, 'Temporal.PlainDateTime'); function getCalendarProperty<P extends keyof CalendarDateRecord>( dt: Temporal.PlainDateTime, prop: P ): CalendarDateRecord[P] { ES.CheckReceiver(dt, ES.IsTemporalDateTime); const isoDate = GetSlot(dt, ISO_DATE_TIME).isoDate; return ES.calendarImplForObj(dt).isoToDate(isoDate, { [prop]: true })[prop]; } function getTimeProperty(dt: Temporal.PlainDateTime, prop: Temporal.TimeUnit) { ES.CheckReceiver(dt, ES.IsTemporalDateTime); return GetSlot(dt, ISO_DATE_TIME).time[prop]; }