mirror of
https://github.com/Samsung/escargot.git
synced 2026-06-22 10:01:50 +00:00
Fix minor Temporal issues
Signed-off-by: Seonghyun Kim <sh8281.kim@samsung.com>
This commit is contained in:
parent
7bb1e520a5
commit
8f24498310
7 changed files with 329 additions and 307 deletions
|
|
@ -67,6 +67,229 @@ namespace Escargot {
|
|||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "failed to get value from ICU calendar"); \
|
||||
}
|
||||
|
||||
static void setICUYear(ExecutionState& state, Calendar calendar, const CalendarFieldsRecord& fields, UCalendar* icuCalendar)
|
||||
{
|
||||
if (calendar.isEraRelated() && (fields.era && fields.eraYear)) {
|
||||
calendar.setYear(state, icuCalendar, fields.era.value(), fields.eraYear.value());
|
||||
} else if (fields.year) {
|
||||
calendar.setYear(state, icuCalendar, fields.year.value());
|
||||
}
|
||||
}
|
||||
|
||||
static void setICUMonth(ExecutionState& state, Calendar calendar, const CalendarFieldsRecord& fields, UCalendar* icuCalendar)
|
||||
{
|
||||
if (fields.month) {
|
||||
calendar.setOrdinalMonth(state, icuCalendar, fields.month.value());
|
||||
}
|
||||
if (fields.monthCode) {
|
||||
calendar.setMonth(icuCalendar, fields.monthCode.value());
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t monthsPerYear(Calendar calendar)
|
||||
{
|
||||
if (calendar.hasEpagomenalMonths() || calendar.hasLeapMonths()) {
|
||||
return 13;
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
|
||||
static uint8_t monthCodePerYear(Calendar calendar)
|
||||
{
|
||||
if (calendar.hasEpagomenalMonths()) {
|
||||
return 13;
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-intl-era-monthcode/#table-additional-month-codes
|
||||
static uint8_t daysInMonth(ExecutionState& state, Calendar calendar, UCalendar* icuCalendar, const CalendarFieldsRecord& fields)
|
||||
{
|
||||
switch (calendar.id()) {
|
||||
case Calendar::ID::ISO8601:
|
||||
case Calendar::ID::Buddhist:
|
||||
case Calendar::ID::Gregorian:
|
||||
case Calendar::ID::Japanese:
|
||||
case Calendar::ID::ROC:
|
||||
if (fields.year) {
|
||||
return ISO8601::daysInMonth(fields.year.value() + calendar.epochISOYear(), fields.month ? fields.month.value() : fields.monthCode.value().monthNumber);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
setICUYear(state, calendar, fields, icuCalendar);
|
||||
setICUMonth(state, calendar, fields, icuCalendar);
|
||||
return TemporalPlainDateGetter::daysInMonth(state, ISO8601::PlainDate(), calendar, icuCalendar).asInt32();
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> isoDaysInMonth(uint8_t ordinal)
|
||||
{
|
||||
if (ordinal == 2) {
|
||||
return { 28, 29 };
|
||||
}
|
||||
if (ordinal == 4 || ordinal == 6 || ordinal == 9 || ordinal == 11) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
return { 31, 31 };
|
||||
}
|
||||
|
||||
static std::pair<uint8_t, uint8_t> daysInMonth(Calendar calendar, MonthCode mc, uint8_t ordinal)
|
||||
{
|
||||
switch (calendar.id()) {
|
||||
case Calendar::ID::ISO8601:
|
||||
case Calendar::ID::Buddhist:
|
||||
case Calendar::ID::Gregorian:
|
||||
case Calendar::ID::Japanese:
|
||||
case Calendar::ID::ROC:
|
||||
return isoDaysInMonth(ordinal);
|
||||
|
||||
case Calendar::ID::Chinese:
|
||||
case Calendar::ID::Dangi:
|
||||
return { 29, 30 };
|
||||
|
||||
case Calendar::ID::Coptic:
|
||||
case Calendar::ID::Ethiopian:
|
||||
case Calendar::ID::EthiopianAmeteAlem: {
|
||||
if (ordinal <= 12) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
return { 5, 6 };
|
||||
}
|
||||
|
||||
case Calendar::ID::Hebrew: {
|
||||
if (ordinal == 2 || ordinal == 3) {
|
||||
return { 29, 30 };
|
||||
}
|
||||
if ((ordinal & 1) == 1 || mc.isLeapMonth) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
return { 29, 29 };
|
||||
}
|
||||
|
||||
case Calendar::ID::Indian: {
|
||||
if (ordinal == 1) {
|
||||
return { 30, 31 };
|
||||
}
|
||||
if (ordinal <= 6) {
|
||||
return { 31, 31 };
|
||||
}
|
||||
return { 30, 30 };
|
||||
}
|
||||
|
||||
case Calendar::ID::IslamicUmmAlQura:
|
||||
return { 29, 30 };
|
||||
|
||||
case Calendar::ID::IslamicCivil:
|
||||
case Calendar::ID::IslamicCivilLegacy:
|
||||
case Calendar::ID::IslamicTabular: {
|
||||
if ((ordinal & 1) == 1) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
if (ordinal < 12) {
|
||||
return { 29, 29 };
|
||||
}
|
||||
return { 29, 30 };
|
||||
}
|
||||
|
||||
case Calendar::ID::Persian: {
|
||||
if (ordinal <= 6) {
|
||||
return { 31, 31 };
|
||||
}
|
||||
if (ordinal <= 11) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
return { 29, 30 };
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
return { 29, 31 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Optional<MonthCode> setICUMonthDay(ExecutionState& state, Calendar calendar, const CalendarFieldsRecord& fields, UCalendar* icuCalendar, TemporalOverflowOption overflow)
|
||||
{
|
||||
if (overflow == TemporalOverflowOption::Constrain) {
|
||||
auto day = fields.day.value();
|
||||
while (day) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, 1);
|
||||
setICUYear(state, calendar, fields, icuCalendar);
|
||||
setICUMonth(state, calendar, fields, icuCalendar);
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, day);
|
||||
if (fields.month) {
|
||||
unsigned test = calendar.ordinalMonth(state, icuCalendar);
|
||||
CHECK_ICU_CALENDAR();
|
||||
if (test != fields.month.value()) {
|
||||
day--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (fields.monthCode) {
|
||||
auto mc = calendar.monthCode(state, icuCalendar);
|
||||
if (fields.monthCode.value() != mc) {
|
||||
day--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return NullOption;
|
||||
}
|
||||
|
||||
// convert to non-leap month
|
||||
if (calendar.hasLeapMonths() && fields.monthCode && fields.monthCode.value().isLeapMonth) {
|
||||
// with hebrew, only M05L is valid
|
||||
Optional<MonthCode> newConstrainedMonth;
|
||||
if ((calendar.id() == Calendar::ID::Hebrew && fields.monthCode.value().monthNumber == 5)) {
|
||||
newConstrainedMonth = MonthCode();
|
||||
newConstrainedMonth.value().monthNumber = 6;
|
||||
} else if (calendar.id() == Calendar::ID::Chinese || calendar.id() == Calendar::ID::Dangi) {
|
||||
// use non-leap months for other
|
||||
newConstrainedMonth = MonthCode();
|
||||
newConstrainedMonth.value().monthNumber = fields.monthCode.value().monthNumber;
|
||||
}
|
||||
if (newConstrainedMonth) {
|
||||
day = fields.day.value();
|
||||
while (day) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, 1);
|
||||
setICUYear(state, calendar, fields, icuCalendar);
|
||||
calendar.setMonth(icuCalendar, newConstrainedMonth.value());
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, day);
|
||||
if (fields.month) {
|
||||
unsigned test = calendar.ordinalMonth(state, icuCalendar);
|
||||
CHECK_ICU_CALENDAR();
|
||||
if (test != fields.month.value()) {
|
||||
day--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto mc = calendar.monthCode(state, icuCalendar);
|
||||
if (newConstrainedMonth.value() != mc) {
|
||||
day--;
|
||||
continue;
|
||||
}
|
||||
|
||||
return newConstrainedMonth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (day == 0) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid monthCode or month");
|
||||
}
|
||||
} else {
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, 1);
|
||||
setICUMonth(state, calendar, fields, icuCalendar);
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, fields.day.value());
|
||||
}
|
||||
return NullOption;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-intl-era-monthcode/#table-eras
|
||||
/*
|
||||
"buddhist" "be" -∞ +∞ epoch
|
||||
|
|
@ -100,12 +323,19 @@ void Calendar::lookupICUEra(ExecutionState& state, const std::function<bool(size
|
|||
{
|
||||
// non-canonical form
|
||||
if (id() == ID::Gregorian) {
|
||||
if (fn(0, "bce")) {
|
||||
return;
|
||||
}
|
||||
if (fn(1, "ce")) {
|
||||
return;
|
||||
}
|
||||
if (fn(0, "bc")) {
|
||||
return;
|
||||
}
|
||||
if (fn(1, "ad")) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
} else if (id() == ID::Ethiopian) {
|
||||
// for old-icu(~77)
|
||||
if (fn(0, "aa")) {
|
||||
|
|
@ -114,6 +344,7 @@ void Calendar::lookupICUEra(ExecutionState& state, const std::function<bool(size
|
|||
if (fn(1, "am")) {
|
||||
return;
|
||||
}
|
||||
return;
|
||||
} else if (id() >= ID::Islamic && id() <= ID::IslamicUmmAlQura) {
|
||||
// for old-icu(~77)
|
||||
if (fn(0, "ah")) {
|
||||
|
|
@ -1424,6 +1655,51 @@ TemporalPlainYearMonthObject* Temporal::toTemporalYearMonth(ExecutionState& stat
|
|||
plainDate, mayID.value());
|
||||
}
|
||||
|
||||
static void makeUnder1972YearCalendar(ExecutionState& state, Calendar calendar, CalendarFieldsRecord fields, UCalendar* icuCalendar, bool wasYearSpecified)
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t diff = 0;
|
||||
ISO8601::PlainDate lastISODate;
|
||||
while (true) {
|
||||
bool shouldChangeYear = false;
|
||||
if (fields.monthCode) {
|
||||
auto mc = calendar.monthCode(state, icuCalendar);
|
||||
if (mc != fields.monthCode.value()) {
|
||||
shouldChangeYear = true;
|
||||
}
|
||||
} else if (fields.month) {
|
||||
unsigned test = calendar.ordinalMonth(state, icuCalendar);
|
||||
CHECK_ICU_CALENDAR();
|
||||
if (test != fields.month.value()) {
|
||||
shouldChangeYear = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldChangeYear) {
|
||||
// should change year
|
||||
diff++;
|
||||
} else {
|
||||
if (wasYearSpecified && calendar.hasLeapMonths() && !fields.monthCode) {
|
||||
fields.monthCode = calendar.monthCode(state, icuCalendar);
|
||||
}
|
||||
|
||||
auto isoDate = Temporal::computeISODate(state, icuCalendar);
|
||||
diff += isoDate.year() - 1972 - 1;
|
||||
if (lastISODate == isoDate) {
|
||||
diff++;
|
||||
}
|
||||
if (isoDate.year() <= 1972) {
|
||||
break;
|
||||
}
|
||||
lastISODate = isoDate;
|
||||
}
|
||||
|
||||
calendar.setYear(state, icuCalendar, fields.year.value() - diff);
|
||||
setICUMonth(state, calendar, fields, icuCalendar);
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, fields.day.value());
|
||||
}
|
||||
}
|
||||
|
||||
TemporalPlainMonthDayObject* Temporal::toTemporalMonthDay(ExecutionState& state, Value item, Value options)
|
||||
{
|
||||
// If options is not present, set options to undefined.
|
||||
|
|
@ -1470,31 +1746,28 @@ TemporalPlainMonthDayObject* Temporal::toTemporalMonthDay(ExecutionState& state,
|
|||
}
|
||||
|
||||
int32_t testYear = 1972;
|
||||
ISO8601::PlainDate plainDate;
|
||||
ISO8601::PlainDate isoDate;
|
||||
Optional<ISO8601::TimeZoneRecord> timeZone;
|
||||
Optional<ISO8601::CalendarID> calendarID;
|
||||
|
||||
if (result) {
|
||||
plainDate = std::get<0>(result.value());
|
||||
isoDate = std::get<0>(result.value());
|
||||
timeZone = std::get<2>(result.value());
|
||||
calendarID = std::get<3>(result.value());
|
||||
|
||||
if (calendarID && calendarID.value() != "iso8601") {
|
||||
testYear = plainDate.year();
|
||||
testYear = isoDate.year();
|
||||
}
|
||||
|
||||
if (!std::get<1>(result.value()) && timeZone && timeZone.value().m_offset) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "ToTemporalMonthDay needs ISO Time string without UTC designator");
|
||||
}
|
||||
} else {
|
||||
plainDate = std::get<0>(parseResultMonthDay.value());
|
||||
isoDate = std::get<0>(parseResultMonthDay.value());
|
||||
timeZone = std::get<1>(parseResultMonthDay.value());
|
||||
calendarID = std::get<2>(parseResultMonthDay.value());
|
||||
}
|
||||
|
||||
// override year
|
||||
plainDate = ISO8601::PlainDate(1972, plainDate.month(), plainDate.day());
|
||||
|
||||
if (timeZone && timeZone.value().m_z) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "ToTemporalMonthDay needs ISO Time string without UTC designator");
|
||||
}
|
||||
|
|
@ -1505,7 +1778,7 @@ TemporalPlainMonthDayObject* Temporal::toTemporalMonthDay(ExecutionState& state,
|
|||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "ToTemporalMonthDay needs ISO8601 calendar");
|
||||
}
|
||||
|
||||
if (!ISO8601::isDateTimeWithinLimits(testYear, plainDate.month(), plainDate.day(), 12, 0, 0, 0, 0, 0)) {
|
||||
if (!ISO8601::isDateTimeWithinLimits(testYear, isoDate.month(), isoDate.day(), 12, 0, 0, 0, 0, 0)) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "ToTemporalMonthDay needs ISO Date string in valid range");
|
||||
}
|
||||
|
||||
|
|
@ -1520,12 +1793,36 @@ TemporalPlainMonthDayObject* Temporal::toTemporalMonthDay(ExecutionState& state,
|
|||
if (!mayID) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid CalendarID");
|
||||
}
|
||||
|
||||
// Let resolvedOptions be ? GetOptionsObject(options).
|
||||
auto resolvedOptions = Intl::getOptionsObject(state, options);
|
||||
// Perform ? GetTemporalOverflowOption(resolvedOptions).
|
||||
Temporal::getTemporalOverflowOption(state, resolvedOptions);
|
||||
|
||||
LocalResourcePointer<UCalendar> icuCalendar(mayID.value().createICUCalendar(state), [](UCalendar* r) {
|
||||
ucal_close(r);
|
||||
});
|
||||
|
||||
if (mayID.value().isISO8601()) {
|
||||
isoDate = ISO8601::PlainDate(1972, isoDate.month(), isoDate.day());
|
||||
}
|
||||
auto epoch = ISO8601::ExactTime::fromPlainDate(isoDate).epochMilliseconds();
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
ucal_setMillis(icuCalendar.get(), epoch, &status);
|
||||
CHECK_ICU_CALENDAR();
|
||||
|
||||
if (!mayID.value().isISO8601()) {
|
||||
CalendarFieldsRecord fields;
|
||||
fields.year = mayID.value().year(state, icuCalendar.get());
|
||||
fields.month = mayID.value().ordinalMonth(state, icuCalendar.get());
|
||||
fields.day = ucal_get(icuCalendar.get(), UCAL_DAY_OF_MONTH, &status);
|
||||
CHECK_ICU_CALENDAR();
|
||||
|
||||
makeUnder1972YearCalendar(state, mayID.value(), fields, icuCalendar.get(), true);
|
||||
}
|
||||
|
||||
return new TemporalPlainMonthDayObject(state, state.context()->globalObject()->temporalPlainMonthDayPrototype(),
|
||||
plainDate, mayID.value());
|
||||
icuCalendar.release(), mayID.value());
|
||||
}
|
||||
|
||||
Int128 Temporal::getStartOfDay(ExecutionState& state, TimeZone timeZone, ISO8601::PlainDate isoDate)
|
||||
|
|
@ -2963,229 +3260,6 @@ CalendarFieldsRecord Temporal::prepareCalendarFields(ExecutionState& state, Cale
|
|||
return result;
|
||||
}
|
||||
|
||||
static void setICUYear(ExecutionState& state, Calendar calendar, const CalendarFieldsRecord& fields, UCalendar* icuCalendar)
|
||||
{
|
||||
if (calendar.isEraRelated() && (fields.era && fields.eraYear)) {
|
||||
calendar.setYear(state, icuCalendar, fields.era.value(), fields.eraYear.value());
|
||||
} else if (fields.year) {
|
||||
calendar.setYear(state, icuCalendar, fields.year.value());
|
||||
}
|
||||
}
|
||||
|
||||
static void setICUMonth(ExecutionState& state, Calendar calendar, const CalendarFieldsRecord& fields, UCalendar* icuCalendar)
|
||||
{
|
||||
if (fields.month) {
|
||||
calendar.setOrdinalMonth(state, icuCalendar, fields.month.value());
|
||||
}
|
||||
if (fields.monthCode) {
|
||||
calendar.setMonth(icuCalendar, fields.monthCode.value());
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t monthsPerYear(Calendar calendar)
|
||||
{
|
||||
if (calendar.hasEpagomenalMonths() || calendar.hasLeapMonths()) {
|
||||
return 13;
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
|
||||
static uint8_t monthCodePerYear(Calendar calendar)
|
||||
{
|
||||
if (calendar.hasEpagomenalMonths()) {
|
||||
return 13;
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-intl-era-monthcode/#table-additional-month-codes
|
||||
static uint8_t daysInMonth(ExecutionState& state, Calendar calendar, UCalendar* icuCalendar, const CalendarFieldsRecord& fields)
|
||||
{
|
||||
switch (calendar.id()) {
|
||||
case Calendar::ID::ISO8601:
|
||||
case Calendar::ID::Buddhist:
|
||||
case Calendar::ID::Gregorian:
|
||||
case Calendar::ID::Japanese:
|
||||
case Calendar::ID::ROC:
|
||||
if (fields.year) {
|
||||
return ISO8601::daysInMonth(fields.year.value() + calendar.epochISOYear(), fields.month ? fields.month.value() : fields.monthCode.value().monthNumber);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
setICUYear(state, calendar, fields, icuCalendar);
|
||||
setICUMonth(state, calendar, fields, icuCalendar);
|
||||
return TemporalPlainDateGetter::daysInMonth(state, ISO8601::PlainDate(), calendar, icuCalendar).asInt32();
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> isoDaysInMonth(uint8_t ordinal)
|
||||
{
|
||||
if (ordinal == 2) {
|
||||
return { 28, 29 };
|
||||
}
|
||||
if (ordinal == 4 || ordinal == 6 || ordinal == 9 || ordinal == 11) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
return { 31, 31 };
|
||||
}
|
||||
|
||||
static std::pair<uint8_t, uint8_t> daysInMonth(Calendar calendar, MonthCode mc, uint8_t ordinal)
|
||||
{
|
||||
switch (calendar.id()) {
|
||||
case Calendar::ID::ISO8601:
|
||||
case Calendar::ID::Buddhist:
|
||||
case Calendar::ID::Gregorian:
|
||||
case Calendar::ID::Japanese:
|
||||
case Calendar::ID::ROC:
|
||||
return isoDaysInMonth(ordinal);
|
||||
|
||||
case Calendar::ID::Chinese:
|
||||
case Calendar::ID::Dangi:
|
||||
return { 29, 30 };
|
||||
|
||||
case Calendar::ID::Coptic:
|
||||
case Calendar::ID::Ethiopian:
|
||||
case Calendar::ID::EthiopianAmeteAlem: {
|
||||
if (ordinal <= 12) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
return { 5, 6 };
|
||||
}
|
||||
|
||||
case Calendar::ID::Hebrew: {
|
||||
if (ordinal == 2 || ordinal == 3) {
|
||||
return { 29, 30 };
|
||||
}
|
||||
if ((ordinal & 1) == 1 || mc.isLeapMonth) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
return { 29, 29 };
|
||||
}
|
||||
|
||||
case Calendar::ID::Indian: {
|
||||
if (ordinal == 1) {
|
||||
return { 30, 31 };
|
||||
}
|
||||
if (ordinal <= 6) {
|
||||
return { 31, 31 };
|
||||
}
|
||||
return { 30, 30 };
|
||||
}
|
||||
|
||||
case Calendar::ID::IslamicUmmAlQura:
|
||||
return { 29, 30 };
|
||||
|
||||
case Calendar::ID::IslamicCivil:
|
||||
case Calendar::ID::IslamicCivilLegacy:
|
||||
case Calendar::ID::IslamicTabular: {
|
||||
if ((ordinal & 1) == 1) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
if (ordinal < 12) {
|
||||
return { 29, 29 };
|
||||
}
|
||||
return { 29, 30 };
|
||||
}
|
||||
|
||||
case Calendar::ID::Persian: {
|
||||
if (ordinal <= 6) {
|
||||
return { 31, 31 };
|
||||
}
|
||||
if (ordinal <= 11) {
|
||||
return { 30, 30 };
|
||||
}
|
||||
return { 29, 30 };
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
return { 29, 31 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Optional<MonthCode> setICUMonthDay(ExecutionState& state, Calendar calendar, const CalendarFieldsRecord& fields, UCalendar* icuCalendar, TemporalOverflowOption overflow)
|
||||
{
|
||||
if (overflow == TemporalOverflowOption::Constrain) {
|
||||
auto day = fields.day.value();
|
||||
while (day) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, 1);
|
||||
setICUYear(state, calendar, fields, icuCalendar);
|
||||
setICUMonth(state, calendar, fields, icuCalendar);
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, day);
|
||||
if (fields.month) {
|
||||
unsigned test = calendar.ordinalMonth(state, icuCalendar);
|
||||
CHECK_ICU_CALENDAR();
|
||||
if (test != fields.month.value()) {
|
||||
day--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (fields.monthCode) {
|
||||
auto mc = calendar.monthCode(state, icuCalendar);
|
||||
if (fields.monthCode.value() != mc) {
|
||||
day--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return NullOption;
|
||||
}
|
||||
|
||||
// convert to non-leap month
|
||||
if (calendar.hasLeapMonths() && fields.monthCode && fields.monthCode.value().isLeapMonth) {
|
||||
// with hebrew, only M05L is valid
|
||||
Optional<MonthCode> newConstrainedMonth;
|
||||
if ((calendar.id() == Calendar::ID::Hebrew && fields.monthCode.value().monthNumber == 5)) {
|
||||
newConstrainedMonth = MonthCode();
|
||||
newConstrainedMonth.value().monthNumber = 6;
|
||||
} else if (calendar.id() == Calendar::ID::Chinese || calendar.id() == Calendar::ID::Dangi) {
|
||||
// use non-leap months for other
|
||||
newConstrainedMonth = MonthCode();
|
||||
newConstrainedMonth.value().monthNumber = fields.monthCode.value().monthNumber;
|
||||
}
|
||||
if (newConstrainedMonth) {
|
||||
day = fields.day.value();
|
||||
while (day) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, 1);
|
||||
setICUYear(state, calendar, fields, icuCalendar);
|
||||
calendar.setMonth(icuCalendar, newConstrainedMonth.value());
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, day);
|
||||
if (fields.month) {
|
||||
unsigned test = calendar.ordinalMonth(state, icuCalendar);
|
||||
CHECK_ICU_CALENDAR();
|
||||
if (test != fields.month.value()) {
|
||||
day--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto mc = calendar.monthCode(state, icuCalendar);
|
||||
if (newConstrainedMonth.value() != mc) {
|
||||
day--;
|
||||
continue;
|
||||
}
|
||||
|
||||
return newConstrainedMonth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (day == 0) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid monthCode or month");
|
||||
}
|
||||
} else {
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, 1);
|
||||
setICUMonth(state, calendar, fields, icuCalendar);
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, fields.day.value());
|
||||
}
|
||||
return NullOption;
|
||||
}
|
||||
|
||||
// https://tc39.es/proposal-temporal/#sec-temporal-calendarresolvefields
|
||||
std::pair<UCalendar*, Optional<ISO8601::PlainDate>> Temporal::calendarResolveFields(ExecutionState& state, Calendar calendar, CalendarFieldsRecord fields, TemporalOverflowOption overflow, CalendarDateFromFieldsMode mode)
|
||||
{
|
||||
|
|
@ -3343,44 +3417,8 @@ std::pair<UCalendar*, Optional<ISO8601::PlainDate>> Temporal::calendarResolveFie
|
|||
}
|
||||
}
|
||||
|
||||
// test262/test/staging/sm/Temporal/PlainMonthDay/result-not-after-1972-dec-31.js
|
||||
if (shouldTestUnder1972Year) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int32_t diff = 0;
|
||||
while (true) {
|
||||
bool shouldChangeYear = false;
|
||||
if (fields.monthCode) {
|
||||
auto mc = calendar.monthCode(state, icuCalendar);
|
||||
if (mc != fields.monthCode.value()) {
|
||||
shouldChangeYear = true;
|
||||
}
|
||||
} else if (fields.month) {
|
||||
unsigned test = calendar.ordinalMonth(state, icuCalendar);
|
||||
CHECK_ICU_CALENDAR();
|
||||
if (test != fields.month.value()) {
|
||||
shouldChangeYear = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldChangeYear) {
|
||||
// should change year
|
||||
diff++;
|
||||
} else {
|
||||
if (wasYearSpecified && calendar.hasLeapMonths() && !fields.monthCode) {
|
||||
fields.monthCode = calendar.monthCode(state, icuCalendar);
|
||||
}
|
||||
|
||||
auto isoDate = computeISODate(state, icuCalendar);
|
||||
diff += isoDate.year() - 1972;
|
||||
if (isoDate.year() - 1972 <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
calendar.setYear(state, icuCalendar, fields.year.value() - diff);
|
||||
setICUMonth(state, calendar, fields, icuCalendar);
|
||||
ucal_set(icuCalendar, UCAL_DAY_OF_MONTH, fields.day.value());
|
||||
}
|
||||
makeUnder1972YearCalendar(state, calendar, fields, icuCalendar, wasYearSpecified);
|
||||
} else if (!calendar.isISO8601()) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
|
|
@ -3415,6 +3453,7 @@ std::pair<UCalendar*, Optional<ISO8601::PlainDate>> Temporal::calendarDateFromFi
|
|||
// Let result be ? CalendarDateToISO(calendar, fields, overflow).
|
||||
// If ISOYearMonthWithinLimits(result) is false, throw a RangeError exception.
|
||||
if (result.second) {
|
||||
result.second.value() = ISO8601::PlainDate(result.second.value().year(), result.second.value().month(), 1);
|
||||
if (!isoYearMonthWithinLimits(ISO8601::PlainDate(result.second.value().year(), result.second.value().month(), result.second.value().day()))) {
|
||||
ucal_close(result.first);
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::RangeError, "Invalid out of range Date");
|
||||
|
|
|
|||
|
|
@ -607,16 +607,9 @@ TemporalPlainDateTimeObject* TemporalPlainDateObject::toPlainDateTime(ExecutionS
|
|||
TemporalPlainMonthDayObject* TemporalPlainDateObject::toPlainMonthDay(ExecutionState& state)
|
||||
{
|
||||
// Let calendar be plainDate.[[Calendar]].
|
||||
// Let fields be ISODateToFields(calendar, plainDate.[[ISODate]], date).
|
||||
auto calendar = m_calendarID;
|
||||
CalendarFieldsRecord fields;
|
||||
auto isoDate = computeISODate(state);
|
||||
fields.year = isoDate.year();
|
||||
fields.month = isoDate.month();
|
||||
MonthCode mc;
|
||||
mc.monthNumber = isoDate.month();
|
||||
fields.monthCode = mc;
|
||||
fields.day = isoDate.day();
|
||||
// Let fields be ISODateToFields(calendar, plainDate.[[ISODate]], date).
|
||||
auto fields = Temporal::isoDateToFields(state, calendar, computeISODate(state), Temporal::ISODateToFieldsType::Date);
|
||||
// Let isoDate be ? CalendarMonthDayFromFields(calendar, fields, constrain).
|
||||
auto u = Temporal::calendarDateFromFields(state, calendar, fields, TemporalOverflowOption::Constrain, Temporal::CalendarDateFromFieldsMode::MonthDay);
|
||||
// Return ! CreateTemporalMonthDay(isoDate, calendar).
|
||||
|
|
@ -626,20 +619,13 @@ TemporalPlainMonthDayObject* TemporalPlainDateObject::toPlainMonthDay(ExecutionS
|
|||
TemporalPlainYearMonthObject* TemporalPlainDateObject::toPlainYearMonth(ExecutionState& state)
|
||||
{
|
||||
// Let calendar be plainDate.[[Calendar]].
|
||||
// Let fields be ISODateToFields(calendar, plainDate.[[ISODate]], date).
|
||||
auto calendar = m_calendarID;
|
||||
CalendarFieldsRecord fields;
|
||||
auto isoDate = computeISODate(state);
|
||||
fields.year = isoDate.year();
|
||||
fields.month = isoDate.month();
|
||||
MonthCode mc;
|
||||
mc.monthNumber = isoDate.month();
|
||||
fields.monthCode = mc;
|
||||
fields.day = 1;
|
||||
// Let fields be ISODateToFields(calendar, plainDate.[[ISODate]], date).
|
||||
auto fields = Temporal::isoDateToFields(state, calendar, computeISODate(state), Temporal::ISODateToFieldsType::Date);
|
||||
// Let isoDate be ? CalendarYearMonthFromFields(calendar, fields, constrain).
|
||||
auto u = Temporal::calendarDateFromFields(state, calendar, fields, TemporalOverflowOption::Constrain, Temporal::CalendarDateFromFieldsMode::YearMonth);
|
||||
// Return ! CreateTemporalYearMonth(isoDate, calendar).
|
||||
return new TemporalPlainYearMonthObject(state, state.context()->globalObject()->temporalPlainYearMonthPrototype(), u, calendar);
|
||||
return new TemporalPlainYearMonthObject(state, state.context()->globalObject()->temporalPlainYearMonthPrototype(), u, m_calendarID);
|
||||
}
|
||||
|
||||
TemporalZonedDateTimeObject* TemporalPlainDateObject::toZonedDateTime(ExecutionState& state, Value item)
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ namespace Escargot {
|
|||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "failed to get value from ICU calendar"); \
|
||||
}
|
||||
|
||||
TemporalPlainMonthDayObject::TemporalPlainMonthDayObject(ExecutionState& state, Object* proto, ISO8601::PlainDate plainDate, Calendar calendar)
|
||||
: TemporalPlainDateObject(state, proto, plainDate, calendar)
|
||||
TemporalPlainMonthDayObject::TemporalPlainMonthDayObject(ExecutionState& state, Object* proto, ISO8601::PlainDate isoDate, Calendar calendar)
|
||||
: TemporalPlainDateObject(state, proto, isoDate, calendar)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -99,13 +99,15 @@ TemporalPlainMonthDayObject* TemporalPlainMonthDayObject::with(ExecutionState& s
|
|||
|
||||
// intl402/Temporal/PlainMonthDay/prototype/with/fields-missing-properties
|
||||
if (!calendar.isISO8601()) {
|
||||
bool missing = false;
|
||||
if (partialMonthDay.month && !partialMonthDay.day) {
|
||||
missing = true;
|
||||
} else if (partialMonthDay.monthCode && !partialMonthDay.day) {
|
||||
missing = true;
|
||||
} else if (partialMonthDay.day && !partialMonthDay.month && !partialMonthDay.monthCode) {
|
||||
missing = true;
|
||||
bool missing = true;
|
||||
if (partialMonthDay.monthCode) {
|
||||
missing = false;
|
||||
} else if (partialMonthDay.day) {
|
||||
missing = false;
|
||||
} else if (partialMonthDay.year) {
|
||||
missing = false;
|
||||
} else if (calendar.isEraRelated() && (partialMonthDay.era || partialMonthDay.eraYear)) {
|
||||
missing = false;
|
||||
}
|
||||
if (missing) {
|
||||
ErrorObject::throwBuiltinError(state, ErrorCode::TypeError, "Invalid temporalMonthDayLike");
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Escargot {
|
|||
|
||||
class TemporalPlainMonthDayObject : public TemporalPlainDateObject {
|
||||
public:
|
||||
TemporalPlainMonthDayObject(ExecutionState& state, Object* proto, ISO8601::PlainDate plainYearMonth, Calendar calendar);
|
||||
TemporalPlainMonthDayObject(ExecutionState& state, Object* proto, ISO8601::PlainDate isoYearMonth, Calendar calendar);
|
||||
TemporalPlainMonthDayObject(ExecutionState& state, Object* proto, UCalendar* icuCalendar, Calendar calendar);
|
||||
|
||||
virtual bool isTemporalPlainDateObject() const override
|
||||
|
|
|
|||
|
|
@ -183,7 +183,8 @@ String* TemporalZonedDateTimeObject::toString(ExecutionState& state, Value optio
|
|||
auto precision = Temporal::toSecondsStringPrecisionRecord(state, toDateTimeUnit(smallestUnit), digits);
|
||||
|
||||
// Return TemporalZonedDateTimeToString(zonedDateTime, precision.[[Precision]], showCalendar, showTimeZone, showOffset, precision.[[Increment]], precision.[[Unit]], roundingMode).
|
||||
auto result = Temporal::roundISODateTime(state, ISO8601::PlainDateTime(plainDate(), plainTime()), precision.increment, precision.unit, roundingMode);
|
||||
auto isoDateTime = Temporal::getISODateTimeFor(state, TimeZone(m_timeZone), epochNanoseconds());
|
||||
auto result = Temporal::roundISODateTime(state, isoDateTime, precision.increment, precision.unit, roundingMode);
|
||||
StringBuilder sb;
|
||||
sb.appendString(TemporalPlainDateObject::temporalDateToString(result.plainDate(), m_calendarID, TemporalShowCalendarNameOption::Never));
|
||||
sb.appendChar('T');
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ public:
|
|||
private:
|
||||
void init(ExecutionState& state, ComputedTimeZone timeZone);
|
||||
Int128* m_epochNanoseconds;
|
||||
ISO8601::PlainDateTime* m_plainDateTime; // stores timezone applied value
|
||||
ISO8601::PlainDateTime* m_plainDateTime; // stores timezone + calendar applied value
|
||||
ComputedTimeZone m_timeZone;
|
||||
Calendar m_calendarID;
|
||||
UCalendar* m_icuCalendar;
|
||||
|
|
|
|||
|
|
@ -489,9 +489,7 @@
|
|||
<test id="intl402/Temporal/PlainDateTime/prototype/withCalendar/extreme-dates"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainMonthDay/from/calendarresolvefields-error-ordering-chinese"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainMonthDay/from/calendarresolvefields-error-ordering-islamic"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainMonthDay/from/reference-date-noniso-calendar"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainMonthDay/prototype/monthCode/chinese-calendar-dates"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainMonthDay/prototype/with/non-iso-calendar-fields"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainYearMonth/from/extreme-dates"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainYearMonth/from/reference-day-chinese"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainYearMonth/from/reference-day-hebrew"><reason>TODO</reason></test>
|
||||
|
|
@ -504,12 +502,9 @@
|
|||
<test id="intl402/Temporal/PlainYearMonth/prototype/until/canonicalize-calendar"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainYearMonth/prototype/until/chinese-calendar-dates"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainYearMonth/prototype/until/dangi-calendar-dates"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/PlainYearMonth/prototype/year/epoch-year"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/from/canonicalize-era-codes"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/from/dst-skipped-cross-midnight"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/from/extreme-dates"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/prototype/add/leap-year-persian"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/prototype/daysInMonth/basic-coptic"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/nanoseconds-subtracted-or-added-at-dst-transition"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/prototype/hoursInDay/dst-skipped-cross-midnight"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/prototype/monthCode/chinese-calendar-dates"><reason>TODO</reason></test>
|
||||
|
|
@ -557,7 +552,6 @@
|
|||
<test id="intl402/Temporal/ZonedDateTime/prototype/until/wrapping-at-end-of-month-persian"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/prototype/withCalendar/extreme-dates"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/prototype/withPlainTime/dst-skipped-cross-midnight"><reason>TODO</reason></test>
|
||||
<test id="intl402/Temporal/ZonedDateTime/prototype/year/arithmetic-year"><reason>TODO</reason></test>
|
||||
<test id="intl402/TypedArray/prototype/toLocaleString/calls-toLocaleString-number-elements"><reason>TODO</reason></test>
|
||||
<test id="intl402/language-tags-with-underscore"><reason>TODO</reason></test>
|
||||
<test id="language/block-scope/syntax/redeclaration/inner-block-var-name-redeclaration-attempt-with-function"><reason>TODO</reason></test>
|
||||
|
|
@ -1448,4 +1442,4 @@
|
|||
<test id="staging/sm/syntax/let-as-label"><reason>TODO</reason></test>
|
||||
<test id="staging/sm/types/8.12.5-01"><reason>TODO</reason></test>
|
||||
<test id="staging/source-phase-imports/import-source-source-text-module"><reason>TODO</reason></test>
|
||||
</excludeList>
|
||||
</excludeList>
|
||||
Loading…
Add table
Add a link
Reference in a new issue