/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/intl/calendar/ICU4XChineseBasedCalendar.h" #include "mozilla/Assertions.h" namespace mozilla::intl::calendar { ICU4XChineseBasedCalendar::ICU4XChineseBasedCalendar( icu4x::capi::CalendarKind kind, const icu::Locale& locale, UErrorCode& success) : ICU4XCalendar(kind, locale, success) {} ICU4XChineseBasedCalendar::ICU4XChineseBasedCalendar( icu4x::capi::CalendarKind kind, const icu::TimeZone& timeZone, const icu::Locale& locale, UErrorCode& success) : ICU4XCalendar(kind, timeZone, locale, success) {} ICU4XChineseBasedCalendar::ICU4XChineseBasedCalendar( const ICU4XChineseBasedCalendar& other) = default; ICU4XChineseBasedCalendar::~ICU4XChineseBasedCalendar() = default; //////////////////////////////////////////// // ICU4XCalendar implementation overrides // //////////////////////////////////////////// bool ICU4XChineseBasedCalendar::hasLeapMonths() const { return true; } bool ICU4XChineseBasedCalendar::hasMonthCode(MonthCode monthCode) const { return monthCode.ordinal() <= 12; } //////////////////////////////////////////// // icu::Calendar implementation overrides // //////////////////////////////////////////// bool ICU4XChineseBasedCalendar::inTemporalLeapYear(UErrorCode& status) const { int32_t days = getActualMaximum(UCAL_DAY_OF_YEAR, status); if (U_FAILURE(status)) { return false; } constexpr int32_t maxDaysInMonth = 30; constexpr int32_t monthsInNonLeapYear = 12; return days > (monthsInNonLeapYear * maxDaysInMonth); } void ICU4XChineseBasedCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status) { int32_t gyear = getGregorianYear(); int32_t gmonth = getGregorianMonth() + 1; int32_t gday = getGregorianDayOfMonth(); MOZ_ASSERT(1 <= gmonth && gmonth <= 12); MOZ_ASSERT(1 <= gday && gday <= 31); auto date = createICU4XDate(ISODate{gyear, gmonth, gday}, status); if (U_FAILURE(status)) { return; } MOZ_ASSERT(date); MonthCode monthCode = monthCodeFrom(date.get()); int32_t extendedYear = icu4x::capi::icu4x_Date_era_year_or_related_iso_mv1(date.get()); int32_t month = icu4x::capi::icu4x_Date_ordinal_month_mv1(date.get()); int32_t dayOfMonth = icu4x::capi::icu4x_Date_day_of_month_mv1(date.get()); int32_t dayOfYear = icu4x::capi::icu4x_Date_day_of_year_mv1(date.get()); MOZ_ASSERT(1 <= month && month <= 13); MOZ_ASSERT(1 <= dayOfMonth && dayOfMonth <= 30); MOZ_ASSERT(1 <= dayOfYear && dayOfYear <= (13 * 30)); // Difference between the Chinese calendar era (the extended year 1) and the // start year used for cycle computations. This is the sixtieth year of reign // of Huáng Dì. Other sources use the first year of reign, which means using // -2697 instead. Both numbers result in the same year of cycle, but the // latter number gives a different cycle number. To align with the ICU4C // Chinese calendar implementation, we use -2637 here. constexpr int32_t chineseCalendarYearDiff = -2637; // Compute the cycle and year of cycle relative to the Chinese calendar, even // when this is the Dangi calendar. int32_t chineseCalendarYear = extendedYear - chineseCalendarYearDiff; int32_t cycle_year = chineseCalendarYear - 1; int32_t cycle = FloorDiv(cycle_year, 60); int32_t yearOfCycle = cycle_year - (cycle * 60); internalSet(UCAL_ERA, cycle + 1); internalSet(UCAL_YEAR, yearOfCycle + 1); internalSet(UCAL_EXTENDED_YEAR, extendedYear); internalSet(UCAL_MONTH, monthCode.ordinal() - 1); internalSet(UCAL_ORDINAL_MONTH, month - 1); internalSet(UCAL_IS_LEAP_MONTH, monthCode.isLeapMonth() ? 1 : 0); internalSet(UCAL_DAY_OF_MONTH, dayOfMonth); internalSet(UCAL_DAY_OF_YEAR, dayOfYear); } // Limits table copied from i18n/chnsecal.cpp. Licensed under: // // © 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html static const int32_t CHINESE_CALENDAR_LIMITS[UCAL_FIELD_COUNT][4] = { // clang-format off // Minimum Greatest Least Maximum // Minimum Maximum { 1, 1, 83333, 83333}, // ERA { 1, 1, 60, 60}, // YEAR { 0, 0, 11, 11}, // MONTH { 1, 1, 50, 55}, // WEEK_OF_YEAR {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH { 1, 1, 29, 30}, // DAY_OF_MONTH { 1, 1, 353, 385}, // DAY_OF_YEAR {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY { 0, 0, 1, 1}, // IS_LEAP_MONTH { 0, 0, 11, 12}, // ORDINAL_MONTH // clang-format on }; int32_t ICU4XChineseBasedCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const { return CHINESE_CALENDAR_LIMITS[field][limitType]; } // Field resolution table copied from i18n/chnsecal.cpp. Licensed under: // // © 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html const icu::UFieldResolutionTable ICU4XChineseBasedCalendar::CHINESE_DATE_PRECEDENCE[] = { // clang-format off { { UCAL_DAY_OF_MONTH, kResolveSTOP }, { UCAL_WEEK_OF_YEAR, UCAL_DAY_OF_WEEK, kResolveSTOP }, { UCAL_WEEK_OF_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP }, { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP }, { UCAL_WEEK_OF_YEAR, UCAL_DOW_LOCAL, kResolveSTOP }, { UCAL_WEEK_OF_MONTH, UCAL_DOW_LOCAL, kResolveSTOP }, { UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP }, { UCAL_DAY_OF_YEAR, kResolveSTOP }, { kResolveRemap | UCAL_DAY_OF_MONTH, UCAL_IS_LEAP_MONTH, kResolveSTOP }, { kResolveSTOP } }, { { UCAL_WEEK_OF_YEAR, kResolveSTOP }, { UCAL_WEEK_OF_MONTH, kResolveSTOP }, { UCAL_DAY_OF_WEEK_IN_MONTH, kResolveSTOP }, { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DAY_OF_WEEK, kResolveSTOP }, { kResolveRemap | UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_DOW_LOCAL, kResolveSTOP }, { kResolveSTOP } }, {{kResolveSTOP}} // clang-format on }; const icu::UFieldResolutionTable* ICU4XChineseBasedCalendar::getFieldResolutionTable() const { return CHINESE_DATE_PRECEDENCE; } } // namespace mozilla::intl::calendar