24#include "unicode/calendar.h"
25#include "unicode/dtitvfmt.h"
26#include "unicode/dtptngen.h"
27#include "unicode/fieldpos.h"
28#include "unicode/gregocal.h"
29#include "unicode/smpdtfmt.h"
30#include "unicode/unistr.h"
32#ifndef V8_INTL_SUPPORT
33#error Internationalization is expected to be enabled.
67 case UDAT_HOUR_CYCLE_11:
69 case UDAT_HOUR_CYCLE_12:
71 case UDAT_HOUR_CYCLE_23:
73 case UDAT_HOUR_CYCLE_24:
91 return defaultHourCycle;
93 if (std::strcmp(locale.getCountry(),
"JP") == 0) {
103 return defaultHourCycle;
108Maybe<JSDateTimeFormat::HourCycle> GetHourCycle(
109 Isolate* isolate, DirectHandle<JSReceiver> options,
110 const char* method_name) {
112 isolate, options,
"hourCycle", method_name, {
"h11",
"h12",
"h23",
"h24"},
120 PatternMap(std::string pattern, std::string value)
122 virtual ~PatternMap() =
default;
127#define BIT_FIELDS(V, _) \
129 V(Year, bool, 1, _) \
130 V(Month, bool, 1, _) \
131 V(Weekday, bool, 1, _) \
133 V(DayPeriod, bool, 1, _) \
134 V(Hour, bool, 1, _) \
135 V(Minute, bool, 1, _) \
136 V(Second, bool, 1, _) \
137 V(TimeZoneName, bool, 1, _) \
138 V(FractionalSecondDigits, bool, 1, _)
144 PatternItem(int32_t shift,
const std::string property,
145 std::vector<PatternMap>
pairs,
148 property(std::move(property)),
151 virtual ~PatternItem() =
default;
154 const std::string property;
161static std::vector<PatternItem> BuildPatternItems() {
162 const std::vector<const char*> kLongShort = {
"long",
"short"};
163 const std::vector<const char*> kNarrowLongShort = {
"narrow",
"long",
"short"};
164 const std::vector<const char*> k2DigitNumeric = {
"2-digit",
"numeric"};
165 const std::vector<const char*> kNarrowLongShort2DigitNumeric = {
166 "narrow",
"long",
"short",
"2-digit",
"numeric"};
167 std::vector<PatternItem> items = {
168 PatternItem(Weekday::kShift,
"weekday",
169 {{
"EEEEE",
"narrow"},
176 PatternItem(Era::kShift,
"era",
177 {{
"GGGGG",
"narrow"}, {
"GGGG",
"long"}, {
"GGG",
"short"}},
179 PatternItem(Year::kShift,
"year", {{
"yy",
"2-digit"}, {
"y",
"numeric"}},
182 items.push_back(PatternItem(Month::kShift,
"month",
183 {{
"MMMMM",
"narrow"},
193 kNarrowLongShort2DigitNumeric));
194 items.push_back(PatternItem(Day::kShift,
"day",
195 {{
"dd",
"2-digit"}, {
"d",
"numeric"}},
197 items.push_back(PatternItem(DayPeriod::kShift,
"dayPeriod",
198 {{
"BBBBB",
"narrow"},
205 items.push_back(PatternItem(Hour::kShift,
"hour",
215 items.push_back(PatternItem(Minute::kShift,
"minute",
216 {{
"mm",
"2-digit"}, {
"m",
"numeric"}},
218 items.push_back(PatternItem(Second::kShift,
"second",
219 {{
"ss",
"2-digit"}, {
"s",
"numeric"}},
222 const std::vector<const char*> kTimezone = {
"long",
"short",
223 "longOffset",
"shortOffset",
224 "longGeneric",
"shortGeneric"};
225 items.push_back(PatternItem(TimeZoneName::kShift,
"timeZoneName",
228 {
"OOOO",
"longOffset"},
229 {
"O",
"shortOffset"},
230 {
"vvvv",
"longGeneric"},
231 {
"v",
"shortGeneric"}},
238 PatternItems() : data(BuildPatternItems()) {}
239 virtual ~PatternItems() =
default;
240 const std::vector<PatternItem>&
Get()
const {
return data; }
243 const std::vector<PatternItem> data;
246static const std::vector<PatternItem>& GetPatternItems() {
249 return items.Pointer()->Get();
254 PatternData(int32_t shift,
const std::string property,
255 std::vector<PatternMap>
pairs,
256 std::vector<const char*> allowed_values)
258 property(
std::move(property)),
260 for (
const auto& pair :
pairs) {
261 map.insert(std::make_pair(pair.value, pair.pattern));
264 virtual ~PatternData() =
default;
267 const std::string property;
268 std::map<const std::string, const std::string> map;
272const std::vector<PatternData> CreateCommonData(
const PatternData& hour_data) {
273 std::vector<PatternData> build;
274 for (
const PatternItem& item : GetPatternItems()) {
275 if (item.property ==
"hour") {
276 build.push_back(hour_data);
278 build.push_back(PatternData(item.bitShift, item.property, item.pairs,
279 item.allowed_values));
285const std::vector<PatternData> CreateData(
const char* digit2,
286 const char* numeric) {
287 return CreateCommonData(PatternData(
288 Hour::kShift,
"hour", {{digit2,
"2-digit"}, {numeric,
"numeric"}},
289 {
"2-digit",
"numeric"}));
306 Pattern(
const char* d1,
const char* d2) : data(CreateData(d1, d2)) {}
307 virtual ~Pattern() =
default;
308 virtual const std::vector<PatternData>&
Get()
const {
return data; }
311 std::vector<PatternData> data;
314#define DEFFINE_TRAIT(name, d1, d2) \
316 static void Construct(void* allocated_ptr) { \
317 new (allocated_ptr) Pattern(d1, d2); \
327const std::vector<PatternData>& GetPatternData(
329 switch (hour_cycle) {
333 return h11.Pointer()->Get();
338 return h12.Pointer()->Get();
343 return h23.Pointer()->Get();
348 return h24.Pointer()->Get();
353 return hDefault.Pointer()->Get();
360std::string GetGMTTzID(
const std::string& input) {
361 std::string ret =
"Etc/GMT";
362 switch (input.length()) {
364 if (input[7] ==
'0')
return ret +
'0';
367 if ((input[7] ==
'+' || input[7] ==
'-') &&
369 return ret + input[7] + input[8];
373 if ((input[7] ==
'+' || input[7] ==
'-') && (input[8] ==
'1') &&
375 return ret + input[7] + input[8] + input[9];
384bool IsAsciiAlpha(
char ch) {
390char LocaleIndependentAsciiToUpper(
char ch) {
395char LocaleIndependentAsciiToLower(
char ch) {
404std::string ToTitleCaseTimezoneLocation(
const std::string& input) {
405 std::string title_cased;
407 for (
char ch : input) {
409 if (IsAsciiAlpha(ch)) {
410 title_cased += word_length == 0 ? LocaleIndependentAsciiToUpper(ch)
411 : LocaleIndependentAsciiToLower(ch);
413 }
else if (ch ==
'_' || ch ==
'-' || ch ==
'/') {
415 if (word_length == 2) {
416 size_t pos = title_cased.length() - 2;
417 std::string substr = title_cased.substr(
pos, 2);
418 if (substr ==
"Of" || substr ==
"Es" || substr ==
"Au") {
419 title_cased[
pos] = LocaleIndependentAsciiToLower(title_cased[
pos]);
426 return std::string();
433class SpecialTimeZoneMap {
435 SpecialTimeZoneMap() {
436 Add(
"America/Argentina/ComodRivadavia");
437 Add(
"America/Knox_IN");
438 Add(
"Antarctica/DumontDUrville");
439 Add(
"Antarctica/McMurdo");
440 Add(
"Australia/ACT");
441 Add(
"Australia/LHI");
442 Add(
"Australia/NSW");
443 Add(
"Brazil/DeNoronha");
444 Add(
"Chile/EasterIsland");
447 Add(
"Mexico/BajaNorte");
448 Add(
"Mexico/BajaSur");
454 std::string Find(
const std::string&
id) {
455 auto it =
map_.find(
id);
456 if (it !=
map_.end()) {
463 void Add(
const char*
id) {
464 std::string upper(
id);
465 transform(upper.begin(), upper.end(), upper.begin(),
466 LocaleIndependentAsciiToUpper);
467 map_.insert({upper,
id});
469 std::map<std::string, std::string>
map_;
477 std::string upper = input;
478 transform(upper.begin(), upper.end(), upper.begin(),
479 LocaleIndependentAsciiToUpper);
480 if (upper.length() == 3) {
481 if (upper ==
"GMT")
return "UTC";
484 }
else if (upper.length() == 7 &&
'0' <= upper[3] && upper[3] <=
'9') {
487 }
else if (upper.length() > 3) {
488 if (memcmp(upper.c_str(),
"ETC", 3) == 0) {
489 if (upper ==
"ETC/UTC" || upper ==
"ETC/GMT" || upper ==
"ETC/UCT") {
492 if (strncmp(upper.c_str(),
"ETC/GMT", 7) == 0) {
493 return GetGMTTzID(input);
495 }
else if (memcmp(upper.c_str(),
"GMT", 3) == 0) {
496 if (upper ==
"GMT0" || upper ==
"GMT+0" || upper ==
"GMT-0") {
499 }
else if (memcmp(upper.c_str(),
"US/", 3) == 0) {
500 std::string title = ToTitleCaseTimezoneLocation(input);
501 if (title.length() >= 2) {
506 }
else if (strncmp(upper.c_str(),
"SYSTEMV/", 8) == 0) {
507 upper.replace(0, 8,
"SystemV/");
516 std::string special_case = special_time_zone_map.Pointer()->Find(upper);
517 if (!special_case.empty()) {
520 return ToTitleCaseTimezoneLocation(input);
528 return isolate->factory()->full_string();
530 return isolate->factory()->long_string();
532 return isolate->factory()->medium_string();
534 return isolate->factory()->short_string();
541int FractionalSecondDigitsFromPattern(
const std::string&
pattern) {
553 Isolate* isolate,
const icu::UnicodeString&
id) {
560 if (
id == UNICODE_STRING_SIMPLE(
"Etc/UTC") ||
561 id == UNICODE_STRING_SIMPLE(
"Etc/GMT")) {
562 return isolate->factory()->UTC_string();
566 if (
id.startsWith(u
"GMT", 3)) {
573 const icu::TimeZone& tz) {
574 Factory* factory = isolate->factory();
577 icu::UnicodeString canonical_time_zone;
579 canonical_time_zone = u
"+00:00";
581 UErrorCode status = U_ZERO_ERROR;
582 icu::TimeZone::getCanonicalID(
time_zone, canonical_time_zone, status);
583 if (U_FAILURE(status)) {
586 return factory->undefined_value();
593 return timezone_value;
598 Isolate* isolate,
const icu::SimpleDateFormat& simple_date_format) {
602 std::string calendar_str = simple_date_format.getCalendar()->getType();
608 if (calendar_str ==
"gregorian") {
609 calendar_str =
"gregory";
610 }
else if (calendar_str ==
"ethiopic-amete-alem") {
611 calendar_str =
"ethioaa";
613 return isolate->factory()->NewStringFromAsciiChecked(calendar_str.c_str());
616DirectHandle<Object> GetTimeZone(
617 Isolate* isolate,
const icu::SimpleDateFormat& simple_date_format) {
619 isolate, simple_date_format.getCalendar()->getTimeZone());
625 return GetCalendar(isolate,
626 *(date_time_format->icu_simple_date_format()->raw()));
631 return GetTimeZone(isolate,
632 *(date_time_format->icu_simple_date_format()->raw()));
638 Factory* factory = isolate->factory();
648 icu::Locale* icu_locale = date_time_format->icu_locale()->raw();
651 date_time_format->icu_simple_date_format()->raw();
661 icu::UnicodeString pattern_unicode;
664 pattern_unicode.toUTF8String(
pattern);
686 isolate, options, factory->locale_string(), locale,
Just(
kDontThrow));
688 USE(maybe_create_locale);
695 USE(maybe_create_calendar);
697 if (!numbering_system.empty()) {
699 isolate, options, factory->numberingSystem_string(),
703 USE(maybe_create_numbering_system);
706 isolate, options, factory->timeZone_string(), timezone,
Just(
kDontThrow));
708 USE(maybe_create_time_zone);
711 HourCycle hc = date_time_format->hour_cycle();
715 isolate, options, factory->hourCycle_string(),
718 USE(maybe_create_hour_cycle);
724 isolate, options, factory->hour12_string(), factory->true_value(),
727 USE(maybe_create_hour12);
733 isolate, options, factory->hour12_string(), factory->false_value(),
736 USE(maybe_create_hour12);
749 for (
const auto& item : GetPatternItems()) {
751 if (item.property ==
"timeZoneName") {
752 int fsd = FractionalSecondDigitsFromPattern(
pattern);
754 Maybe<bool> maybe_create_fractional_seconds_digits =
756 isolate, options, factory->fractionalSecondDigits_string(),
759 USE(maybe_create_fractional_seconds_digits);
762 for (
const auto& pair : item.pairs) {
763 if (
pattern.find(pair.pattern) != std::string::npos) {
770 USE(maybe_create_property);
780 isolate, options, factory->dateStyle_string(),
781 DateTimeStyleAsString(isolate, date_time_format->date_style()),
784 USE(maybe_create_date_style);
790 isolate, options, factory->timeStyle_string(),
791 DateTimeStyleAsString(isolate, date_time_format->time_style()),
794 USE(maybe_create_time_style);
804 if (!IsJSReceiver(*value)) {
813 if (!IsJSTemporalPlainDate(*value) && !IsJSTemporalPlainTime(*value) &&
814 !IsJSTemporalPlainDateTime(*value) &&
815 !IsJSTemporalZonedDateTime(*value) &&
816 !IsJSTemporalPlainYearMonth(*value) &&
817 !IsJSTemporalPlainMonthDay(*value) && !IsJSTemporalInstant(*value)) {
826bool SameTemporalType(DirectHandle<Object>
x, DirectHandle<Object>
y) {
829 if (!IsTemporalObject(
x))
return false;
830 if (!IsTemporalObject(
y))
return false;
833 if (IsJSTemporalPlainDate(*
x) && !IsJSTemporalPlainDate(*
y))
return false;
836 if (IsJSTemporalPlainTime(*
x) && !IsJSTemporalPlainTime(*
y))
return false;
839 if (IsJSTemporalPlainDateTime(*
x) && !IsJSTemporalPlainDateTime(*
y)) {
844 if (IsJSTemporalZonedDateTime(*
x) && !IsJSTemporalZonedDateTime(*
y)) {
849 if (IsJSTemporalPlainYearMonth(*
x) && !IsJSTemporalPlainYearMonth(*
y)) {
854 if (IsJSTemporalPlainMonthDay(*
x) && !IsJSTemporalPlainMonthDay(*
y)) {
859 if (IsJSTemporalInstant(*
x) && !IsJSTemporalInstant(*
y))
return false;
864enum class PatternKind {
874struct DateTimeValueRecord {
879DateTimeValueRecord TemporalInstantToRecord(
880 Isolate* isolate, DirectHandle<JSTemporalInstant> instant,
882 double milliseconds =
887 return {milliseconds,
kind};
890Maybe<DateTimeValueRecord> TemporalPlainDateTimeToRecord(
891 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
892 PatternKind
kind, DirectHandle<JSTemporalPlainDateTime> plain_date_time,
893 const char* method_name) {
895 DirectHandle<Object> time_zone_obj = GetTimeZone(isolate, date_time_format);
898 CHECK(IsString(*time_zone_obj));
899 DirectHandle<JSTemporalTimeZone>
time_zone =
904 DirectHandle<JSTemporalInstant> instant;
908 isolate,
time_zone, plain_date_time, method_name),
915 return Just(TemporalInstantToRecord(isolate, instant,
kind));
919Maybe<DateTimeValueRecord> TemporalToRecord(
920 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
921 PatternKind
kind, DirectHandle<T> temporal,
922 DirectHandle<JSReceiver>
calendar,
const char* method_name) {
926 DirectHandle<JSTemporalPlainDateTime> plain_date_time;
928 isolate, plain_date_time,
931 {{temporal->iso_year(), temporal->iso_month(), temporal->iso_day()},
932 {12, 0, 0, 0, 0, 0}},
935 return TemporalPlainDateTimeToRecord(isolate, date_time_format,
kind,
936 plain_date_time, method_name);
940Maybe<DateTimeValueRecord> HandleDateTimeTemporalDate(
941 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
942 DirectHandle<String> date_time_format_calendar,
943 DirectHandle<JSTemporalPlainDate> temporal_date,
const char* method_name) {
957 DirectHandle<JSReceiver> calendar_override;
960 calendar_override =
direct_handle(temporal_date->calendar(), isolate);
963 isolate->factory()->iso8601_string())) {
967 isolate, calendar_override,
975 NewRangeError(MessageTemplate::kInvalid,
976 isolate->factory()->calendar_string(),
calendar),
979 return TemporalToRecord<JSTemporalPlainDate>(
980 isolate, date_time_format, PatternKind::kPlainDate, temporal_date,
981 calendar_override, method_name);
985Maybe<DateTimeValueRecord> HandleDateTimeTemporalDateTime(
986 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
987 DirectHandle<String> date_time_format_calendar,
988 DirectHandle<JSTemporalPlainDateTime> date_time,
const char* method_name) {
999 DirectHandle<JSReceiver> calendar_override;
1001 isolate->factory()->iso8601_string()) &&
1006 NewRangeError(MessageTemplate::kInvalid,
1007 isolate->factory()->calendar_string(),
calendar),
1019 return TemporalPlainDateTimeToRecord(isolate, date_time_format,
1020 PatternKind::kPlainDateTime, date_time,
1025Maybe<DateTimeValueRecord> HandleDateTimeTemporalZonedDateTime(
1026 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
1027 DirectHandle<String> date_time_format_calendar,
1028 DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
1029 const char* method_name) {
1043 DirectHandle<JSReceiver> calendar_override;
1045 isolate->factory()->iso8601_string()) &&
1050 NewRangeError(MessageTemplate::kInvalid,
1051 isolate->factory()->calendar_string(),
calendar),
1063 DirectHandle<Object> date_time_format_time_zone =
1064 GetTimeZone(isolate, date_time_format);
1065 DCHECK(IsString(*date_time_format_time_zone));
1066 DirectHandle<String> date_time_format_time_zone_string =
1074 NewRangeError(MessageTemplate::kInvalid,
1075 isolate->factory()->timeZone_string(),
time_zone),
1079 DirectHandle<JSTemporalInstant> instant =
1081 isolate,
direct_handle(zoned_date_time->nanoseconds(), isolate))
1088 TemporalInstantToRecord(isolate, instant, PatternKind::kZonedDateTime));
1092Maybe<DateTimeValueRecord> HandleDateTimeTemporalInstant(
1093 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
1094 DirectHandle<JSTemporalInstant> instant,
const char* method_name) {
1101 return Just(TemporalInstantToRecord(isolate, instant, PatternKind::kInstant));
1105Maybe<DateTimeValueRecord> HandleDateTimeTemporalTime(
1106 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
1107 DirectHandle<JSTemporalPlainTime> temporal_time,
const char* method_name) {
1119 DirectHandle<JSTemporalPlainDateTime> plain_date_time;
1121 isolate, plain_date_time,
1125 {temporal_time->iso_hour(), temporal_time->iso_minute(),
1126 temporal_time->iso_second(), temporal_time->iso_millisecond(),
1127 temporal_time->iso_microsecond(), temporal_time->iso_nanosecond()}},
1130 return TemporalPlainDateTimeToRecord(isolate, date_time_format,
1131 PatternKind::kPlainTime, plain_date_time,
1135template <
typename T>
1136Maybe<DateTimeValueRecord> HandleDateTimeTemporalYearMonthOrMonthDay(
1137 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
1138 DirectHandle<String> date_time_format_calendar, PatternKind
kind,
1139 DirectHandle<T> temporal,
const char* method_name) {
1152 NewRangeError(MessageTemplate::kInvalid,
1153 isolate->factory()->calendar_string(),
calendar),
1157 return TemporalToRecord<T>(isolate, date_time_format,
kind, temporal,
1163Maybe<DateTimeValueRecord> HandleDateTimeTemporalYearMonth(
1164 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
1165 DirectHandle<String> date_time_format_calendar,
1166 DirectHandle<JSTemporalPlainYearMonth> temporal_year_month,
1167 const char* method_name) {
1168 return HandleDateTimeTemporalYearMonthOrMonthDay<JSTemporalPlainYearMonth>(
1169 isolate, date_time_format, date_time_format_calendar,
1170 PatternKind::kPlainYearMonth, temporal_year_month, method_name);
1174Maybe<DateTimeValueRecord> HandleDateTimeTemporalMonthDay(
1175 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
1176 DirectHandle<String> date_time_format_calendar,
1177 DirectHandle<JSTemporalPlainMonthDay> temporal_month_day,
1178 const char* method_name) {
1179 return HandleDateTimeTemporalYearMonthOrMonthDay<JSTemporalPlainMonthDay>(
1180 isolate, date_time_format, date_time_format_calendar,
1181 PatternKind::kPlainMonthDay, temporal_month_day, method_name);
1185Maybe<DateTimeValueRecord> HandleDateTimeOthers(
1186 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
1187 DirectHandle<Object> x_obj,
const char* method_name) {
1189 DCHECK(!IsTemporalObject(x_obj));
1196 if (IsUndefined(*x_obj)) {
1211 isolate, NewRangeError(MessageTemplate::kInvalidTimeValue),
1219 return Just(DateTimeValueRecord({
x, PatternKind::kDate}));
1223Maybe<DateTimeValueRecord> HandleDateTimeValue(
1224 Isolate* isolate,
const icu::SimpleDateFormat& date_time_format,
1225 DirectHandle<String> date_time_format_calendar, DirectHandle<Object>
x,
1226 const char* method_name) {
1227 if (IsTemporalObject(
x)) {
1229 if (IsJSTemporalPlainDate(*
x)) {
1231 return HandleDateTimeTemporalDate(
1232 isolate, date_time_format, date_time_format_calendar,
1236 if (IsJSTemporalPlainYearMonth(*
x)) {
1238 return HandleDateTimeTemporalYearMonth(
1239 isolate, date_time_format, date_time_format_calendar,
1243 if (IsJSTemporalPlainMonthDay(*
x)) {
1245 return HandleDateTimeTemporalMonthDay(
1246 isolate, date_time_format, date_time_format_calendar,
1250 if (IsJSTemporalPlainTime(*
x)) {
1252 return HandleDateTimeTemporalTime(
1256 if (IsJSTemporalPlainDateTime(*
x)) {
1258 return HandleDateTimeTemporalDateTime(
1259 isolate, date_time_format, date_time_format_calendar,
1263 if (IsJSTemporalInstant(*
x)) {
1265 return HandleDateTimeTemporalInstant(
1269 DCHECK(IsJSTemporalZonedDateTime(*
x));
1271 return HandleDateTimeTemporalZonedDateTime(
1272 isolate, date_time_format, date_time_format_calendar,
1277 return HandleDateTimeOthers(isolate, date_time_format,
x, method_name);
1290icu::UnicodeString KeepSupportedAddDefault(
1291 const icu::UnicodeString& input,
const std::set<char16_t>& keep,
1292 const std::set<char16_t>& add_default) {
1293 const std::map<char16_t, char16_t> equivalent({{
'L',
'M'},
1300 std::set<char16_t> to_be_added(add_default);
1301 icu::UnicodeString
result;
1302 for (int32_t
i = 0;
i < input.
length();
i++) {
1303 char16_t ch = input.charAt(
i);
1304 if (keep.find(ch) != keep.end()) {
1305 to_be_added.erase(ch);
1306 auto also = equivalent.find(ch);
1307 if (also != equivalent.end()) {
1308 to_be_added.erase(also->second);
1313 for (
auto it = to_be_added.begin(); it != to_be_added.end(); ++it) {
1319icu::UnicodeString GetSkeletonForPatternKind(
const icu::UnicodeString& input,
1334 case PatternKind::kDate:
1336 case PatternKind::kPlainDate:
1337 return KeepSupportedAddDefault(
1340 input, {
'E',
'c',
'G',
'y',
'M',
'L',
'd'},
1343 case PatternKind::kPlainYearMonth:
1344 return KeepSupportedAddDefault(
1346 input, {
'G',
'y',
'M',
'L'},
1349 case PatternKind::kPlainMonthDay:
1350 return KeepSupportedAddDefault(
1352 input, {
'M',
'L',
'd'},
1356 case PatternKind::kPlainTime:
1357 return KeepSupportedAddDefault(
1361 {
'h',
'H',
'k',
'K',
'j',
'm',
's',
'B',
'b',
'a',
'S'},
1366 case PatternKind::kPlainDateTime:
1371 case PatternKind::kInstant:
1372 return KeepSupportedAddDefault(
1377 {
'E',
'c',
'G',
'y',
'M',
'L',
'd',
'h',
'H',
'k',
'K',
'j',
'm',
's',
1378 'B',
'b',
'a',
'S'},
1381 {
'y',
'M',
'd',
'j',
'm',
's'});
1383 case PatternKind::kZonedDateTime:
1384 return KeepSupportedAddDefault(
1388 input, {
'E',
'c',
'G',
'y',
'M',
'L',
'd',
'h',
'H',
'k',
'K',
1389 'j',
'm',
's',
'B',
'b',
'a',
'S',
'z',
'O',
'v'},
1392 {
'y',
'M',
'd',
'j',
'm',
's',
'z'});
1396icu::UnicodeString SkeletonFromDateFormat(
1397 const icu::SimpleDateFormat& icu_date_format) {
1401 UErrorCode status = U_ZERO_ERROR;
1402 icu::UnicodeString skeleton =
1403 icu::DateTimePatternGenerator::staticGetSkeleton(
pattern, status);
1404 DCHECK(U_SUCCESS(status));
1408std::unique_ptr<icu::SimpleDateFormat> GetSimpleDateTimeForTemporal(
1409 const icu::SimpleDateFormat& date_format, PatternKind
kind) {
1411 icu::UnicodeString skeleton =
1412 GetSkeletonForPatternKind(SkeletonFromDateFormat(date_format),
kind);
1413 UErrorCode status = U_ZERO_ERROR;
1414 std::unique_ptr<icu::SimpleDateFormat>
result(
1415 static_cast<icu::SimpleDateFormat*
>(
1416 icu::DateFormat::createInstanceForSkeleton(
1417 skeleton, date_format.getSmpFmtLocale(), status)));
1419 DCHECK(U_SUCCESS(status));
1420 result->setTimeZone(date_format.getTimeZone());
1424icu::UnicodeString CallICUFormat(
const icu::SimpleDateFormat& date_format,
1425 PatternKind
kind,
double time_in_milliseconds,
1426 icu::FieldPositionIterator* fp_iter,
1427 UErrorCode& status) {
1428 icu::UnicodeString
result;
1430 if (
kind == PatternKind::kDate) {
1431 date_format.format(time_in_milliseconds,
result, fp_iter, status);
1435 std::unique_ptr<icu::SimpleDateFormat>
pattern(
1436 GetSimpleDateTimeForTemporal(date_format,
kind));
1437 pattern->format(time_in_milliseconds,
result, fp_iter, status);
1443MaybeDirectHandle<String> FormatDateTime(
1444 Isolate* isolate,
const icu::SimpleDateFormat& date_format,
double x) {
1446 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
1449 icu::UnicodeString
result;
1450 date_format.format(
x,
result);
1454 result =
result.findAndReplace(icu::UnicodeString(0x202f),
1455 icu::UnicodeString(0x20));
1460MaybeDirectHandle<String> FormatMillisecondsByKindToString(
1461 Isolate* isolate,
const icu::SimpleDateFormat& date_format,
1462 PatternKind
kind,
double x) {
1463 UErrorCode status = U_ZERO_ERROR;
1464 icu::UnicodeString
result =
1465 CallICUFormat(date_format,
kind,
x,
nullptr, status);
1466 DCHECK(U_SUCCESS(status));
1471MaybeDirectHandle<String> FormatDateTimeWithTemporalSupport(
1472 Isolate* isolate,
const icu::SimpleDateFormat& date_format,
1473 DirectHandle<String> date_time_format_calendar, DirectHandle<Object>
x,
1474 const char* method_name) {
1475 DateTimeValueRecord
record;
1478 HandleDateTimeValue(isolate, date_format, date_time_format_calendar,
x,
1481 return FormatMillisecondsByKindToString(isolate, date_format,
record.kind,
1482 record.epoch_milliseconds);
1485MaybeDirectHandle<String> FormatDateTimeWithTemporalSupport(
1486 Isolate* isolate, DirectHandle<JSDateTimeFormat> date_time_format,
1487 DirectHandle<Object>
x,
const char* method_name) {
1488 return FormatDateTimeWithTemporalSupport(
1489 isolate, *(date_time_format->icu_simple_date_format()->raw()),
1503 return FormatDateTimeWithTemporalSupport(isolate, date_time_format,
date,
1509 if (IsUndefined(*
date)) {
1520 icu::SimpleDateFormat* format =
1521 date_time_format->icu_simple_date_format()->raw();
1522 return FormatDateTime(isolate, *format,
x);
1526Isolate::ICUObjectCacheType ConvertToCacheType(
1530 return Isolate::ICUObjectCacheType::kDefaultSimpleDateFormatForDate;
1532 return Isolate::ICUObjectCacheType::kDefaultSimpleDateFormatForTime;
1534 return Isolate::ICUObjectCacheType::kDefaultSimpleDateFormat;
1544 Isolate::ICUObjectCacheType cache_type = ConvertToCacheType(defaults);
1546 Factory* factory = isolate->factory();
1548 if (!IsJSDate(*
date)) {
1550 NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
1551 factory->Date_string()));
1555 if (std::isnan(
x)) {
1556 return factory->Invalid_Date_string();
1562 bool can_cache = (IsString(*locales) || IsUndefined(*locales, isolate)) &&
1563 IsUndefined(*options, isolate);
1566 icu::SimpleDateFormat* cached_icu_simple_date_format =
1567 static_cast<icu::SimpleDateFormat*
>(
1568 isolate->get_cached_icu_object(cache_type, locales));
1569 if (cached_icu_simple_date_format !=
nullptr) {
1570 return FormatDateTime(isolate, *cached_icu_simple_date_format,
x);
1577 ->intl_date_time_format_function()),
1585 isolate, date_time_format,
1587 required, defaults, method_name));
1590 isolate->set_icu_object_in_cache(
1591 cache_type, locales,
1592 std::static_pointer_cast<icu::UMemory>(
1593 date_time_format->icu_simple_date_format()->get()));
1596 icu::SimpleDateFormat* format =
1597 date_time_format->icu_simple_date_format()->raw();
1598 return FormatDateTime(isolate, *format,
x);
1606 isolate->context()->native_context()->intl_date_time_format_function(),
1613 isolate, date_time_format,
1617 return FormatDateTimeWithTemporalSupport(isolate, date_time_format,
x,
1632 IsJSDateTimeFormat(*format_holder)));
1635 if (!IsJSDateTimeFormat(*dtf)) {
1638 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
1639 isolate->factory()->NewStringFromAsciiChecked(
1640 "UnwrapDateTimeFormat"),
1655 int32_t len = flat.
length();
1658 return std::nullopt;
1660 std::string tz(
"GMT");
1661 switch (flat.
Get(0)) {
1671 return std::nullopt;
1674 uint16_t h0 = flat.
Get(1);
1675 uint16_t h1 = flat.
Get(2);
1677 if ((h0 >=
'0' && h0 <=
'1' && h1 >=
'0' && h1 <=
'9') ||
1678 (h0 ==
'2' && h1 >=
'0' && h1 <=
'3')) {
1683 return std::nullopt;
1689 uint16_t m0 = flat.
Get(p);
1695 return std::nullopt;
1701 return std::nullopt;
1703 uint16_t m1 = flat.
Get(p + 1);
1704 if (m0 >=
'0' && m0 <=
'5' && m1 >=
'0' && m1 <=
'9') {
1710 return std::nullopt;
1716 std::optional<std::string> offsetTimeZone =
1718 if (offsetTimeZone.has_value()) {
1719 std::unique_ptr<icu::TimeZone> tz(
1720 icu::TimeZone::createTimeZone(offsetTimeZone->c_str()));
1723 std::unique_ptr<char[]>
time_zone = time_zone_string->ToCString();
1725 if (canonicalized.empty())
return std::unique_ptr<icu::TimeZone>();
1726 std::unique_ptr<icu::TimeZone> tz(
1727 icu::TimeZone::createTimeZone(canonicalized.c_str()));
1736class CalendarCache {
1738 icu::Calendar* CreateCalendar(
const icu::Locale& locale, icu::TimeZone* tz) {
1739 icu::UnicodeString tz_id;
1742 tz_id.toUTF8String<std::string>(
key);
1744 key += locale.getName();
1748 if (it !=
map_.end()) {
1750 return it->second->clone();
1753 UErrorCode status = U_ZERO_ERROR;
1754 std::unique_ptr<icu::Calendar>
calendar(
1755 icu::Calendar::createInstance(tz, locale, status));
1756 DCHECK(U_SUCCESS(status));
1759 if (
calendar->getDynamicClassID() ==
1760 icu::GregorianCalendar::getStaticClassID() ||
1761 strcmp(
calendar->getType(),
"iso8601") == 0) {
1762 icu::GregorianCalendar* gc =
1763 static_cast<icu::GregorianCalendar*
>(
calendar.get());
1764 status = U_ZERO_ERROR;
1766 const double start_of_time = -9007199254740992;
1767 gc->setGregorianChange(start_of_time, status);
1768 DCHECK(U_SUCCESS(status));
1771 if (
map_.size() > 8) {
1779 std::map<std::string, std::unique_ptr<icu::Calendar>>
map_;
1783icu::Calendar* CreateCalendar(Isolate* isolate,
const icu::Locale& icu_locale,
1784 icu::TimeZone* tz) {
1787 return calendar_cache.Pointer()->CreateCalendar(icu_locale, tz);
1790icu::UnicodeString ReplaceHourCycleInPattern(icu::UnicodeString
pattern,
1792 char16_t replacement;
1809 bool replace =
true;
1810 icu::UnicodeString
result;
1811 char16_t last = u
'\0';
1812 for (int32_t
i = 0;
i <
pattern.length();
i++) {
1827 if (replace && last == u
'd') {
1830 result.append(replace ? replacement : ch);
1841std::unique_ptr<icu::SimpleDateFormat> CreateICUDateFormat(
1842 const icu::Locale& icu_locale,
const icu::UnicodeString& skeleton,
1855 UErrorCode status = U_ZERO_ERROR;
1856 pattern = generator->getBestPattern(skeleton, UDATPG_MATCH_HOUR_FIELD_LENGTH,
1859 DCHECK(U_SUCCESS(status));
1863 status = U_ZERO_ERROR;
1864 std::unique_ptr<icu::SimpleDateFormat> date_format(
1865 new icu::SimpleDateFormat(
pattern, icu_locale, status));
1866 if (U_FAILURE(status))
return std::unique_ptr<icu::SimpleDateFormat>();
1872class DateFormatCache {
1874 icu::SimpleDateFormat* Create(
const icu::Locale& icu_locale,
1875 const icu::UnicodeString& skeleton,
1876 icu::DateTimePatternGenerator* generator,
1879 skeleton.toUTF8String<std::string>(
key);
1881 key += icu_locale.getName();
1885 if (it !=
map_.end()) {
1886 return static_cast<icu::SimpleDateFormat*
>(it->second->clone());
1889 if (
map_.size() > 8) {
1892 std::unique_ptr<icu::SimpleDateFormat> instance(
1893 CreateICUDateFormat(icu_locale, skeleton, generator, hc));
1894 if (instance ==
nullptr)
return nullptr;
1895 map_[
key] = std::move(instance);
1896 return static_cast<icu::SimpleDateFormat*
>(
map_[
key]->clone());
1900 std::map<std::string, std::unique_ptr<icu::SimpleDateFormat>>
map_;
1904std::unique_ptr<icu::SimpleDateFormat> CreateICUDateFormatFromCache(
1905 const icu::Locale& icu_locale,
const icu::UnicodeString& skeleton,
1909 return std::unique_ptr<icu::SimpleDateFormat>(
1910 cache.Pointer()->Create(icu_locale, skeleton, generator, hc));
1920std::unique_ptr<icu::DateIntervalFormat> LazyCreateDateIntervalFormat(
1921 Isolate* isolate, DirectHandle<JSDateTimeFormat> date_time_format,
1924 date_time_format->icu_date_interval_format();
1925 if (
kind == PatternKind::kDate && managed_format->get()) {
1926 return std::unique_ptr<icu::DateIntervalFormat>(
1927 managed_format->raw()->clone());
1929 UErrorCode status = U_ZERO_ERROR;
1931 icu::Locale loc = *(date_time_format->icu_locale()->raw());
1934 std::string hcString = ToHourCycleString(date_time_format->hour_cycle());
1935 if (!hcString.empty()) {
1936 loc.setUnicodeKeywordValue(
"hc", hcString, status);
1940 date_time_format->icu_simple_date_format()->raw();
1942 icu::UnicodeString skeleton = GetSkeletonForPatternKind(
1945 std::unique_ptr<icu::DateIntervalFormat> date_interval_format(
1946 icu::DateIntervalFormat::createInstance(skeleton, loc, status));
1947 DCHECK(U_SUCCESS(status));
1949 if (
kind != PatternKind::kDate) {
1950 return date_interval_format;
1952 DirectHandle<Managed<icu::DateIntervalFormat>> managed_interval_format =
1954 std::move(date_interval_format));
1955 date_time_format->set_icu_date_interval_format(*managed_interval_format);
1956 return std::unique_ptr<icu::DateIntervalFormat>(
1957 managed_interval_format->raw()->clone());
1961 const icu::UnicodeString
pattern) {
1962 bool in_quote =
false;
1963 for (int32_t
i = 0;
i <
pattern.length();
i++) {
1967 in_quote = !in_quote;
1986icu::DateFormat::EStyle DateTimeStyleToEStyle(
1990 return icu::DateFormat::EStyle::kFull;
1992 return icu::DateFormat::EStyle::kLong;
1994 return icu::DateFormat::EStyle::kMedium;
1996 return icu::DateFormat::EStyle::kShort;
2002icu::UnicodeString ReplaceSkeleton(
const icu::UnicodeString input,
2004 icu::UnicodeString
result;
2022 for (int32_t
i = 0;
i < input.
length();
i++) {
2050std::unique_ptr<icu::SimpleDateFormat> DateTimeStylePattern(
2054 std::unique_ptr<icu::SimpleDateFormat>
result;
2057 result.reset(
reinterpret_cast<icu::SimpleDateFormat*
>(
2058 icu::DateFormat::createDateTimeInstance(
2059 DateTimeStyleToEStyle(date_style),
2060 DateTimeStyleToEStyle(time_style), icu_locale)));
2062 result.reset(
reinterpret_cast<icu::SimpleDateFormat*
>(
2063 icu::DateFormat::createDateInstance(DateTimeStyleToEStyle(date_style),
2073 result.reset(
reinterpret_cast<icu::SimpleDateFormat*
>(
2074 icu::DateFormat::createTimeInstance(DateTimeStyleToEStyle(time_style),
2081 UErrorCode status = U_ZERO_ERROR;
2083 if (
result.get() ==
nullptr) {
2085 if (!icu_locale.getUnicodeKeywordValue<std::string>(
"nu", status).empty()) {
2086 status = U_ZERO_ERROR;
2087 icu_locale.setUnicodeKeywordValue(
"nu",
nullptr, status);
2088 return DateTimeStylePattern(date_style, time_style, icu_locale, hc,
2091 status = U_ZERO_ERROR;
2093 if (!icu_locale.getUnicodeKeywordValue<std::string>(
"hc", status).empty()) {
2094 status = U_ZERO_ERROR;
2095 icu_locale.setUnicodeKeywordValue(
"hc",
nullptr, status);
2096 return DateTimeStylePattern(date_style, time_style, icu_locale, hc,
2099 status = U_ZERO_ERROR;
2101 if (!icu_locale.getUnicodeKeywordValue<std::string>(
"ca", status).empty()) {
2102 status = U_ZERO_ERROR;
2103 icu_locale.setUnicodeKeywordValue(
"ca",
nullptr, status);
2104 return DateTimeStylePattern(date_style, time_style, icu_locale, hc,
2112 status = U_ZERO_ERROR;
2113 icu::UnicodeString skeleton =
2114 icu::DateTimePatternGenerator::staticGetSkeleton(
pattern, status);
2115 DCHECK(U_SUCCESS(status));
2118 if (hc == HourCycleFromPattern(
pattern)) {
2122 return CreateICUDateFormatFromCache(icu_locale, ReplaceSkeleton(skeleton, hc),
2126class DateTimePatternGeneratorCache {
2129 icu::DateTimePatternGenerator* CreateGenerator(Isolate* isolate,
2130 const icu::Locale& locale) {
2131 std::string
key(locale.getName());
2134 icu::DateTimePatternGenerator* orig;
2135 if (it !=
map_.end()) {
2136 DCHECK(it->second !=
nullptr);
2137 orig = it->second.get();
2139 UErrorCode status = U_ZERO_ERROR;
2140 orig = icu::DateTimePatternGenerator::createInstance(locale, status);
2143 if (U_FAILURE(status)) {
2144 status = U_ZERO_ERROR;
2145 orig = icu::DateTimePatternGenerator::createInstance(
"root", status);
2147 if (U_SUCCESS(status) && orig !=
nullptr) {
2150 DCHECK(status == U_MEMORY_ALLOCATION_ERROR);
2152 isolate,
"DateTimePatternGeneratorCache::CreateGenerator");
2155 icu::DateTimePatternGenerator* clone = orig ? orig->clone() :
nullptr;
2156 if (clone ==
nullptr) {
2158 isolate,
"DateTimePatternGeneratorCache::CreateGenerator");
2164 std::map<std::string, std::unique_ptr<icu::DateTimePatternGenerator>>
map_;
2185 Factory* factory = isolate->factory();
2190 std::vector<std::string> requested_locales =
2191 maybe_requested_locales.
FromJust();
2205 std::unique_ptr<char[]> calendar_str =
nullptr;
2206 std::unique_ptr<char[]> numbering_system_str =
nullptr;
2207 const std::vector<const char*> empty_values = {};
2211 isolate, options,
"calendar", empty_values, service, &calendar_str);
2213 if (maybe_calendar.
FromJust() && calendar_str !=
nullptr) {
2214 icu::Locale default_locale;
2217 isolate, NewRangeError(
2218 MessageTemplate::kInvalid, factory->calendar_string(),
2226 isolate, options, service, &numbering_system_str);
2233 GetBoolOption(isolate, options,
"hour12", service, &hour12);
2238 Maybe<HourCycle> maybe_hour_cycle = GetHourCycle(isolate, options, service);
2252 std::set<std::string> relevant_extension_keys = {
"nu",
"ca",
"hc"};
2261 locale_matcher, relevant_extension_keys);
2267 icu::Locale icu_locale =
r.icu_locale;
2268 DCHECK(!icu_locale.isBogus());
2270 UErrorCode status = U_ZERO_ERROR;
2271 if (calendar_str !=
nullptr) {
2272 auto ca_extension_it =
r.extensions.find(
"ca");
2273 if (ca_extension_it !=
r.extensions.end() &&
2274 ca_extension_it->second != calendar_str.get()) {
2275 icu_locale.setUnicodeKeywordValue(
"ca",
nullptr, status);
2276 DCHECK(U_SUCCESS(status));
2279 if (numbering_system_str !=
nullptr) {
2280 auto nu_extension_it =
r.extensions.find(
"nu");
2281 if (nu_extension_it !=
r.extensions.end() &&
2282 nu_extension_it->second != numbering_system_str.get()) {
2283 icu_locale.setUnicodeKeywordValue(
"nu",
nullptr, status);
2284 DCHECK(U_SUCCESS(status));
2290 icu::Locale resolved_locale(icu_locale);
2292 if (calendar_str !=
nullptr &&
2294 icu_locale.setUnicodeKeywordValue(
"ca", calendar_str.get(), status);
2295 DCHECK(U_SUCCESS(status));
2298 if (numbering_system_str !=
nullptr &&
2300 icu_locale.setUnicodeKeywordValue(
"nu", numbering_system_str.get(), status);
2301 DCHECK(U_SUCCESS(status));
2307 std::unique_ptr<icu::DateTimePatternGenerator> generator(
2308 generator_cache.Pointer()->CreateGenerator(isolate, icu_locale));
2311 HourCycle hc_default = ToHourCycle(generator->getDefaultHourCycle(status));
2312 DCHECK(U_SUCCESS(status));
2317 auto hc_extension_it =
r.extensions.find(
"hc");
2318 if (hc_extension_it !=
r.extensions.end()) {
2319 hc = ToHourCycle(hc_extension_it->second.c_str());
2329 hc = DefaultHourCycle12(icu_locale, hc_default);
2333 hc = DefaultHourCycle24(icu_locale, hc_default);
2348 isolate, time_zone_obj,
2350 isolate->factory()->timeZone_string()));
2352 std::unique_ptr<icu::TimeZone> tz;
2353 if (!IsUndefined(*time_zone_obj, isolate)) {
2360 tz.reset(icu::TimeZone::createDefault());
2363 if (tz.get() ==
nullptr) {
2364 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeZone,
2368 std::unique_ptr<icu::Calendar>
calendar(
2369 CreateCalendar(isolate, icu_locale, tz.release()));
2374 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeZone,
2380 std::unique_ptr<icu::SimpleDateFormat> icu_date_format;
2383 int32_t explicit_format_components =
2386 bool has_hour_option =
false;
2387 std::string skeleton;
2388 for (
const PatternData& item : GetPatternData(hc)) {
2390 if (item.property ==
"timeZoneName") {
2397 factory->fractionalSecondDigits_string(), 1, 3, 0),
2400 explicit_format_components =
2401 FractionalSecondDigits::update(explicit_format_components,
true);
2404 for (
int i = 0;
i < fsd;
i++) {
2408 std::unique_ptr<char[]> input;
2414 item.allowed_values, service, &input);
2418 if (item.property ==
"hour") {
2419 has_hour_option =
true;
2423 skeleton += item.map.find(input.get())->second;
2426 explicit_format_components |= 1 <<
static_cast<int32_t
>(item.bitShift);
2438 isolate, options,
"formatMatcher", service, {
"best fit",
"basic"},
2448 isolate, options,
"dateStyle", service,
2449 {
"full",
"long",
"medium",
"short"},
2460 isolate, options,
"timeStyle", service,
2461 {
"full",
"long",
"medium",
"short"},
2474 dateTimeFormatHourCycle = hc;
2481 if (explicit_format_components != 0) {
2484 isolate, NewTypeError(MessageTemplate::kInvalid,
2493 NewTypeError(MessageTemplate::kInvalid,
2495 factory->timeStyle_string()));
2502 NewTypeError(MessageTemplate::kInvalid,
2504 factory->dateStyle_string()));
2508 isolate->CountUsage(
2513 dateTimeFormatHourCycle, generator.get());
2514 if (icu_date_format.get() ==
nullptr) {
2519 bool needDefaults =
true;
2527 needDefaults &= !Weekday::decode(explicit_format_components);
2528 needDefaults &= !Year::decode(explicit_format_components);
2529 needDefaults &= !Month::decode(explicit_format_components);
2530 needDefaults &= !Day::decode(explicit_format_components);
2538 needDefaults &= !DayPeriod::decode(explicit_format_components);
2539 needDefaults &= !Hour::decode(explicit_format_components);
2540 needDefaults &= !Minute::decode(explicit_format_components);
2541 needDefaults &= !Second::decode(explicit_format_components);
2543 !FractionalSecondDigits::decode(explicit_format_components);
2579 if (has_hour_option) {
2581 dateTimeFormatHourCycle = hc;
2587 icu::UnicodeString skeleton_ustr(skeleton.c_str());
2588 icu_date_format = CreateICUDateFormatFromCache(
2589 icu_locale, skeleton_ustr, generator.get(), dateTimeFormatHourCycle);
2590 if (icu_date_format.get() ==
nullptr) {
2592 icu_locale = icu::Locale(icu_locale.getBaseName());
2593 icu_date_format = CreateICUDateFormatFromCache(
2594 icu_locale, skeleton_ustr, generator.get(), dateTimeFormatHourCycle);
2595 if (icu_date_format.get() ==
nullptr) {
2604 icu_date_format->adoptCalendar(
calendar.release());
2621 auto hc_extension_it =
r.extensions.find(
"hc");
2622 if (hc_extension_it !=
r.extensions.end()) {
2623 if (dateTimeFormatHourCycle !=
2624 ToHourCycle(hc_extension_it->second.c_str())) {
2626 status = U_ZERO_ERROR;
2627 resolved_locale.setUnicodeKeywordValue(
"hc",
nullptr, status);
2628 DCHECK(U_SUCCESS(status));
2636 isolate->factory()->NewStringFromAsciiChecked(
2637 maybe_locale_str.
FromJust().c_str());
2641 isolate, 0, std::shared_ptr<icu::Locale>{icu_locale.clone()});
2645 std::move(icu_date_format));
2652 isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
2654 date_time_format->set_flags(0);
2656 date_time_format->set_date_style(
date_style);
2659 date_time_format->set_time_style(
time_style);
2661 date_time_format->set_hour_cycle(dateTimeFormatHourCycle);
2662 date_time_format->set_locale(*locale_str);
2663 date_time_format->set_icu_locale(*managed_locale);
2664 date_time_format->set_icu_simple_date_format(*managed_format);
2665 date_time_format->set_icu_date_interval_format(*managed_interval_format);
2666 return date_time_format;
2678 return isolate->factory()->literal_string();
2679 case UDAT_YEAR_FIELD:
2680 case UDAT_EXTENDED_YEAR_FIELD:
2681 return isolate->factory()->year_string();
2682 case UDAT_YEAR_NAME_FIELD:
2683 return isolate->factory()->yearName_string();
2684 case UDAT_MONTH_FIELD:
2685 case UDAT_STANDALONE_MONTH_FIELD:
2686 return isolate->factory()->month_string();
2687 case UDAT_DATE_FIELD:
2688 return isolate->factory()->day_string();
2689 case UDAT_HOUR_OF_DAY1_FIELD:
2690 case UDAT_HOUR_OF_DAY0_FIELD:
2691 case UDAT_HOUR1_FIELD:
2692 case UDAT_HOUR0_FIELD:
2693 return isolate->factory()->hour_string();
2694 case UDAT_MINUTE_FIELD:
2695 return isolate->factory()->minute_string();
2696 case UDAT_SECOND_FIELD:
2697 return isolate->factory()->second_string();
2698 case UDAT_DAY_OF_WEEK_FIELD:
2699 case UDAT_DOW_LOCAL_FIELD:
2700 case UDAT_STANDALONE_DAY_FIELD:
2701 return isolate->factory()->weekday_string();
2702 case UDAT_AM_PM_FIELD:
2703 case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
2704 case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
2705 return isolate->factory()->dayPeriod_string();
2706 case UDAT_TIMEZONE_FIELD:
2707 case UDAT_TIMEZONE_RFC_FIELD:
2708 case UDAT_TIMEZONE_GENERIC_FIELD:
2709 case UDAT_TIMEZONE_SPECIAL_FIELD:
2710 case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD:
2711 case UDAT_TIMEZONE_ISO_FIELD:
2712 case UDAT_TIMEZONE_ISO_LOCAL_FIELD:
2713 return isolate->factory()->timeZoneName_string();
2714 case UDAT_ERA_FIELD:
2715 return isolate->factory()->era_string();
2716 case UDAT_FRACTIONAL_SECOND_FIELD:
2717 return isolate->factory()->fractionalSecond_string();
2718 case UDAT_RELATED_YEAR_FIELD:
2719 return isolate->factory()->relatedYear_string();
2721 case UDAT_QUARTER_FIELD:
2722 case UDAT_STANDALONE_QUARTER_FIELD:
2730MaybeDirectHandle<JSArray> FieldPositionIteratorToArray(
2731 Isolate* isolate,
const icu::UnicodeString&
formatted,
2732 icu::FieldPositionIterator fp_iter,
bool output_source);
2734MaybeDirectHandle<JSArray> FormatMillisecondsByKindToArray(
2735 Isolate* isolate,
const icu::SimpleDateFormat& date_format,
2736 PatternKind
kind,
double x,
bool output_source) {
2737 icu::FieldPositionIterator fp_iter;
2738 UErrorCode status = U_ZERO_ERROR;
2740 CallICUFormat(date_format,
kind,
x, &fp_iter, status);
2741 if (U_FAILURE(status)) {
2744 return FieldPositionIteratorToArray(isolate,
formatted, fp_iter,
2748MaybeDirectHandle<JSArray> FormatMillisecondsByKindToArrayOutputSource(
2749 Isolate* isolate,
const icu::SimpleDateFormat& date_format,
2750 PatternKind
kind,
double x) {
2751 return FormatMillisecondsByKindToArray(isolate, date_format,
kind,
x,
true);
2754MaybeDirectHandle<JSArray> FormatToPartsWithTemporalSupport(
2755 Isolate* isolate, DirectHandle<JSDateTimeFormat> date_time_format,
2756 DirectHandle<Object>
x,
bool output_source,
const char* method_name) {
2757 icu::SimpleDateFormat* format =
2758 date_time_format->icu_simple_date_format()->raw();
2762 DateTimeValueRecord x_record;
2765 HandleDateTimeValue(isolate, *format, GetCalendar(isolate, *format),
x,
2769 return FormatMillisecondsByKindToArray(isolate, *format, x_record.kind,
2770 x_record.epoch_milliseconds,
2774MaybeDirectHandle<JSArray> FormatMillisecondsToArray(
2775 Isolate* isolate,
const icu::SimpleDateFormat& format,
double value,
2776 bool output_source) {
2778 icu::FieldPositionIterator fp_iter;
2779 UErrorCode status = U_ZERO_ERROR;
2780 format.format(value,
formatted, &fp_iter, status);
2781 if (U_FAILURE(status)) {
2784 return FieldPositionIteratorToArray(isolate,
formatted, fp_iter,
2788MaybeDirectHandle<JSArray> FormatMillisecondsToArrayOutputSource(
2789 Isolate* isolate,
const icu::SimpleDateFormat& format,
double value) {
2790 return FormatMillisecondsToArray(isolate, format, value,
true);
2797 Factory* factory = isolate->factory();
2799 return FormatToPartsWithTemporalSupport(isolate, date_time_format,
x,
2800 output_source, method_name);
2803 if (IsUndefined(*
x, isolate)) {
2811 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
2813 return FormatMillisecondsToArray(
2814 isolate, *(date_time_format->icu_simple_date_format()->raw()), date_value,
2821 icu::FieldPositionIterator fp_iter,
bool output_source) {
2822 Factory* factory = isolate->factory();
2823 icu::FieldPosition fp;
2826 if (length == 0)
return result;
2829 int32_t previous_end_pos = 0;
2831 while (fp_iter.next(fp)) {
2832 int32_t begin_pos = fp.getBeginIndex();
2833 int32_t end_pos = fp.getEndIndex();
2835 if (previous_end_pos < begin_pos) {
2839 if (output_source) {
2841 IcuDateFieldIdToDateType(-1, isolate), substring,
2842 isolate->factory()->source_string(),
2843 isolate->factory()->shared_string());
2846 IcuDateFieldIdToDateType(-1, isolate), substring);
2853 if (output_source) {
2855 IcuDateFieldIdToDateType(fp.getField(), isolate),
2856 substring, isolate->factory()->source_string(),
2857 isolate->factory()->shared_string());
2860 IcuDateFieldIdToDateType(fp.getField(), isolate),
2863 previous_end_pos = end_pos;
2866 if (previous_end_pos < length) {
2870 if (output_source) {
2872 IcuDateFieldIdToDateType(-1, isolate), substring,
2873 isolate->factory()->source_string(),
2874 isolate->factory()->shared_string());
2877 IcuDateFieldIdToDateType(-1, isolate), substring);
2893 return isolate->factory()->undefined_string();
2895 return isolate->factory()->h11_string();
2897 return isolate->factory()->h12_string();
2899 return isolate->factory()->h23_string();
2901 return isolate->factory()->h24_string();
2911 const icu::UnicodeString&
string, int32_t index, int32_t field,
2918 IcuDateFieldIdToDateType(field, isolate), substring,
2919 isolate->factory()->source_string(),
2929 UErrorCode status = U_ZERO_ERROR;
2931 if (U_FAILURE(status)) {
2934 icu::ConstrainedFieldPosition cfpos;
2935 while (
formatted.nextPosition(cfpos, status)) {
2936 if (cfpos.getCategory() == UFIELD_CATEGORY_DATE_INTERVAL_SPAN) {
2940 return std::nullopt;
2948std::optional<MaybeDirectHandle<JSArray>> FormattedDateIntervalToJSArray(
2949 Isolate* isolate,
const icu::FormattedValue&
formatted) {
2950 UErrorCode status = U_ZERO_ERROR;
2953 Factory* factory = isolate->factory();
2954 DirectHandle<JSArray> array = factory->
NewJSArray(0);
2955 icu::ConstrainedFieldPosition cfpos;
2958 Intl::FormatRangeSourceTracker tracker;
2959 bool output_range =
false;
2960 while (
formatted.nextPosition(cfpos, status)) {
2961 int32_t category = cfpos.getCategory();
2962 int32_t field = cfpos.getField();
2964 int32_t limit = cfpos.getLimit();
2966 if (category == UFIELD_CATEGORY_DATE_INTERVAL_SPAN) {
2968 output_range =
true;
2969 tracker.Add(field,
start, limit);
2971 DCHECK(category == UFIELD_CATEGORY_DATE);
2972 if (
start > previous_end_pos) {
2975 Maybe<bool> maybe_added =
2976 AddPartForFormatRange(isolate, array,
result, index, -1,
2977 previous_end_pos,
start, tracker);
2979 previous_end_pos =
start;
2982 Maybe<bool> maybe_added = AddPartForFormatRange(
2983 isolate, array,
result, index, field,
start, limit, tracker);
2985 previous_end_pos = limit;
2991 if (
end > previous_end_pos) {
2992 Maybe<bool> maybe_added = AddPartForFormatRange(
2993 isolate, array,
result, index, -1, previous_end_pos,
end, tracker);
2997 if (U_FAILURE(status)) {
3002 if (output_range)
return array;
3003 return std::nullopt;
3007template <
typename T, std::optional<MaybeDirectHandle<T>> (*Format)(
3008 Isolate*, const icu::FormattedValue&)>
3009std::optional<MaybeDirectHandle<T>> CallICUFormatRange(
3010 Isolate* isolate,
const icu::DateIntervalFormat* format,
3011 const icu::Calendar*
calendar,
double x,
double y);
3014template <
typename T, std::optional<MaybeDirectHandle<T>> (*Format)(
3015 Isolate*, const icu::FormattedValue&)>
3016std::optional<MaybeDirectHandle<T>> PartitionDateTimeRangePattern(
3017 Isolate* isolate, DirectHandle<JSDateTimeFormat> date_time_format,
double x,
3018 double y,
const char* method_name) {
3022 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
3027 THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
3030 std::unique_ptr<icu::DateIntervalFormat>
format(LazyCreateDateIntervalFormat(
3031 isolate, date_time_format, PatternKind::kDate));
3032 if (format.get() ==
nullptr) {
3036 icu::SimpleDateFormat* date_format =
3037 date_time_format->icu_simple_date_format()->raw();
3038 const icu::Calendar*
calendar = date_format->getCalendar();
3040 return CallICUFormatRange<T, Format>(isolate, format.get(),
calendar,
x,
y);
3043template <
typename T, std::optional<MaybeDirectHandle<T>> (*Format)(
3044 Isolate*, const icu::FormattedValue&)>
3045std::optional<MaybeDirectHandle<T>> CallICUFormatRange(
3046 Isolate* isolate,
const icu::DateIntervalFormat* format,
3047 const icu::Calendar*
calendar,
double x,
double y) {
3048 UErrorCode status = U_ZERO_ERROR;
3050 std::unique_ptr<icu::Calendar> c1(
calendar->clone());
3051 std::unique_ptr<icu::Calendar> c2(
calendar->clone());
3052 c1->setTime(
x, status);
3053 c2->setTime(
y, status);
3058 format->formatToValue(*c1, *c2, status);
3059 if (U_FAILURE(status)) {
3065template <
typename T,
3066 std::optional<MaybeDirectHandle<T>> (*Format)(
3067 Isolate*,
const icu::FormattedValue&),
3068 MaybeDirectHandle<T> (*Fallback)(
3069 Isolate*,
const icu::SimpleDateFormat&, PatternKind, double)>
3070MaybeDirectHandle<T> FormatRangeCommonWithTemporalSupport(
3071 Isolate* isolate, DirectHandle<JSDateTimeFormat> date_time_format,
3072 DirectHandle<Object> x_obj, DirectHandle<Object> y_obj,
3073 const char* method_name) {
3076 if (IsTemporalObject(x_obj) || IsTemporalObject(y_obj)) {
3078 if (!SameTemporalType(x_obj, y_obj)) {
3081 NewTypeError(MessageTemplate::kInvalidArgumentForTemporal, y_obj));
3086 date_time_format->icu_simple_date_format()->raw();
3087 DirectHandle<String> date_time_format_calendar =
3089 DateTimeValueRecord x_record;
3093 date_time_format_calendar, x_obj, method_name),
3097 DateTimeValueRecord y_record;
3101 date_time_format_calendar, y_obj, method_name),
3104 std::unique_ptr<icu::DateIntervalFormat>
format(
3105 LazyCreateDateIntervalFormat(isolate, date_time_format, x_record.kind));
3106 if (format.get() ==
nullptr) {
3111 date_time_format->icu_simple_date_format()->raw()->getCalendar();
3113 std::optional<MaybeDirectHandle<T>>
result = CallICUFormatRange<T, Format>(
3114 isolate, format.get(),
calendar, x_record.epoch_milliseconds,
3115 y_record.epoch_milliseconds);
3118 x_record.epoch_milliseconds);
3121template <
typename T,
3122 std::optional<MaybeDirectHandle<T>> (*Format)(
3123 Isolate*,
const icu::FormattedValue&),
3124 MaybeDirectHandle<T> (*Fallback)(
3125 Isolate*,
const icu::SimpleDateFormat&, double)>
3126MaybeDirectHandle<T> FormatRangeCommon(
3127 Isolate* isolate, DirectHandle<JSDateTimeFormat> date_time_format,
3128 DirectHandle<Object> x_obj, DirectHandle<Object> y_obj,
3129 const char* method_name) {
3137 std::optional<MaybeDirectHandle<T>>
result =
3138 PartitionDateTimeRangePattern<T, Format>(isolate, date_time_format,
x,
y,
3141 return Fallback(isolate, *(date_time_format->icu_simple_date_format()->raw()),
3154 return FormatRangeCommonWithTemporalSupport<
3156 isolate, date_time_format,
x,
y, method_name);
3159 return FormatRangeCommon<String, FormattedToString, FormatDateTime>(
3160 isolate, date_time_format,
x,
y, method_name);
3170 return FormatRangeCommonWithTemporalSupport<
3171 JSArray, FormattedDateIntervalToJSArray,
3172 FormatMillisecondsByKindToArrayOutputSource>(
isolate, date_time_format,
3176 return FormatRangeCommon<
JSArray, FormattedDateIntervalToJSArray,
3177 FormatMillisecondsToArrayOutputSource>(
3178 isolate, date_time_format,
x,
y, method_name);
#define DEFINE_BIT_FIELDS(LIST_MACRO)
@ kDateTimeFormatDateTimeStyle
V8_INLINE T FromJust() const &
V8_INLINE bool IsNothing() const
static MaybeHandle< BigInt > Divide(Isolate *isolate, DirectHandle< BigInt > x, DirectHandle< BigInt > y)
static V8_EXPORT_PRIVATE Handle< BigInt > FromInt64(Isolate *isolate, int64_t n)
static bool TryTimeClip(double *time)
V8_INLINE bool is_null() const
Handle< Number > NewNumberFromInt(int32_t value)
Handle< String > NewStringFromAsciiChecked(const char *str, AllocationType allocation=AllocationType::kYoung)
DirectHandle< Number > NewNumberFromInt64(int64_t value)
Handle< JSArray > NewJSArray(ElementsKind elements_kind, int length, int capacity, ArrayStorageAllocationMode mode=ArrayStorageAllocationMode::DONT_INITIALIZE_ARRAY_ELEMENTS, AllocationType allocation=AllocationType::kYoung)
Handle< JSObject > NewJSObject(DirectHandle< JSFunction > constructor, AllocationType allocation=AllocationType::kYoung, NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Handle< String > NewStringFromStaticChars(const char(&str)[N], AllocationType allocation=AllocationType::kYoung)
static void AddElement(Isolate *isolate, DirectHandle< JSArray > array, int index, DirectHandle< String > field_type_string, DirectHandle< String > value)
static bool IsValidCalendar(const icu::Locale &locale, const std::string &value)
static std::string GetNumberingSystem(const icu::Locale &icu_locale)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > LegacyUnwrapReceiver(Isolate *isolate, DirectHandle< JSReceiver > receiver, DirectHandle< JSFunction > constructor, bool has_initialized_slot)
static V8_WARN_UNUSED_RESULT MaybeHandle< String > ToString(Isolate *isolate, const icu::UnicodeString &string)
static Maybe< std::vector< std::string > > CanonicalizeLocaleList(Isolate *isolate, DirectHandle< Object > locales, bool only_return_one_result=false)
static const std::set< std::string > & GetAvailableLocalesForDateFormat()
static DirectHandle< String > DefaultTimeZone(Isolate *isolate)
static Maybe< ResolvedLocale > ResolveLocale(Isolate *isolate, const std::set< std::string > &available_locales, const std::vector< std::string > &requested_locales, MatcherOption options, const std::set< std::string > &relevant_extension_keys)
static V8_WARN_UNUSED_RESULT bool IsValidTimeZoneName(const icu::TimeZone &tz)
static V8_WARN_UNUSED_RESULT Maybe< MatcherOption > GetLocaleMatcher(Isolate *isolate, DirectHandle< JSReceiver > options, const char *method_name)
static bool IsWellFormedCalendar(const std::string &value)
static Maybe< std::string > ToLanguageTag(const icu::Locale &locale)
static bool IsValidNumberingSystem(const std::string &value)
static DirectHandle< String > SourceString(Isolate *isolate, FormatRangeSource source)
static int64_t CurrentTimeValue(Isolate *isolate)
static V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT MaybeHandle< Map > GetDerivedMap(Isolate *isolate, DirectHandle< JSFunction > constructor, DirectHandle< JSReceiver > new_target)
static void ValidateElements(Tagged< JSObject > object)
static V8_WARN_UNUSED_RESULT Maybe< bool > CreateDataProperty(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Name > key, DirectHandle< Object > value, Maybe< ShouldThrow > should_throw)
static DirectHandle< Managed< CppType > > From(Isolate *isolate, size_t estimated_size, std::shared_ptr< CppType > shared_ptr, AllocationType allocation_type=AllocationType::kYoung)
static V8_WARN_UNUSED_RESULT HandleType< String >::MaybeType ToString(Isolate *isolate, HandleType< T > input)
static V8_WARN_UNUSED_RESULT MaybeHandle< Object > GetPropertyOrElement(Isolate *isolate, DirectHandle< JSAny > object, DirectHandle< Name > name)
static V8_WARN_UNUSED_RESULT HandleType< Number >::MaybeType ToNumber(Isolate *isolate, HandleType< T > input)
static double NumberValue(Tagged< Number > obj)
base::uc16 Get(uint32_t i) const
static V8_INLINE HandleType< String > Flatten(Isolate *isolate, HandleType< T > string, AllocationType allocation=AllocationType::kYoung)
bool Equals(Tagged< String > other) const
static V8_EXPORT_PRIVATE void FatalProcessOutOfMemory(Isolate *isolate, const char *location, const OOMDetails &details=kNoOOMDetails)
#define THROW_NEW_ERROR_RETURN_VALUE(isolate, call, value)
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
#define THROW_NEW_ERROR(isolate, call)
#define ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
#define MAYBE_RETURN(call, value)
#define MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
DirectHandle< JSReceiver > options
DirectHandle< Object > calendar
ZoneVector< RpoNumber > & result
#define LAZY_INSTANCE_INITIALIZER
constexpr bool IsInRange(T value, U lower_limit, U higher_limit)
LockGuard< Mutex > MutexGuard
void Add(RWDigits Z, Digits X, Digits Y)
V8_INLINE const Operation & Get(const Graph &graph, OpIndex index)
MaybeDirectHandle< JSTemporalTimeZone > CreateTemporalTimeZone(Isolate *isolate, DirectHandle< String > identifier)
MaybeDirectHandle< JSTemporalPlainDateTime > CreateTemporalDateTime(Isolate *isolate, const DateTimeRecord &date_time, DirectHandle< JSReceiver > calendar)
MaybeDirectHandle< JSTemporalInstant > CreateTemporalInstant(Isolate *isolate, DirectHandle< JSFunction > target, DirectHandle< HeapObject > new_target, DirectHandle< BigInt > epoch_nanoseconds)
MaybeDirectHandle< JSTemporalCalendar > GetBuiltinCalendar(Isolate *isolate, DirectHandle< String > id)
MaybeDirectHandle< JSTemporalInstant > BuiltinTimeZoneGetInstantForCompatible(Isolate *isolate, DirectHandle< JSReceiver > time_zone, DirectHandle< JSTemporalPlainDateTime > date_time, const char *method_name)
DirectHandle< JSTemporalCalendar > GetISO8601Calendar(Isolate *isolate)
MaybeDirectHandle< String > FormattedToString(Isolate *isolate, const icu::FormattedValue &formatted, const std::vector< std::vector< Part > > *parts, JSDurationFormat::Separator)
bool IsNumber(Tagged< Object > obj)
Tagged(T object) -> Tagged< T >
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
V8_EXPORT_PRIVATE FlagValues v8_flags
V8_WARN_UNUSED_RESULT Maybe< bool > GetBoolOption(Isolate *isolate, DirectHandle< JSReceiver > options, const char *property, const char *method_name, bool *result)
Maybe< int > GetNumberOption(Isolate *isolate, DirectHandle< JSReceiver > options, DirectHandle< String > property, int min, int max, int fallback)
MaybeDirectHandle< JSReceiver > CoerceOptionsToObject(Isolate *isolate, DirectHandle< Object > options, const char *method_name)
std::optional< std::string > GetOffsetTimeZone(Isolate *isolate, DirectHandle< String > time_zone)
Maybe< bool > GetStringOption(Isolate *isolate, DirectHandle< JSReceiver > options, const char *property, const std::vector< const char * > &values, const char *method_name, std::unique_ptr< char[]> *result)
V8_EXPORT_PRIVATE void V8_EXPORT_PRIVATE void const char * format
!IsContextMap !IsContextMap native_context
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Maybe< T > Just(const T &t)
#define DCHECK_LE(v1, v2)
#define DCHECK_NOT_NULL(val)
#define DCHECK_NE(v1, v2)
#define DCHECK(condition)
typename LazyStaticInstance< T, CreateTrait, InitOnceTrait, DestroyTrait >::type type