tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ICU4XCalendar.cpp (18362B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "mozilla/intl/calendar/ICU4XCalendar.h"
      6 
      7 #include "mozilla/Assertions.h"
      8 #include "mozilla/TextUtils.h"
      9 
     10 #include <cstring>
     11 #include <mutex>
     12 #include <stdint.h>
     13 #include <type_traits>
     14 
     15 #include "unicode/timezone.h"
     16 
     17 #include "diplomat_runtime.hpp"
     18 #include "icu4x/CalendarError.hpp"
     19 
     20 namespace mozilla::intl::calendar {
     21 
     22 // Copied from js/src/util/Text.h
     23 template <typename CharT>
     24 static constexpr uint8_t AsciiDigitToNumber(CharT c) {
     25  using UnsignedCharT = std::make_unsigned_t<CharT>;
     26  auto uc = static_cast<UnsignedCharT>(c);
     27  return uc - '0';
     28 }
     29 
     30 static UniqueICU4XCalendar CreateICU4XCalendar(icu4x::capi::CalendarKind kind) {
     31  auto* result = icu4x::capi::icu4x_Calendar_create_mv1(kind);
     32  return UniqueICU4XCalendar{result};
     33 }
     34 
     35 static UniqueICU4XDate CreateICU4XDate(const ISODate& date,
     36                                       const icu4x::capi::Calendar* calendar) {
     37  auto result = icu4x::capi::icu4x_Date_from_iso_in_calendar_mv1(
     38      date.year, date.month, date.day, calendar);
     39  if (!result.is_ok) {
     40    return nullptr;
     41  }
     42  return UniqueICU4XDate{result.ok};
     43 }
     44 
     45 static UniqueICU4XDate CreateDateFromCodes(
     46    const icu4x::capi::Calendar* calendar, std::string_view era,
     47    int32_t eraYear, MonthCode monthCode, int32_t day) {
     48  auto monthCodeView = std::string_view{monthCode};
     49  auto date = icu4x::capi::icu4x_Date_from_codes_in_calendar_mv1(
     50      diplomat::capi::DiplomatStringView{era.data(), era.length()}, eraYear,
     51      diplomat::capi::DiplomatStringView{monthCodeView.data(),
     52                                         monthCodeView.length()},
     53      day, calendar);
     54  if (date.is_ok) {
     55    return UniqueICU4XDate{date.ok};
     56  }
     57  return nullptr;
     58 }
     59 
     60 // Copied from js/src/builtin/temporal/Calendar.cpp
     61 static UniqueICU4XDate CreateDateFrom(const icu4x::capi::Calendar* calendar,
     62                                      std::string_view era, int32_t eraYear,
     63                                      int32_t month, int32_t day) {
     64  MOZ_ASSERT(1 <= month && month <= 13);
     65 
     66  // Create date with month number replaced by month-code.
     67  auto monthCode = MonthCode{std::min(month, 12)};
     68  auto date = CreateDateFromCodes(calendar, era, eraYear, monthCode, day);
     69  if (!date) {
     70    return nullptr;
     71  }
     72 
     73  // If the ordinal month of |date| matches the input month, no additional
     74  // changes are necessary and we can directly return |date|.
     75  int32_t ordinal = icu4x::capi::icu4x_Date_ordinal_month_mv1(date.get());
     76  if (ordinal == month) {
     77    return date;
     78  }
     79 
     80  // Otherwise we need to handle three cases:
     81  // 1. The input year contains a leap month and we need to adjust the
     82  //    month-code.
     83  // 2. The thirteenth month of a year without leap months was requested.
     84  // 3. The thirteenth month of a year with leap months was requested.
     85  if (ordinal > month) {
     86    MOZ_ASSERT(1 < month && month <= 12);
     87 
     88    // This case can only happen in leap years.
     89    MOZ_ASSERT(icu4x::capi::icu4x_Date_months_in_year_mv1(date.get()) == 13);
     90 
     91    // Leap months can occur after any month in the Chinese calendar.
     92    //
     93    // Example when the fourth month is a leap month between M03 and M04.
     94    //
     95    // Month code:     M01  M02  M03  M03L  M04  M05  M06 ...
     96    // Ordinal month:  1    2    3    4     5    6    7
     97 
     98    // The month can be off by exactly one.
     99    MOZ_ASSERT((ordinal - month) == 1);
    100 
    101    // First try the case when the previous month isn't a leap month. This
    102    // case can only occur when |month > 2|, because otherwise we know that
    103    // "M01L" is the correct answer.
    104    if (month > 2) {
    105      auto previousMonthCode = MonthCode{month - 1};
    106      date =
    107          CreateDateFromCodes(calendar, era, eraYear, previousMonthCode, day);
    108      if (!date) {
    109        return nullptr;
    110      }
    111      int32_t ordinal = icu4x::capi::icu4x_Date_ordinal_month_mv1(date.get());
    112      if (ordinal == month) {
    113        return date;
    114      }
    115    }
    116 
    117    // Fall-through when the previous month is a leap month.
    118  } else {
    119    MOZ_ASSERT(month == 13);
    120    MOZ_ASSERT(ordinal == 12);
    121 
    122    // Years with leap months contain thirteen months.
    123    if (icu4x::capi::icu4x_Date_months_in_year_mv1(date.get()) != 13) {
    124      return nullptr;
    125    }
    126 
    127    // Fall-through to return leap month "M12L" at the end of the year.
    128  }
    129 
    130  // Finally handle the case when the previous month is a leap month.
    131  auto leapMonthCode = MonthCode{month - 1, /* isLeapMonth= */ true};
    132  return CreateDateFromCodes(calendar, era, eraYear, leapMonthCode, day);
    133 }
    134 
    135 static ISODate ToISODate(const icu4x::capi::Date* date) {
    136  UniqueICU4XIsoDate isoDate{icu4x::capi::icu4x_Date_to_iso_mv1(date)};
    137 
    138  int32_t isoYear = icu4x::capi::icu4x_IsoDate_year_mv1(isoDate.get());
    139  int32_t isoMonth = icu4x::capi::icu4x_IsoDate_month_mv1(isoDate.get());
    140  int32_t isoDay = icu4x::capi::icu4x_IsoDate_day_of_month_mv1(isoDate.get());
    141 
    142  return {isoYear, isoMonth, isoDay};
    143 }
    144 
    145 ////////////////////////////////////////////////////////////////////////////////
    146 
    147 ICU4XCalendar::ICU4XCalendar(icu4x::capi::CalendarKind kind,
    148                             const icu::Locale& locale, UErrorCode& success)
    149    : icu::Calendar(icu::TimeZone::forLocaleOrDefault(locale), locale, success),
    150      kind_(kind) {}
    151 
    152 ICU4XCalendar::ICU4XCalendar(icu4x::capi::CalendarKind kind,
    153                             const icu::TimeZone& timeZone,
    154                             const icu::Locale& locale, UErrorCode& success)
    155    : icu::Calendar(timeZone, locale, success), kind_(kind) {}
    156 
    157 ICU4XCalendar::ICU4XCalendar(const ICU4XCalendar& other)
    158    : icu::Calendar(other), kind_(other.kind_) {}
    159 
    160 ICU4XCalendar::~ICU4XCalendar() = default;
    161 
    162 /**
    163 * Get or create the underlying ICU4X calendar.
    164 */
    165 icu4x::capi::Calendar* ICU4XCalendar::getICU4XCalendar(
    166    UErrorCode& status) const {
    167  if (U_FAILURE(status)) {
    168    return nullptr;
    169  }
    170  if (!calendar_) {
    171    auto result = CreateICU4XCalendar(kind_);
    172    if (!result) {
    173      status = U_INTERNAL_PROGRAM_ERROR;
    174      return nullptr;
    175    }
    176    calendar_ = std::move(result);
    177  }
    178  return calendar_.get();
    179 }
    180 
    181 /**
    182 * Get or create the fallback ICU4C calendar. Used for dates outside the range
    183 * supported by ICU4X.
    184 */
    185 icu::Calendar* ICU4XCalendar::getFallbackCalendar(UErrorCode& status) const {
    186  if (U_FAILURE(status)) {
    187    return nullptr;
    188  }
    189  if (!fallback_) {
    190    icu::Locale locale = getLocale(ULOC_ACTUAL_LOCALE, status);
    191    locale.setKeywordValue("calendar", getType(), status);
    192    fallback_.reset(
    193        icu::Calendar::createInstance(getTimeZone(), locale, status));
    194  }
    195  return fallback_.get();
    196 }
    197 
    198 UniqueICU4XDate ICU4XCalendar::createICU4XDate(const ISODate& date,
    199                                               UErrorCode& status) const {
    200  MOZ_ASSERT(U_SUCCESS(status));
    201 
    202  auto* calendar = getICU4XCalendar(status);
    203  if (U_FAILURE(status)) {
    204    return nullptr;
    205  }
    206 
    207  auto dt = CreateICU4XDate(date, calendar);
    208  if (!dt) {
    209    status = U_INTERNAL_PROGRAM_ERROR;
    210  }
    211  return dt;
    212 }
    213 
    214 MonthCode ICU4XCalendar::monthCodeFrom(const icu4x::capi::Date* date) {
    215  // Storage for the largest valid month code and the terminating NUL-character.
    216  // DiplomatWrite doesn't have std::span version.
    217  // https://github.com/rust-diplomat/diplomat/issues/866
    218  std::string buf;
    219  auto writable = diplomat::WriteFromString(buf);
    220 
    221  icu4x::capi::icu4x_Date_month_code_mv1(date, &writable);
    222 
    223  MOZ_ASSERT(buf.length() >= 3);
    224  MOZ_ASSERT(buf[0] == 'M');
    225  MOZ_ASSERT(mozilla::IsAsciiDigit(buf[1]));
    226  MOZ_ASSERT(mozilla::IsAsciiDigit(buf[2]));
    227  MOZ_ASSERT_IF(buf.length() > 3, buf[3] == 'L');
    228 
    229  int32_t ordinal =
    230      AsciiDigitToNumber(buf[1]) * 10 + AsciiDigitToNumber(buf[2]);
    231  bool isLeapMonth = buf.length() > 3;
    232 
    233  return MonthCode{ordinal, isLeapMonth};
    234 }
    235 
    236 ////////////////////////////////////////////
    237 // icu::Calendar implementation overrides //
    238 ////////////////////////////////////////////
    239 
    240 const char* ICU4XCalendar::getTemporalMonthCode(UErrorCode& status) const {
    241  int32_t month = get(UCAL_MONTH, status);
    242  int32_t isLeapMonth = get(UCAL_IS_LEAP_MONTH, status);
    243  if (U_FAILURE(status)) {
    244    return nullptr;
    245  }
    246 
    247  static const char* MonthCodes[] = {
    248      // Non-leap months.
    249      "M01",
    250      "M02",
    251      "M03",
    252      "M04",
    253      "M05",
    254      "M06",
    255      "M07",
    256      "M08",
    257      "M09",
    258      "M10",
    259      "M11",
    260      "M12",
    261      "M13",
    262 
    263      // Leap months. (Note: There's no thirteenth leap month.)
    264      "M01L",
    265      "M02L",
    266      "M03L",
    267      "M04L",
    268      "M05L",
    269      "M06L",
    270      "M07L",
    271      "M08L",
    272      "M09L",
    273      "M10L",
    274      "M11L",
    275      "M12L",
    276  };
    277 
    278  size_t index = month + (isLeapMonth ? 12 : 0);
    279  if (index >= std::size(MonthCodes)) {
    280    status = U_ILLEGAL_ARGUMENT_ERROR;
    281    return nullptr;
    282  }
    283  return MonthCodes[index];
    284 }
    285 
    286 void ICU4XCalendar::setTemporalMonthCode(const char* code, UErrorCode& status) {
    287  if (U_FAILURE(status)) {
    288    return;
    289  }
    290 
    291  size_t len = std::strlen(code);
    292  if (len < 3 || len > 4 || code[0] != 'M' || !IsAsciiDigit(code[1]) ||
    293      !IsAsciiDigit(code[2]) || (len == 4 && code[3] != 'L')) {
    294    status = U_ILLEGAL_ARGUMENT_ERROR;
    295    return;
    296  }
    297 
    298  int32_t month =
    299      AsciiDigitToNumber(code[1]) * 10 + AsciiDigitToNumber(code[2]);
    300  bool isLeapMonth = len == 4;
    301 
    302  if (month < 1 || month > 13 || (month == 13 && isLeapMonth)) {
    303    status = U_ILLEGAL_ARGUMENT_ERROR;
    304    return;
    305  }
    306 
    307  // Check if this calendar supports the requested month code.
    308  auto monthCode = MonthCode{month, isLeapMonth};
    309  if (!hasMonthCode(monthCode)) {
    310    status = U_ILLEGAL_ARGUMENT_ERROR;
    311    return;
    312  }
    313 
    314  set(UCAL_MONTH, monthCode.ordinal() - 1);
    315  set(UCAL_IS_LEAP_MONTH, int32_t(monthCode.isLeapMonth()));
    316 }
    317 
    318 int32_t ICU4XCalendar::internalGetMonth(int32_t defaultValue,
    319                                        UErrorCode& status) const {
    320  if (U_FAILURE(status)) {
    321    return 0;
    322  }
    323  if (resolveFields(kMonthPrecedence) == UCAL_MONTH) {
    324    return internalGet(UCAL_MONTH, defaultValue);
    325  }
    326  if (!hasLeapMonths()) {
    327    return internalGet(UCAL_ORDINAL_MONTH);
    328  }
    329  return internalGetMonth(status);
    330 }
    331 
    332 /**
    333 * Return the current month, possibly by computing it from |UCAL_ORDINAL_MONTH|.
    334 */
    335 int32_t ICU4XCalendar::internalGetMonth(UErrorCode& status) const {
    336  if (U_FAILURE(status)) {
    337    return 0;
    338  }
    339  if (resolveFields(kMonthPrecedence) == UCAL_MONTH) {
    340    return internalGet(UCAL_MONTH);
    341  }
    342  if (!hasLeapMonths()) {
    343    return internalGet(UCAL_ORDINAL_MONTH);
    344  }
    345 
    346  int32_t extendedYear = internalGet(UCAL_EXTENDED_YEAR);
    347  int32_t ordinalMonth = internalGet(UCAL_ORDINAL_MONTH);
    348 
    349  int32_t month;
    350  int32_t isLeapMonth;
    351  if (requiresFallbackForExtendedYear(extendedYear)) {
    352    // Use the fallback calendar for years outside the range supported by ICU4X.
    353    auto* fallback = getFallbackCalendar(status);
    354    if (U_FAILURE(status)) {
    355      return 0;
    356    }
    357    fallback->clear();
    358    fallback->set(UCAL_EXTENDED_YEAR, extendedYear);
    359    fallback->set(UCAL_ORDINAL_MONTH, ordinalMonth);
    360    fallback->set(UCAL_DAY_OF_MONTH, 1);
    361 
    362    month = fallback->get(UCAL_MONTH, status);
    363    isLeapMonth = fallback->get(UCAL_IS_LEAP_MONTH, status);
    364    if (U_FAILURE(status)) {
    365      return 0;
    366    }
    367  } else {
    368    auto* cal = getICU4XCalendar(status);
    369    if (U_FAILURE(status)) {
    370      return 0;
    371    }
    372 
    373    UniqueICU4XDate date = CreateDateFrom(cal, eraName(extendedYear),
    374                                          extendedYear, ordinalMonth + 1, 1);
    375    if (!date) {
    376      status = U_INTERNAL_PROGRAM_ERROR;
    377      return 0;
    378    }
    379 
    380    MonthCode monthCode = monthCodeFrom(date.get());
    381    month = monthCode.ordinal() - 1;
    382    isLeapMonth = monthCode.isLeapMonth();
    383  }
    384 
    385  auto* nonConstThis = const_cast<ICU4XCalendar*>(this);
    386  nonConstThis->internalSet(UCAL_IS_LEAP_MONTH, isLeapMonth);
    387  nonConstThis->internalSet(UCAL_MONTH, month);
    388 
    389  return month;
    390 }
    391 
    392 void ICU4XCalendar::add(UCalendarDateFields field, int32_t amount,
    393                        UErrorCode& status) {
    394  switch (field) {
    395    case UCAL_MONTH:
    396    case UCAL_ORDINAL_MONTH:
    397      if (amount != 0) {
    398        // Our implementation doesn't yet support this action.
    399        status = U_ILLEGAL_ARGUMENT_ERROR;
    400        break;
    401      }
    402      break;
    403    default:
    404      Calendar::add(field, amount, status);
    405      break;
    406  }
    407 }
    408 
    409 void ICU4XCalendar::add(EDateFields field, int32_t amount, UErrorCode& status) {
    410  add(static_cast<UCalendarDateFields>(field), amount, status);
    411 }
    412 
    413 void ICU4XCalendar::roll(UCalendarDateFields field, int32_t amount,
    414                         UErrorCode& status) {
    415  switch (field) {
    416    case UCAL_MONTH:
    417    case UCAL_ORDINAL_MONTH:
    418      if (amount != 0) {
    419        // Our implementation doesn't yet support this action.
    420        status = U_ILLEGAL_ARGUMENT_ERROR;
    421        break;
    422      }
    423      break;
    424    default:
    425      Calendar::roll(field, amount, status);
    426      break;
    427  }
    428 }
    429 
    430 void ICU4XCalendar::roll(EDateFields field, int32_t amount,
    431                         UErrorCode& status) {
    432  roll(static_cast<UCalendarDateFields>(field), amount, status);
    433 }
    434 
    435 int32_t ICU4XCalendar::handleGetExtendedYear(UErrorCode& status) {
    436  if (U_FAILURE(status)) {
    437    return 0;
    438  }
    439  if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
    440    return internalGet(UCAL_EXTENDED_YEAR, 1);
    441  }
    442 
    443  // We don't yet support the case when UCAL_YEAR is newer.
    444  status = U_UNSUPPORTED_ERROR;
    445  return 0;
    446 }
    447 
    448 int32_t ICU4XCalendar::handleGetYearLength(int32_t extendedYear,
    449                                           UErrorCode& status) const {
    450  // Use the (slower) default implementation for years outside the range
    451  // supported by ICU4X.
    452  if (requiresFallbackForExtendedYear(extendedYear)) {
    453    return icu::Calendar::handleGetYearLength(extendedYear, status);
    454  }
    455 
    456  auto* cal = getICU4XCalendar(status);
    457  if (U_FAILURE(status)) {
    458    return 0;
    459  }
    460 
    461  UniqueICU4XDate date =
    462      CreateDateFrom(cal, eraName(extendedYear), extendedYear, 1, 1);
    463  if (!date) {
    464    status = U_INTERNAL_PROGRAM_ERROR;
    465    return 0;
    466  }
    467  return icu4x::capi::icu4x_Date_days_in_year_mv1(date.get());
    468 }
    469 
    470 /**
    471 * Return the number of days in a month.
    472 */
    473 int32_t ICU4XCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month,
    474                                            UErrorCode& status) const {
    475  if (U_FAILURE(status)) {
    476    return 0;
    477  }
    478 
    479  // ICU4C supports wrap around. We don't support this case.
    480  if (month < 0 || month > 11) {
    481    status = U_ILLEGAL_ARGUMENT_ERROR;
    482    return 0;
    483  }
    484 
    485  // Use the fallback calendar for years outside the range supported by ICU4X.
    486  if (requiresFallbackForExtendedYear(extendedYear)) {
    487    auto* fallback = getFallbackCalendar(status);
    488    if (U_FAILURE(status)) {
    489      return 0;
    490    }
    491    fallback->clear();
    492    fallback->set(UCAL_EXTENDED_YEAR, extendedYear);
    493    fallback->set(UCAL_MONTH, month);
    494    fallback->set(UCAL_DAY_OF_MONTH, 1);
    495 
    496    return fallback->getActualMaximum(UCAL_DAY_OF_MONTH, status);
    497  }
    498 
    499  auto* cal = getICU4XCalendar(status);
    500  if (U_FAILURE(status)) {
    501    return 0;
    502  }
    503 
    504  bool isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) != 0;
    505  auto monthCode = MonthCode{month + 1, isLeapMonth};
    506  UniqueICU4XDate date = CreateDateFromCodes(cal, eraName(extendedYear),
    507                                             extendedYear, monthCode, 1);
    508  if (!date) {
    509    status = U_INTERNAL_PROGRAM_ERROR;
    510    return 0;
    511  }
    512 
    513  return icu4x::capi::icu4x_Date_days_in_month_mv1(date.get());
    514 }
    515 
    516 /**
    517 * Return the start of the month as a Julian date.
    518 */
    519 int64_t ICU4XCalendar::handleComputeMonthStart(int32_t extendedYear,
    520                                               int32_t month, UBool useMonth,
    521                                               UErrorCode& status) const {
    522  if (U_FAILURE(status)) {
    523    return 0;
    524  }
    525 
    526  // ICU4C supports wrap around. We don't support this case.
    527  if (month < 0 || month > 11) {
    528    status = U_ILLEGAL_ARGUMENT_ERROR;
    529    return 0;
    530  }
    531 
    532  // Use the fallback calendar for years outside the range supported by ICU4X.
    533  if (requiresFallbackForExtendedYear(extendedYear)) {
    534    auto* fallback = getFallbackCalendar(status);
    535    if (U_FAILURE(status)) {
    536      return 0;
    537    }
    538    fallback->clear();
    539    fallback->set(UCAL_EXTENDED_YEAR, extendedYear);
    540    if (useMonth) {
    541      fallback->set(UCAL_MONTH, month);
    542      fallback->set(UCAL_IS_LEAP_MONTH, internalGet(UCAL_IS_LEAP_MONTH));
    543    } else {
    544      fallback->set(UCAL_ORDINAL_MONTH, month);
    545    }
    546    fallback->set(UCAL_DAY_OF_MONTH, 1);
    547 
    548    int32_t newMoon = fallback->get(UCAL_JULIAN_DAY, status);
    549    if (U_FAILURE(status)) {
    550      return 0;
    551    }
    552    return newMoon - 1;
    553  }
    554 
    555  auto* cal = getICU4XCalendar(status);
    556  if (U_FAILURE(status)) {
    557    return 0;
    558  }
    559 
    560  UniqueICU4XDate date{};
    561  if (useMonth) {
    562    bool isLeapMonth = internalGet(UCAL_IS_LEAP_MONTH) != 0;
    563    auto monthCode = MonthCode{month + 1, isLeapMonth};
    564    date = CreateDateFromCodes(cal, eraName(extendedYear), extendedYear,
    565                               monthCode, 1);
    566  } else {
    567    date =
    568        CreateDateFrom(cal, eraName(extendedYear), extendedYear, month + 1, 1);
    569  }
    570  if (!date) {
    571    status = U_INTERNAL_PROGRAM_ERROR;
    572    return 0;
    573  }
    574 
    575  auto isoDate = ToISODate(date.get());
    576  int32_t newMoon = MakeDay(isoDate);
    577 
    578  return (newMoon - 1) + kEpochStartAsJulianDay;
    579 }
    580 
    581 /**
    582 * Default implementation of handleComputeFields when using the fallback
    583 * calendar.
    584 */
    585 void ICU4XCalendar::handleComputeFieldsFromFallback(int32_t julianDay,
    586                                                    UErrorCode& status) {
    587  auto* fallback = getFallbackCalendar(status);
    588  if (U_FAILURE(status)) {
    589    return;
    590  }
    591  fallback->clear();
    592  fallback->set(UCAL_JULIAN_DAY, julianDay);
    593 
    594  internalSet(UCAL_ERA, fallback->get(UCAL_ERA, status));
    595  internalSet(UCAL_YEAR, fallback->get(UCAL_YEAR, status));
    596  internalSet(UCAL_EXTENDED_YEAR, fallback->get(UCAL_EXTENDED_YEAR, status));
    597  internalSet(UCAL_MONTH, fallback->get(UCAL_MONTH, status));
    598  internalSet(UCAL_ORDINAL_MONTH, fallback->get(UCAL_ORDINAL_MONTH, status));
    599  internalSet(UCAL_IS_LEAP_MONTH, fallback->get(UCAL_IS_LEAP_MONTH, status));
    600  internalSet(UCAL_DAY_OF_MONTH, fallback->get(UCAL_DAY_OF_MONTH, status));
    601  internalSet(UCAL_DAY_OF_YEAR, fallback->get(UCAL_DAY_OF_YEAR, status));
    602 }
    603 
    604 }  // namespace mozilla::intl::calendar