1 /* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ECMASCRIPT_JS_DATE_TIME_FORMAT_H 17 #define ECMASCRIPT_JS_DATE_TIME_FORMAT_H 18 19 #include "ecmascript/ecma_context.h" 20 #include "ecmascript/js_locale.h" 21 22 namespace panda::ecmascript { 23 enum class CalendarOption : uint8_t { UNDEFINED = 0x01 }; 24 enum class DateTimeStyleOption : uint8_t { FULL = 0x01, LONG, MEDIUM, SHORT, UNDEFINED, EXCEPTION }; 25 enum class DefaultsOption : uint8_t { DATE = 0x01, TIME, ALL }; 26 enum class HourCycleOption : uint8_t { H11 = 0x01, H12, H23, H24, UNDEFINED, EXCEPTION }; 27 enum class RequiredOption : uint8_t { DATE = 0x01, TIME, ANY }; 28 enum class Value : uint8_t { SHARED, START_RANGE, END_RANGE }; 29 enum class IcuCacheType : uint8_t {NOT_CACHE, DEFAULT, DATE, TIME}; 30 31 constexpr int CAPACITY_3 = 3; 32 constexpr int CAPACITY_4 = 4; 33 constexpr int CAPACITY_5 = 5; 34 constexpr int CAPACITY_8 = 8; 35 constexpr int STRING_LENGTH_2 = 2; 36 constexpr int STRING_LENGTH_3 = 3; 37 constexpr int STRING_LENGTH_7 = 7; 38 constexpr int STRING_LENGTH_8 = 8; 39 constexpr int STRING_LENGTH_9 = 9; 40 constexpr int STRING_LENGTH_10 = 10; 41 42 class IcuPatternDesc; 43 44 std::vector<IcuPatternDesc> BuildIcuPatternDescs(); 45 std::vector<IcuPatternDesc> InitializePattern(const IcuPatternDesc &hourData); 46 icu::DateFormat::EStyle DateTimeStyleToEStyle(DateTimeStyleOption style); 47 HourCycleOption HourCycleFromPattern(const icu::UnicodeString pattern); 48 icu::UnicodeString ReplaceSkeleton(const icu::UnicodeString input, HourCycleOption hc); 49 std::unique_ptr<icu::SimpleDateFormat> DateTimeStylePattern(DateTimeStyleOption dateStyle, 50 DateTimeStyleOption timeStyle, 51 icu::Locale &icuLocale, 52 HourCycleOption hc, 53 icu::DateTimePatternGenerator *generator); 54 55 using IcuPatternDescVect = std::vector<IcuPatternDesc>; 56 using IcuPatternEntry = std::pair<std::string, std::string>; 57 58 class IcuPatternDesc { 59 public: IcuPatternDesc(std::string property, const std::vector<IcuPatternEntry> &pairs, std::vector<std::string> allowedValues)60 IcuPatternDesc(std::string property, const std::vector<IcuPatternEntry> &pairs, 61 std::vector<std::string> allowedValues) : property(std::move(property)), pairs(std::move(pairs)), 62 allowedValues(std::move(allowedValues)) 63 { 64 for (const auto &pair : pairs) { 65 map.emplace(pair.second, pair.first); 66 } 67 } 68 69 virtual ~IcuPatternDesc() = default; 70 71 std::string property; // NOLINT(misc-non-private-member-variables-in-classes) 72 std::vector<IcuPatternEntry> pairs; // NOLINT(misc-non-private-member-variables-in-classes) 73 std::map<const std::string, const std::string> map; // NOLINT(misc-non-private-member-variables-in-classes) 74 std::vector<std::string> allowedValues; // NOLINT(misc-non-private-member-variables-in-classes) 75 76 DEFAULT_COPY_SEMANTIC(IcuPatternDesc); 77 // NOLINT(performance-noexcept-move-constructor, hicpp-noexcept-move) 78 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(IcuPatternDesc); 79 }; 80 81 class Pattern { 82 public: Pattern(const std::string &data1, const std::string &data2)83 Pattern(const std::string &data1, const std::string &data2) : data(InitializePattern( 84 IcuPatternDesc("hour", {{data1, "2-digit"}, {data2, "numeric"}}, {"2-digit", "numeric"}))) {} 85 virtual ~Pattern() = default; Get() const86 std::vector<IcuPatternDesc> Get() const 87 { 88 return data; 89 } 90 91 private: 92 std::vector<IcuPatternDesc> data{}; 93 NO_COPY_SEMANTIC(Pattern); 94 NO_MOVE_SEMANTIC(Pattern); 95 }; 96 97 class JSDateTimeFormat : public JSObject { 98 public: 99 CAST_CHECK(JSDateTimeFormat, IsJSDateTimeFormat); 100 101 static constexpr size_t LOCALE_OFFSET = JSObject::SIZE; 102 ACCESSORS(Locale, LOCALE_OFFSET, CALENDAR_OFFSET) 103 ACCESSORS(Calendar, CALENDAR_OFFSET, NUMBER_STRING_SYSTEM_OFFSET) 104 ACCESSORS(NumberingSystem, NUMBER_STRING_SYSTEM_OFFSET, TIME_ZONE_OFFSET) 105 ACCESSORS(TimeZone, TIME_ZONE_OFFSET, LOCALE_ICU_OFFSET) 106 ACCESSORS(LocaleIcu, LOCALE_ICU_OFFSET, SIMPLE_DATE_TIME_FORMAT_ICU_OFFSET) 107 ACCESSORS(SimpleDateTimeFormatIcu, SIMPLE_DATE_TIME_FORMAT_ICU_OFFSET, ISO8601_OFFSET) 108 ACCESSORS(Iso8601, ISO8601_OFFSET, BOUND_FORMAT_OFFSET) 109 ACCESSORS(BoundFormat, BOUND_FORMAT_OFFSET, BIT_FIELD_OFFSET) 110 ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) 111 DEFINE_ALIGN_SIZE(LAST_OFFSET); 112 113 // define BitField 114 static constexpr size_t HONOR_CYCLE_BITS = 3; 115 static constexpr size_t DATE_STYLE_BITS = 3; 116 static constexpr size_t TIME_STYLE_BITS = 3; 117 FIRST_BIT_FIELD(BitField, HourCycle, HourCycleOption, HONOR_CYCLE_BITS) 118 NEXT_BIT_FIELD(BitField, DateStyle, DateTimeStyleOption, DATE_STYLE_BITS, HourCycle) 119 NEXT_BIT_FIELD(BitField, TimeStyle, DateTimeStyleOption, TIME_STYLE_BITS, DateStyle) 120 121 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, LOCALE_OFFSET, BIT_FIELD_OFFSET) 122 DECL_DUMP() 123 124 icu::Locale *GetIcuLocale() const; 125 static void SetIcuLocale(JSThread *thread, JSHandle<JSDateTimeFormat> obj, 126 const icu::Locale &icuLocale, const NativePointerCallback &callback); 127 static void FreeIcuLocale(void *env, void *pointer, void *data); 128 129 icu::SimpleDateFormat *GetIcuSimpleDateFormat() const; 130 static void SetIcuSimpleDateFormat(JSThread *thread, JSHandle<JSDateTimeFormat> obj, 131 const icu::SimpleDateFormat &icuSimpleDateTimeFormat, const NativePointerCallback &callback); 132 static void FreeSimpleDateFormat(void *env, void *pointer, void *data); 133 static icu::SimpleDateFormat *GetCachedIcuSimpleDateFormat(JSThread *thread, 134 const JSHandle<JSTaggedValue> &locales, 135 IcuFormatterType type); 136 137 // 13.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) 138 static JSHandle<JSDateTimeFormat> InitializeDateTimeFormat(JSThread *thread, 139 const JSHandle<JSDateTimeFormat> &dateTimeFormat, 140 const JSHandle<JSTaggedValue> &locales, 141 const JSHandle<JSTaggedValue> &options, 142 IcuCacheType type = IcuCacheType::NOT_CACHE); 143 144 // 13.1.2 ToDateTimeOptions (options, required, defaults) 145 static JSHandle<JSObject> ToDateTimeOptions(JSThread *thread, const JSHandle<JSTaggedValue> &options, 146 const RequiredOption &required, const DefaultsOption &defaults); 147 148 static void ToDateTimeSkeleton(JSThread *thread, const std::vector<std::string> &options, 149 std::string &skeleton, HourCycleOption hc, 150 const RequiredOption &required, const DefaultsOption &defaults); 151 152 // 13.1.7 FormatDateTime(dateTimeFormat, x) 153 static JSHandle<EcmaString> FormatDateTime(JSThread *thread, const JSHandle<JSDateTimeFormat> &dateTimeFormat, 154 double x); 155 static JSHandle<EcmaString> FormatDateTime(JSThread *thread, const icu::SimpleDateFormat *simpleDateFormat, 156 double x); 157 158 // 13.1.8 FormatDateTimeToParts (dateTimeFormat, x) 159 static JSHandle<JSArray> FormatDateTimeToParts(JSThread *thread, const JSHandle<JSDateTimeFormat> &dateTimeFormat, 160 double x); 161 162 // 13.1.10 UnwrapDateTimeFormat(dtf) 163 static JSHandle<JSTaggedValue> UnwrapDateTimeFormat(JSThread *thread, 164 const JSHandle<JSTaggedValue> &dateTimeFormat); 165 166 static JSHandle<TaggedArray> GainAvailableLocales(JSThread *thread); 167 168 static void ResolvedOptions(JSThread *thread, const JSHandle<JSDateTimeFormat> &dateTimeFormat, 169 const JSHandle<JSObject> &options); 170 171 static JSHandle<EcmaString> NormDateTimeRange(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf, double x, 172 double y); 173 174 static JSHandle<JSArray> NormDateTimeRangeToParts(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf, 175 double x, double y); 176 177 private: 178 static HourCycleOption OptionToHourCycle(const std::string &hc); 179 // 2: number of elements 180 static Value TrackValue(int32_t beginning, int32_t ending, std::array<int32_t, 2> begin, 181 std::array<int32_t, 2> end); // 2: number of elements 182 183 static HourCycleOption OptionToHourCycle(UDateFormatHourCycle hc); 184 185 static std::string ToHourCycleString(HourCycleOption hc); 186 187 static std::unique_ptr<icu::TimeZone> ConstructTimeZone(const std::string &timezone); 188 189 static std::string ConstructFormattedTimeZoneID(const std::string &input); 190 191 static std::string ToTitleCaseTimezonePosition(const std::string &input); 192 193 static std::unique_ptr<icu::DateIntervalFormat> ConstructDateIntervalFormat(const JSHandle<JSDateTimeFormat> &dtf); 194 195 static std::string ConstructGMTTimeZoneID(const std::string &input); 196 197 static std::unique_ptr<icu::Calendar> BuildCalendar(const icu::Locale &locale, const icu::TimeZone &timeZone); 198 199 static std::map<std::string, std::string> GetSpecialTimeZoneMap(); 200 201 static JSHandle<JSArray> ConstructFDateIntervalToJSArray(JSThread *thread, 202 const icu::FormattedDateInterval &formatted); 203 204 static std::vector<IcuPatternDesc> GetIcuPatternDesc(const HourCycleOption &hourCycle); 205 206 static std::unique_ptr<icu::SimpleDateFormat> CreateICUSimpleDateFormat(const icu::Locale &icuLocale, 207 const icu::UnicodeString &skeleton, 208 icu::DateTimePatternGenerator *generator, 209 HourCycleOption hc); 210 211 static JSHandle<JSTaggedValue> ConvertFieldIdToDateType(JSThread *thread, int32_t fieldId); 212 213 static icu::UnicodeString ChangeHourCyclePattern(const icu::UnicodeString &pattern, HourCycleOption hc); 214 215 static std::string ToTitleCaseFunction(const std::string &input); 216 217 static bool IsValidTimeZoneInput(const std::string &input); 218 219 static JSHandle<EcmaString> ToValueString(JSThread *thread, Value value); 220 221 static icu::FormattedDateInterval ConstructDTFRange(JSThread *thread, const JSHandle<JSDateTimeFormat> &dtf, 222 double x, double y); 223 }; 224 } // namespace panda::ecmascript 225 #endif // ECMASCRIPT_JS_DATE_TIME_FORMAT_H 226