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