diff --git a/polyfill/lib/calendar.mjs b/polyfill/lib/calendar.mjs index cef161dfb7..d9f6555325 100644 --- a/polyfill/lib/calendar.mjs +++ b/polyfill/lib/calendar.mjs @@ -199,6 +199,15 @@ impl['iso8601'] = { if (fields.month !== undefined && fields.year === undefined && fields.monthCode === undefined) { throw new TypeError('either year or monthCode required with month'); } + // If the user omits the calendar from `from`, then it's clearly not + // intended to be cross-calendar code because the user is unambiguously + // asking for the ISO calendar. Therefore there's no requirement for + // `monthCode` to be present. ES.UndefinedMonthCode is a symbol that is only + // passed in the "omits the calendar and omits monthCode" case. This is + // needed to differentiate from the case where the user specified the ISO + // calendar explicitly. In that case, `monthCode` is required and + // `undefined` will throw above. + if (fields.monthCode === ES.UndefinedMonthCode) fields.monthCode = undefined; fields = resolveNonLunisolarMonth(fields); let { month, day } = fields; ({ month, day } = ES.RegulateMonthDay(month, day, overflow)); diff --git a/polyfill/lib/ecmascript.mjs b/polyfill/lib/ecmascript.mjs index 4fe698cc52..a66ad8a60f 100644 --- a/polyfill/lib/ecmascript.mjs +++ b/polyfill/lib/ecmascript.mjs @@ -999,11 +999,11 @@ export const ES = ObjectAssign({}, ES2020, { for (const fieldRecord of fields) { const [property, defaultValue] = fieldRecord; let value = bag[property]; - if (value === undefined) { + if (value === undefined || value === ES.UndefinedMonthCode) { if (fieldRecord.length === 1) { throw new TypeError(`required property '${property}' missing or undefined`); } - value = defaultValue; + if (value === undefined) value = defaultValue; } else { any = true; if (BUILTIN_CASTS.has(property)) { @@ -1270,6 +1270,7 @@ export const ES = ObjectAssign({}, ES2020, { if (!ES.IsTemporalInstant(result)) throw new TypeError('invalid result'); return result; }, + UndefinedMonthCode: Symbol('undefined-month-code'), ToTemporalMonthDay: (item, constructor, options = {}) => { if (ES.Type(item) === 'Object') { if (ES.IsTemporalMonthDay(item)) return item; @@ -1280,7 +1281,7 @@ export const ES = ObjectAssign({}, ES2020, { const fieldNames = ES.CalendarFields(calendar, ['day', 'month', 'monthCode', 'year']); const fields = ES.ToTemporalMonthDayFields(item, fieldNames); if (calendarAbsent && fields.month !== undefined && fields.monthCode === undefined) { - fields.monthCode = `M${ES.ToString(fields.month)}`; + fields.monthCode = ES.UndefinedMonthCode; } return ES.MonthDayFromFields(calendar, fields, constructor, options); } diff --git a/polyfill/test/intl.mjs b/polyfill/test/intl.mjs index 467e6db8c4..b4040b26ad 100644 --- a/polyfill/test/intl.mjs +++ b/polyfill/test/intl.mjs @@ -882,6 +882,9 @@ describe('Intl', () => { if (test.monthCode === undefined) test.monthCode = `M${test.month}`; const { calendar, monthCode, month, day, year, isoReferenceYear } = test; const md = Temporal.PlainMonthDay.from({ year, month, day, calendar }); + const isoString = md.toString(); + const mdFromIso = Temporal.PlainMonthDay.from(isoString); + equal(mdFromIso, md); const isoFields = md.getISOFields(); equal(md.monthCode, monthCode); equal(md.day, day);