/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ECMASCRIPT_JS_DATE_TIME_FORMAT_H #define ECMASCRIPT_JS_DATE_TIME_FORMAT_H #include "ecmascript/js_locale.h" namespace panda::ecmascript { enum class CalendarOption : uint8_t { UNDEFINED = 0x01 }; enum class DateTimeStyleOption : uint8_t { FULL = 0x01, LONG, MEDIUM, SHORT, UNDEFINED, EXCEPTION }; enum class DefaultsOption : uint8_t { DATE = 0x01, TIME, ALL }; enum class HourCycleOption : uint8_t { H11 = 0x01, H12, H23, H24, UNDEFINED, EXCEPTION }; enum class RequiredOption : uint8_t { DATE = 0x01, TIME, ANY }; enum class Value : uint8_t { SHARED, START_RANGE, END_RANGE }; enum class IcuCacheType : uint8_t {NOT_CACHE, DEFAULT, DATE, TIME}; constexpr int CAPACITY_3 = 3; constexpr int CAPACITY_4 = 4; constexpr int CAPACITY_5 = 5; constexpr int CAPACITY_8 = 8; constexpr int STRING_LENGTH_2 = 2; constexpr int STRING_LENGTH_3 = 3; constexpr int STRING_LENGTH_7 = 7; constexpr int STRING_LENGTH_8 = 8; constexpr int STRING_LENGTH_9 = 9; constexpr int STRING_LENGTH_10 = 10; class IcuPatternDesc; std::vector BuildIcuPatternDescs(); std::vector InitializePattern(const IcuPatternDesc &hourData); using IcuPatternDescVect = std::vector; using IcuPatternEntry = std::pair; class IcuPatternDesc { public: IcuPatternDesc(std::string property, const std::vector &pairs, std::vector allowedValues) : property(std::move(property)), pairs(std::move(pairs)), allowedValues(std::move(allowedValues)) { for (const auto &pair : pairs) { map.emplace(pair.second, pair.first); } } virtual ~IcuPatternDesc() = default; std::string property; // NOLINT(misc-non-private-member-variables-in-classes) std::vector pairs; // NOLINT(misc-non-private-member-variables-in-classes) std::map map; // NOLINT(misc-non-private-member-variables-in-classes) std::vector allowedValues; // NOLINT(misc-non-private-member-variables-in-classes) DEFAULT_COPY_SEMANTIC(IcuPatternDesc); // NOLINT(performance-noexcept-move-constructor, hicpp-noexcept-move) DEFAULT_NOEXCEPT_MOVE_SEMANTIC(IcuPatternDesc); }; class Pattern { public: Pattern(const std::string &data1, const std::string &data2) : data(InitializePattern( IcuPatternDesc("hour", {{data1, "2-digit"}, {data2, "numeric"}}, {"2-digit", "numeric"}))) {} virtual ~Pattern() = default; std::vector Get() const { return data; } private: std::vector data{}; NO_COPY_SEMANTIC(Pattern); NO_MOVE_SEMANTIC(Pattern); }; class JSDateTimeFormat : public JSObject { public: CAST_CHECK(JSDateTimeFormat, IsJSDateTimeFormat); static constexpr size_t LOCALE_OFFSET = JSObject::SIZE; ACCESSORS(Locale, LOCALE_OFFSET, CALENDAR_OFFSET) ACCESSORS(Calendar, CALENDAR_OFFSET, NUMBER_STRING_SYSTEM_OFFSET) ACCESSORS(NumberingSystem, NUMBER_STRING_SYSTEM_OFFSET, TIME_ZONE_OFFSET) ACCESSORS(TimeZone, TIME_ZONE_OFFSET, LOCALE_ICU_OFFSET) ACCESSORS(LocaleIcu, LOCALE_ICU_OFFSET, SIMPLE_DATE_TIME_FORMAT_ICU_OFFSET) ACCESSORS(SimpleDateTimeFormatIcu, SIMPLE_DATE_TIME_FORMAT_ICU_OFFSET, ISO8601_OFFSET) ACCESSORS(Iso8601, ISO8601_OFFSET, BOUND_FORMAT_OFFSET) ACCESSORS(BoundFormat, BOUND_FORMAT_OFFSET, BIT_FIELD_OFFSET) ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) DEFINE_ALIGN_SIZE(LAST_OFFSET); // define BitField static constexpr size_t HONOR_CYCLE_BITS = 3; static constexpr size_t DATE_STYLE_BITS = 3; static constexpr size_t TIME_STYLE_BITS = 3; FIRST_BIT_FIELD(BitField, HourCycle, HourCycleOption, HONOR_CYCLE_BITS) NEXT_BIT_FIELD(BitField, DateStyle, DateTimeStyleOption, DATE_STYLE_BITS, HourCycle) NEXT_BIT_FIELD(BitField, TimeStyle, DateTimeStyleOption, TIME_STYLE_BITS, DateStyle) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, LOCALE_OFFSET, BIT_FIELD_OFFSET) DECL_DUMP() icu::Locale *GetIcuLocale() const; static void SetIcuLocale(JSThread *thread, JSHandle obj, const icu::Locale &icuLocale, const DeleteEntryPoint &callback); static void FreeIcuLocale(void *pointer, void *data); icu::SimpleDateFormat *GetIcuSimpleDateFormat() const; static void SetIcuSimpleDateFormat(JSThread *thread, JSHandle obj, const icu::SimpleDateFormat &icuSimpleDateTimeFormat, const DeleteEntryPoint &callback); static void FreeSimpleDateFormat(void *pointer, void *data); static icu::SimpleDateFormat *GetCachedIcuSimpleDateFormat(JSThread *thread, const JSHandle &locales, IcuFormatterType type); // 13.1.1 InitializeDateTimeFormat (dateTimeFormat, locales, options) static JSHandle InitializeDateTimeFormat(JSThread *thread, const JSHandle &dateTimeFormat, const JSHandle &locales, const JSHandle &options, IcuCacheType type = IcuCacheType::NOT_CACHE); // 13.1.2 ToDateTimeOptions (options, required, defaults) static JSHandle ToDateTimeOptions(JSThread *thread, const JSHandle &options, const RequiredOption &required, const DefaultsOption &defaults); // 13.1.7 FormatDateTime(dateTimeFormat, x) static JSHandle FormatDateTime(JSThread *thread, const JSHandle &dateTimeFormat, double x); static JSHandle FormatDateTime(JSThread *thread, const icu::SimpleDateFormat *simpleDateFormat, double x); // 13.1.8 FormatDateTimeToParts (dateTimeFormat, x) static JSHandle FormatDateTimeToParts(JSThread *thread, const JSHandle &dateTimeFormat, double x); // 13.1.10 UnwrapDateTimeFormat(dtf) static JSHandle UnwrapDateTimeFormat(JSThread *thread, const JSHandle &dateTimeFormat); static JSHandle GainAvailableLocales(JSThread *thread); static void ResolvedOptions(JSThread *thread, const JSHandle &dateTimeFormat, const JSHandle &options); static JSHandle NormDateTimeRange(JSThread *thread, const JSHandle &dtf, double x, double y); static JSHandle NormDateTimeRangeToParts(JSThread *thread, const JSHandle &dtf, double x, double y); private: static HourCycleOption OptionToHourCycle(const std::string &hc); // 2: number of elements static Value TrackValue(int32_t beginning, int32_t ending, std::array begin, std::array end); // 2: number of elements static HourCycleOption OptionToHourCycle(UDateFormatHourCycle hc); static std::string ToHourCycleString(HourCycleOption hc); static std::unique_ptr ConstructTimeZone(const std::string &timezone); static std::string ConstructFormattedTimeZoneID(const std::string &input); static std::string ToTitleCaseTimezonePosition(const std::string &input); static std::unique_ptr ConstructDateIntervalFormat(const JSHandle &dtf); static std::string ConstructGMTTimeZoneID(const std::string &input); static std::unique_ptr BuildCalendar(const icu::Locale &locale, const icu::TimeZone &timeZone); static std::map GetSpecialTimeZoneMap(); static JSHandle ConstructFDateIntervalToJSArray(JSThread *thread, const icu::FormattedDateInterval &formatted); static std::vector GetIcuPatternDesc(const HourCycleOption &hourCycle); static std::unique_ptr CreateICUSimpleDateFormat(const icu::Locale &icuLocale, const icu::UnicodeString &skeleton, icu::DateTimePatternGenerator *generator, HourCycleOption hc); static JSHandle ConvertFieldIdToDateType(JSThread *thread, int32_t fieldId); static icu::UnicodeString ChangeHourCyclePattern(const icu::UnicodeString &pattern, HourCycleOption hc); static std::string ToTitleCaseFunction(const std::string &input); static bool IsValidTimeZoneInput(const std::string &input); static JSHandle ToValueString(JSThread *thread, Value value); static icu::FormattedDateInterval ConstructDTFRange(JSThread *thread, const JSHandle &dtf, double x, double y); }; } // namespace panda::ecmascript #endif // ECMASCRIPT_JS_DATE_TIME_FORMAT_H