ICU4XCalendar.h (5084B)
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 #ifndef intl_components_calendar_ICU4XCalendar_h_ 5 #define intl_components_calendar_ICU4XCalendar_h_ 6 7 #include "mozilla/intl/calendar/ICU4XUniquePtr.h" 8 #include "mozilla/intl/calendar/ISODate.h" 9 #include "mozilla/intl/calendar/MonthCode.h" 10 11 #include <memory> 12 #include <mutex> 13 #include <stdint.h> 14 #include <string_view> 15 16 #include "unicode/calendar.h" 17 #include "unicode/locid.h" 18 #include "unicode/timezone.h" 19 #include "unicode/utypes.h" 20 21 #include "icu4x/CalendarKind.hpp" 22 23 namespace mozilla::intl::calendar { 24 25 /** 26 * Abstract class to implement icu::Calendar using ICU4X. 27 */ 28 class ICU4XCalendar : public icu::Calendar { 29 mutable UniqueICU4XCalendar calendar_{}; 30 mutable std::unique_ptr<icu::Calendar> fallback_{}; 31 icu4x::capi::CalendarKind kind_; 32 33 protected: 34 ICU4XCalendar(icu4x::capi::CalendarKind kind, const icu::Locale& locale, 35 UErrorCode& success); 36 ICU4XCalendar(icu4x::capi::CalendarKind kind, const icu::TimeZone& timeZone, 37 const icu::Locale& locale, UErrorCode& success); 38 ICU4XCalendar(const ICU4XCalendar& other); 39 40 /** 41 * Get or create the underlying ICU4X calendar. 42 */ 43 icu4x::capi::Calendar* getICU4XCalendar(UErrorCode& status) const; 44 45 /** 46 * Get or create the ICU4C fallback calendar implementation. 47 */ 48 icu::Calendar* getFallbackCalendar(UErrorCode& status) const; 49 50 protected: 51 /** 52 * Return the ICU4X era name for the given extended year. 53 */ 54 virtual std::string_view eraName(int32_t extendedYear) const = 0; 55 56 /** 57 * Return true if this calendar contains any leap months. 58 */ 59 virtual bool hasLeapMonths() const = 0; 60 61 /** 62 * Return true if this calendar contains the requested month code. 63 */ 64 virtual bool hasMonthCode(MonthCode monthCode) const = 0; 65 66 /** 67 * Subclasses can request to use the ICU4C fallback calendar. 68 * 69 * Can be removed when <https://github.com/unicode-org/icu4x/issues/4917> is 70 * fixed. 71 */ 72 virtual bool requiresFallbackForExtendedYear(int32_t year) const = 0; 73 virtual bool requiresFallbackForGregorianYear(int32_t year) const = 0; 74 75 protected: 76 static constexpr int32_t kEpochStartAsJulianDay = 77 2440588; // January 1, 1970 (Gregorian) 78 79 /** 80 * Return the month code of |date|. 81 */ 82 static MonthCode monthCodeFrom(const icu4x::capi::Date* date); 83 84 /** 85 * Create a new ICU4X date object from an ISO date. 86 */ 87 UniqueICU4XDate createICU4XDate(const ISODate& date, 88 UErrorCode& status) const; 89 90 public: 91 ICU4XCalendar() = delete; 92 virtual ~ICU4XCalendar(); 93 94 const char* getTemporalMonthCode(UErrorCode& status) const override; 95 void setTemporalMonthCode(const char* code, UErrorCode& status) override; 96 97 void add(UCalendarDateFields field, int32_t amount, 98 UErrorCode& status) override; 99 void add(EDateFields field, int32_t amount, UErrorCode& status) override; 100 void roll(UCalendarDateFields field, int32_t amount, 101 UErrorCode& status) override; 102 void roll(EDateFields field, int32_t amount, UErrorCode& status) override; 103 104 protected: 105 int32_t internalGetMonth(int32_t defaultValue, 106 UErrorCode& status) const override; 107 int32_t internalGetMonth(UErrorCode& status) const override; 108 109 int64_t handleComputeMonthStart(int32_t extendedYear, int32_t month, 110 UBool useMonth, 111 UErrorCode& status) const override; 112 int32_t handleGetMonthLength(int32_t extendedYear, int32_t month, 113 UErrorCode& status) const override; 114 int32_t handleGetYearLength(int32_t extendedYear, 115 UErrorCode& status) const override; 116 117 int32_t handleGetExtendedYear(UErrorCode& status) override; 118 119 protected: 120 /** 121 * handleComputeFields implementation using the ICU4C fallback calendar. 122 */ 123 void handleComputeFieldsFromFallback(int32_t julianDay, UErrorCode& status); 124 }; 125 126 /** 127 * `IMPL_SYSTEM_DEFAULT_CENTURY` is internal to "i18n/gregoimp.h", so we have 128 * to provider our own helper class to implement default centuries. 129 */ 130 template <class Calendar, class Locale> 131 class SystemDefaultCentury { 132 mutable UDate start_ = DBL_MIN; 133 mutable int32_t startYear_ = -1; 134 mutable std::once_flag init_{}; 135 136 void initialize() const { 137 UErrorCode status = U_ZERO_ERROR; 138 Calendar calendar(Locale::identifier, status); 139 if (U_FAILURE(status)) { 140 return; 141 } 142 calendar.setTime(icu::Calendar::getNow(), status); 143 calendar.add(UCAL_EXTENDED_YEAR, -80, status); 144 start_ = calendar.getTime(status); 145 startYear_ = calendar.get(UCAL_YEAR, status); 146 } 147 148 public: 149 UDate start() const { 150 std::call_once(init_, [this] { initialize(); }); 151 return start_; 152 } 153 int32_t startYear() const { 154 std::call_once(init_, [this] { initialize(); }); 155 return startYear_; 156 } 157 }; 158 159 } // namespace mozilla::intl::calendar 160 161 #endif