Calendar.cpp (4917B)
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.h" 6 7 #include "unicode/ucal.h" 8 #include "unicode/uloc.h" 9 #include "unicode/utypes.h" 10 11 namespace mozilla::intl { 12 13 /* static */ 14 Result<UniquePtr<Calendar>, ICUError> Calendar::TryCreate( 15 const char* aLocale, Maybe<Span<const char16_t>> aTimeZoneOverride) { 16 UErrorCode status = U_ZERO_ERROR; 17 const UChar* zoneID = nullptr; 18 int32_t zoneIDLen = 0; 19 if (aTimeZoneOverride) { 20 zoneIDLen = static_cast<int32_t>(aTimeZoneOverride->Length()); 21 zoneID = aTimeZoneOverride->Elements(); 22 } 23 24 UCalendar* calendar = 25 ucal_open(zoneID, zoneIDLen, aLocale, UCAL_DEFAULT, &status); 26 27 if (U_FAILURE(status)) { 28 return Err(ToICUError(status)); 29 } 30 31 return MakeUnique<Calendar>(calendar); 32 } 33 34 Result<Span<const char>, ICUError> Calendar::GetBcp47Type() { 35 UErrorCode status = U_ZERO_ERROR; 36 const char* oldType = ucal_getType(mCalendar, &status); 37 if (U_FAILURE(status)) { 38 return Err(ToICUError(status)); 39 } 40 const char* bcp47Type = uloc_toUnicodeLocaleType("calendar", oldType); 41 42 if (!bcp47Type) { 43 return Err(ICUError::InternalError); 44 } 45 46 return MakeStringSpan(bcp47Type); 47 } 48 49 static Weekday WeekdayFromDaysOfWeek(UCalendarDaysOfWeek weekday) { 50 switch (weekday) { 51 case UCAL_MONDAY: 52 return Weekday::Monday; 53 case UCAL_TUESDAY: 54 return Weekday::Tuesday; 55 case UCAL_WEDNESDAY: 56 return Weekday::Wednesday; 57 case UCAL_THURSDAY: 58 return Weekday::Thursday; 59 case UCAL_FRIDAY: 60 return Weekday::Friday; 61 case UCAL_SATURDAY: 62 return Weekday::Saturday; 63 case UCAL_SUNDAY: 64 return Weekday::Sunday; 65 } 66 MOZ_CRASH("unexpected weekday value"); 67 } 68 69 Result<EnumSet<Weekday>, ICUError> Calendar::GetWeekend() { 70 static_assert(static_cast<int32_t>(UCAL_SUNDAY) == 1); 71 static_assert(static_cast<int32_t>(UCAL_SATURDAY) == 7); 72 73 UErrorCode status = U_ZERO_ERROR; 74 75 EnumSet<Weekday> weekend; 76 for (int32_t i = UCAL_SUNDAY; i <= UCAL_SATURDAY; i++) { 77 auto dayOfWeek = static_cast<UCalendarDaysOfWeek>(i); 78 auto type = ucal_getDayOfWeekType(mCalendar, dayOfWeek, &status); 79 if (U_FAILURE(status)) { 80 return Err(ToICUError(status)); 81 } 82 83 switch (type) { 84 case UCAL_WEEKEND_ONSET: 85 // Treat days which start as a weekday as weekdays. 86 [[fallthrough]]; 87 case UCAL_WEEKDAY: 88 break; 89 90 case UCAL_WEEKEND_CEASE: 91 // Treat days which start as a weekend day as weekend days. 92 [[fallthrough]]; 93 case UCAL_WEEKEND: 94 weekend += WeekdayFromDaysOfWeek(dayOfWeek); 95 break; 96 } 97 } 98 99 return weekend; 100 } 101 102 Weekday Calendar::GetFirstDayOfWeek() { 103 int32_t firstDayOfWeek = ucal_getAttribute(mCalendar, UCAL_FIRST_DAY_OF_WEEK); 104 MOZ_ASSERT(UCAL_SUNDAY <= firstDayOfWeek && firstDayOfWeek <= UCAL_SATURDAY); 105 106 return WeekdayFromDaysOfWeek( 107 static_cast<UCalendarDaysOfWeek>(firstDayOfWeek)); 108 } 109 110 int32_t Calendar::GetMinimalDaysInFirstWeek() { 111 int32_t minimalDays = 112 ucal_getAttribute(mCalendar, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK); 113 MOZ_ASSERT(1 <= minimalDays && minimalDays <= 7); 114 115 return minimalDays; 116 } 117 118 Result<Ok, ICUError> Calendar::SetTimeInMs(double aUnixEpoch) { 119 UErrorCode status = U_ZERO_ERROR; 120 ucal_setMillis(mCalendar, aUnixEpoch, &status); 121 if (U_FAILURE(status)) { 122 return Err(ToICUError(status)); 123 } 124 return Ok{}; 125 } 126 127 /* static */ 128 Result<SpanEnumeration<char>, ICUError> 129 Calendar::GetLegacyKeywordValuesForLocale(const char* aLocale) { 130 UErrorCode status = U_ZERO_ERROR; 131 UEnumeration* enumeration = ucal_getKeywordValuesForLocale( 132 "calendar", aLocale, /* commonlyUsed */ false, &status); 133 134 if (U_SUCCESS(status)) { 135 return SpanEnumeration<char>(enumeration); 136 } 137 138 return Err(ToICUError(status)); 139 } 140 141 /* static */ 142 SpanResult<char> Calendar::LegacyIdentifierToBcp47(const char* aIdentifier, 143 int32_t aLength) { 144 if (aIdentifier == nullptr) { 145 return Err(InternalError{}); 146 } 147 // aLength is not needed here, as the ICU call uses the null terminated 148 // string. 149 return MakeStringSpan(uloc_toUnicodeLocaleType("ca", aIdentifier)); 150 } 151 152 /* static */ 153 Result<Calendar::Bcp47IdentifierEnumeration, ICUError> 154 Calendar::GetBcp47KeywordValuesForLocale(const char* aLocale, 155 CommonlyUsed aCommonlyUsed) { 156 UErrorCode status = U_ZERO_ERROR; 157 UEnumeration* enumeration = ucal_getKeywordValuesForLocale( 158 "calendar", aLocale, static_cast<bool>(aCommonlyUsed), &status); 159 160 if (U_SUCCESS(status)) { 161 return Bcp47IdentifierEnumeration(enumeration); 162 } 163 164 return Err(ToICUError(status)); 165 } 166 167 Calendar::~Calendar() { 168 MOZ_ASSERT(mCalendar); 169 ucal_close(mCalendar); 170 } 171 172 } // namespace mozilla::intl