Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 122 additions & 58 deletions polyfill/lib/calendar.mjs

Large diffs are not rendered by default.

69 changes: 36 additions & 33 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ export function ParseTemporalTimeString(isoString) {
// Reject strings that are ambiguous with PlainMonthDay or PlainYearMonth.
try {
const { month, day } = ParseTemporalMonthDayString(isoString);
RejectISODate(1972, month, day);
RejectISODate(1972, month, day, 'reject', 'reject');
} catch {
try {
const { year, month } = ParseTemporalYearMonthString(isoString);
Expand Down Expand Up @@ -691,16 +691,9 @@ function ParseTemporalDurationString(isoString) {
);
}

export function RegulateISODate(year, month, day, overflow) {
switch (overflow) {
case 'reject':
RejectISODate(year, month, day);
break;
case 'constrain':
({ year, month, day } = ConstrainISODate(year, month, day));
break;
}
return { year, month, day };
export function RegulateISODate(year, month, day, overflowMonths, overflowDays) {
RejectISODate(year, month, day, overflowMonths, overflowDays);
return ConstrainISODate(year, month, day);
}

export function RegulateTime(hour, minute, second, millisecond, microsecond, nanosecond, overflow) {
Expand Down Expand Up @@ -1709,8 +1702,8 @@ export function CalendarMergeFields(calendar, fields, additionalFields) {
return merged;
}

export function CalendarDateAdd(calendar, isoDate, dateDuration, overflow) {
const result = calendarImplForID(calendar).dateAdd(isoDate, dateDuration, overflow);
export function CalendarDateAdd(calendar, isoDate, dateDuration, overflowMonths, overflowDays) {
const result = calendarImplForID(calendar).dateAdd(isoDate, dateDuration, overflowMonths, overflowDays);
RejectDateRange(result);
return result;
}
Expand Down Expand Up @@ -1767,19 +1760,19 @@ export function CalendarDateFromFields(calendar, fields, overflow) {
return result;
}

export function CalendarYearMonthFromFields(calendar, fields, overflow) {
export function CalendarYearMonthFromFields(calendar, fields, overflowMonths) {
const calendarImpl = calendarImplForID(calendar);
calendarImpl.resolveFields(fields, 'year-month');
fields.day = 1;
const result = calendarImpl.dateToISO(fields, overflow);
const result = calendarImpl.dateToISO(fields, overflowMonths);
RejectYearMonthRange(result);
return result;
}

export function CalendarMonthDayFromFields(calendar, fields, overflow) {
const calendarImpl = calendarImplForID(calendar);
calendarImpl.resolveFields(fields, 'month-day');
const result = calendarImpl.monthDayToISOReferenceDate(fields, overflow);
const result = calendarImpl.monthDayToISOReferenceDate(fields, overflow, overflow);
RejectDateRange(result);
return result;
}
Expand Down Expand Up @@ -2747,7 +2740,13 @@ export function DateDurationDays(dateDuration, plainRelativeTo) {

// balance years, months, and weeks down to days
const isoDate = GetSlot(plainRelativeTo, ISO_DATE);
const later = CalendarDateAdd(GetSlot(plainRelativeTo, CALENDAR), isoDate, yearsMonthsWeeksDuration, 'constrain');
const later = CalendarDateAdd(
GetSlot(plainRelativeTo, CALENDAR),
isoDate,
yearsMonthsWeeksDuration,
'constrain',
'constrain'
);
const epochDaysEarlier = ISODateToEpochDays(isoDate.year, isoDate.month - 1, isoDate.day);
const epochDaysLater = ISODateToEpochDays(later.year, later.month - 1, later.day);
const yearsMonthsWeeksInDays = epochDaysLater - epochDaysEarlier;
Expand Down Expand Up @@ -2784,9 +2783,13 @@ export function RejectToRange(value, min, max) {
if (value < min || value > max) throw new RangeErrorCtor(`value out of range: ${min} <= ${value} <= ${max}`);
}

export function RejectISODate(year, month, day) {
RejectToRange(month, 1, 12);
RejectToRange(day, 1, ISODaysInMonth(year, month));
export function RejectISODate(year, month, day, overflowMonths, overflowDays) {
if (overflowMonths === 'reject') {
RejectToRange(month, 1, 12);
}
if (overflowDays === 'reject') {
RejectToRange(day, 1, ISODaysInMonth(year, month));
}
Comment on lines -2787 to +2792
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, RejectISODate can just stay as is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't work with the implementation of RejectISODate being as it is, because there's no way for it to distinguish between the case where it should (effectively) constrain the day despite overflow being reject, and the case where it should reject the day, without taking an overflow argument.

}

function RejectDateRange(isoDate) {
Expand All @@ -2809,7 +2812,7 @@ export function RejectTime(hour, minute, second, millisecond, microsecond, nanos
}

export function RejectDateTime(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond) {
RejectISODate(year, month, day);
RejectISODate(year, month, day, 'reject', 'reject');
RejectTime(hour, minute, second, millisecond, microsecond, nanosecond);
}

Expand Down Expand Up @@ -3203,7 +3206,7 @@ function ComputeNudgeWindow(
}
case 'week': {
const yearsMonths = AdjustDateDurationRecord(duration.date, 0, 0);
const weeksStart = CalendarDateAdd(calendar, isoDateTime.isoDate, yearsMonths, 'constrain');
const weeksStart = CalendarDateAdd(calendar, isoDateTime.isoDate, yearsMonths, 'constrain', 'constrain');
const weeksEnd = BalanceISODate(weeksStart.year, weeksStart.month, weeksStart.day + duration.date.days);
const untilResult = CalendarDateUntil(calendar, weeksStart, weeksEnd, 'week');
const weeks = RoundNumberToIncrement(duration.date.weeks + untilResult.weeks, increment, 'trunc');
Expand Down Expand Up @@ -3237,15 +3240,15 @@ function ComputeNudgeWindow(
// which loses precision and creates a distorted bounding window.
startEpochNs = originEpochNs;
} else {
const start = CalendarDateAdd(calendar, isoDateTime.isoDate, startDuration, 'constrain');
const start = CalendarDateAdd(calendar, isoDateTime.isoDate, startDuration, 'constrain', 'constrain');
const startDateTime = CombineISODateAndTimeRecord(start, isoDateTime.time);
startEpochNs = timeZone
? GetEpochNanosecondsFor(timeZone, startDateTime, 'compatible')
: GetUTCEpochNanoseconds(startDateTime);
}

// Convert to bound-END to epoch-nanoseconds
const end = CalendarDateAdd(calendar, isoDateTime.isoDate, endDuration, 'constrain');
const end = CalendarDateAdd(calendar, isoDateTime.isoDate, endDuration, 'constrain', 'constrain');
const endDateTime = CombineISODateAndTimeRecord(end, isoDateTime.time);
const endEpochNs = timeZone
? GetEpochNanosecondsFor(timeZone, endDateTime, 'compatible')
Expand Down Expand Up @@ -3366,7 +3369,7 @@ function NudgeToZonedTime(sign, duration, isoDateTime, timeZone, calendar, incre
// unit must be hour or smaller

// Apply to origin, output start/end of the day as PlainDateTimes
const start = CalendarDateAdd(calendar, isoDateTime.isoDate, duration.date, 'constrain');
const start = CalendarDateAdd(calendar, isoDateTime.isoDate, duration.date, 'constrain', 'constrain');
const startDateTime = CombineISODateAndTimeRecord(start, isoDateTime.time);
const endDate = BalanceISODate(start.year, start.month, start.day + sign);
const endDateTime = CombineISODateAndTimeRecord(endDate, isoDateTime.time);
Expand Down Expand Up @@ -3500,7 +3503,7 @@ function BubbleRelativeDuration(
}

// Compute end-of-unit in epoch-nanoseconds
const end = CalendarDateAdd(calendar, isoDateTime.isoDate, endDuration, 'constrain');
const end = CalendarDateAdd(calendar, isoDateTime.isoDate, endDuration, 'constrain', 'constrain');
const endDateTime = CombineISODateAndTimeRecord(end, isoDateTime.time);
let endEpochNs;
if (timeZone) {
Expand Down Expand Up @@ -4032,7 +4035,7 @@ export function AddZonedDateTime(epochNs, timeZone, calendar, duration, overflow
// RFC 5545 requires the date portion to be added in calendar days and the
// time portion to be added in exact time.
const dt = GetISODateTimeFor(timeZone, epochNs);
const addedDate = CalendarDateAdd(calendar, dt.isoDate, duration.date, overflow);
const addedDate = CalendarDateAdd(calendar, dt.isoDate, duration.date, overflow, overflow);
const dtIntermediate = CombineISODateAndTimeRecord(addedDate, dt.time);

// Note that 'compatible' is used below because this disambiguation behavior
Expand Down Expand Up @@ -4085,7 +4088,7 @@ export function AddDurationToDate(operation, plainDate, durationLike, options) {
const resolvedOptions = GetOptionsObject(options);
const overflow = GetTemporalOverflowOption(resolvedOptions);

const addedDate = CalendarDateAdd(calendar, GetSlot(plainDate, ISO_DATE), dateDuration, overflow);
const addedDate = CalendarDateAdd(calendar, GetSlot(plainDate, ISO_DATE), dateDuration, overflow, overflow);
return CreateTemporalDate(addedDate, calendar);
}

Expand All @@ -4106,7 +4109,7 @@ export function AddDurationToDateTime(operation, dateTime, durationLike, options

// Delegate the date part addition to the calendar
RejectDuration(dateDuration.years, dateDuration.months, dateDuration.weeks, dateDuration.days, 0, 0, 0, 0, 0, 0);
const addedDate = CalendarDateAdd(calendar, isoDateTime.isoDate, dateDuration, overflow);
const addedDate = CalendarDateAdd(calendar, isoDateTime.isoDate, dateDuration, overflow, overflow);

const result = CombineISODateAndTimeRecord(addedDate, timeResult);
return CreateTemporalDateTime(result, calendar);
Expand All @@ -4128,23 +4131,23 @@ export function AddDurationToYearMonth(operation, yearMonth, durationLike, optio
let duration = ToTemporalDuration(durationLike);
if (operation === 'subtract') duration = CreateNegatedTemporalDuration(duration);
const resolvedOptions = GetOptionsObject(options);
const overflow = GetTemporalOverflowOption(resolvedOptions);
const overflowMonths = GetTemporalOverflowOption(resolvedOptions);
const sign = DurationSign(duration);

const calendar = GetSlot(yearMonth, CALENDAR);
const fields = ISODateToFields(calendar, GetSlot(yearMonth, ISO_DATE), 'year-month');
fields.day = 1;
let startDate = CalendarDateFromFields(calendar, fields, 'constrain');
if (sign < 0) {
const nextMonth = CalendarDateAdd(calendar, startDate, { months: 1 }, 'constrain');
const nextMonth = CalendarDateAdd(calendar, startDate, { months: 1 }, 'constrain', 'constrain');
startDate = BalanceISODate(nextMonth.year, nextMonth.month, nextMonth.day - 1);
}
const durationToAdd = ToDateDurationRecordWithoutTime(duration);
RejectDateRange(startDate);
const addedDate = CalendarDateAdd(calendar, startDate, durationToAdd, overflow);
const addedDate = CalendarDateAdd(calendar, startDate, durationToAdd, overflowMonths, 'constrain');
const addedDateFields = ISODateToFields(calendar, addedDate, 'year-month');

const isoDate = CalendarYearMonthFromFields(calendar, addedDateFields, overflow);
const isoDate = CalendarYearMonthFromFields(calendar, addedDateFields, overflowMonths, 'constrain');
return CreateTemporalYearMonth(isoDate, calendar);
}

Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/plaindate.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class PlainDate {
const day = ES.ToIntegerWithTruncation(isoDay);
calendar = calendar === undefined ? 'iso8601' : ES.RequireString(calendar);
calendar = ES.CanonicalizeCalendar(calendar);
ES.RejectISODate(year, month, day);
ES.RejectISODate(year, month, day, 'reject', 'reject');

ES.CreateTemporalDateSlots(this, { year, month, day }, calendar);
}
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/plainmonthday.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class PlainMonthDay {
calendar = ES.CanonicalizeCalendar(calendar);
const year = ES.ToIntegerWithTruncation(referenceISOYear);

ES.RejectISODate(year, month, day);
ES.RejectISODate(year, month, day, 'reject', 'reject');
ES.CreateTemporalMonthDaySlots(this, { year, month, day }, calendar);
}

Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/plainyearmonth.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class PlainYearMonth {
calendar = ES.CanonicalizeCalendar(calendar);
const day = ES.ToIntegerWithTruncation(referenceISODay);

ES.RejectISODate(year, month, day);
ES.RejectISODate(year, month, day, 'reject', 'reject');
ES.CreateTemporalYearMonthSlots(this, { year, month, day }, calendar);
}
get year() {
Expand Down
Loading