v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
js-duration-format.cc
Go to the documentation of this file.
1// Copyright 2022 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_INTL_SUPPORT
6#error Internationalization is expected to be enabled.
7#endif // V8_INTL_SUPPORT
8
10
11#include <map>
12#include <memory>
13#include <string>
14#include <string_view>
15
16#include "src/common/globals.h"
18#include "src/heap/factory.h"
26#pragma GCC diagnostic push
27#pragma GCC diagnostic ignored "-Wshadow"
28#include "unicode/dtfmtsym.h"
29#include "unicode/listformatter.h"
30#include "unicode/locid.h"
31#include "unicode/numberformatter.h"
32#include "unicode/ulistformatter.h"
33#include "unicode/unumberformatter.h"
34#pragma GCC diagnostic pop
35
36namespace v8 {
37namespace internal {
38
39using temporal::DurationRecord;
40
41namespace {
42
43// #sec-getdurationunitoptions
44enum class StylesList { k3Styles, k4Styles, k5Styles };
45enum class Unit {
46 kYears,
47 kMonths,
48 kWeeks,
49 kDays,
50 kHours,
51 kMinutes,
52 kSeconds,
53 kMilliseconds,
54 kMicroseconds,
55 kNanoseconds
56};
57struct DurationUnitOptions {
60};
61
62const std::initializer_list<const char*> kLongShortNarrowStrings = {
63 "long", "short", "narrow"};
64const std::initializer_list<const char*> kLongShortNarrowNumericStrings = {
65 "long", "short", "narrow", "numeric"};
66const std::initializer_list<const char*> kLongShortNarrowNumeric2DigitStrings =
67 {"long", "short", "narrow", "numeric", "2-digit"};
68
69const std::initializer_list<JSDurationFormat::FieldStyle>
70 kLongShortNarrowEnums = {JSDurationFormat::FieldStyle::kLong,
73const std::initializer_list<JSDurationFormat::FieldStyle>
74 kLongShortNarrowNumericEnums = {JSDurationFormat::FieldStyle::kLong,
78const std::initializer_list<JSDurationFormat::FieldStyle>
79 kLongShortNarrowNumeric2DigitEnums = {
85
86Maybe<DurationUnitOptions> GetDurationUnitOptions(
87 Isolate* isolate, Unit unit, const char* unit_string,
88 const char* display_field, DirectHandle<JSReceiver> options,
89 JSDurationFormat::Style base_style,
90 const std::vector<const char*>& value_strings,
91 const std::vector<JSDurationFormat::FieldStyle>& value_enums,
94 const char* method_name = "Intl.DurationFormat";
96 // 1. Let style be ? GetOption(options, unit, "string", stylesList,
97 // undefined).
99 isolate, style,
101 isolate, options, unit_string, method_name, value_strings,
104
105 // 2. Let displayDefault be "always".
106 JSDurationFormat::Display display_default =
108 // 3. If style is undefined, then
110 // a. If baseStyle is "digital", then
111 if (base_style == JSDurationFormat::Style::kDigital) {
112 // i. If unit is not one of "hours", "minutes", or "seconds", then
113 if (unit != Unit::kHours && unit != Unit::kMinutes &&
114 unit != Unit::kSeconds) {
115 // a. Set displayDefault to "auto".
116 display_default = JSDurationFormat::Display::kAuto;
117 }
118 // ii. Set style to digitalBase.
119 style = digital_base;
120 // b. Else
121 } else {
122 // i. if prevStyle is "fractional", "numeric", or "2-digit", then
126 // 1. If unit is not one of "minutes" or "seconds", then
127 if (unit != Unit::kMinutes && unit != Unit::kSeconds) {
128 // a. Set displayDefault to "auto".
129 display_default = JSDurationFormat::Display::kAuto;
130 }
131 // 2. Set style to "numeric".
133 // iii. Else,
134 } else {
135 // 1. Set displayDefault to "auto".
136 display_default = JSDurationFormat::Display::kAuto;
137 // 2. Set style to baseStyle.
138 switch (base_style) {
141 break;
144 break;
147 break;
148 default:
149 UNREACHABLE();
150 }
151 }
152 }
153 }
154 // 4. If style is "numeric", then
156 // a. If unit is one of "milliseconds", "microseconds", or "nanoseconds",
157 // then
158 if (unit == Unit::kMilliseconds || unit == Unit::kMicroseconds ||
159 unit == Unit::kNanoseconds) {
160 // i. Set style to "fractional".
162 // ii. Set displayDefault to "auto".
163 display_default = JSDurationFormat::Display::kAuto;
164 }
165 }
166 // 5. Let displayField be the string-concatenation of unit and "Display".
167 // 6. Let display be ? GetOption(options, displayField, "string", « "auto",
168 // "always" », displayDefault).
171 isolate, display,
173 isolate, options, display_field, method_name, {"auto", "always"},
176 display_default),
178 // 7. If display is "always" and style is "fractional", then
181 // a. Throw a RangeError exception.
183 isolate,
184 NewRangeError(MessageTemplate::kInvalid,
185 isolate->factory()->object_string(), options),
187 }
188 // 8. If prevStyle is "fractional", then
190 // a. If style is not "fractional", then
192 // i. Throw a RangeError exception.
194 isolate,
195 NewRangeError(MessageTemplate::kInvalid,
196 isolate->factory()->object_string(), options),
198 }
199 }
200 // 7. If prevStyle is "numeric" or "2-digit", then
201 if (prev_style == JSDurationFormat::FieldStyle::kNumeric ||
203 // a. If style is not "fractional", "numeric" or "2-digit", then
207 // i. Throw a RangeError exception.
209 isolate,
210 NewRangeError(MessageTemplate::kInvalid,
211 isolate->factory()->object_string(), options),
213 }
214 // b. If unit is "minutes" or "seconds", then
215 if (unit == Unit::kMinutes || unit == Unit::kSeconds) {
216 // i. Set style to "2-digit".
218 }
219 }
220 // 8. Return the Record { [[Style]]: style, [[Display]]: display }.
221 return Just(DurationUnitOptions({style, display}));
222}
223
224JSDurationFormat::Separator GetSeparator(const icu::Locale& l) {
225 UErrorCode status = U_ZERO_ERROR;
226 icu::DateFormatSymbols sym(l, status);
227 if (U_FAILURE(status)) return JSDurationFormat::Separator::kColon;
228 icu::UnicodeString sep;
229 sym.getTimeSeparatorString(sep);
230 if (sep.length() != 1) return JSDurationFormat::Separator::kColon;
231 switch (sep.charAt(0)) {
232 case u'.':
234 case u'\uFF1A':
236 case u'\u066B':
238 // By default, or if we get anything else, just use ':'.
239 default:
241 }
242}
243
244} // namespace
246 Isolate* isolate, DirectHandle<Map> map, DirectHandle<Object> locales,
247 DirectHandle<Object> input_options) {
248 Factory* factory = isolate->factory();
249 const char* method_name = "Intl.DurationFormat";
250
251 // 3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
252 std::vector<std::string> requested_locales;
254 isolate, requested_locales,
255 Intl::CanonicalizeLocaleList(isolate, locales),
257
258 // 4. Let options be ? GetOptionsObject(options).
261 isolate, options, GetOptionsObject(isolate, input_options, method_name));
262
263 // 5. Let matcher be ? GetOption(options, "localeMatcher", "string", «
264 // "lookup", "best fit" », "best fit").
265 Intl::MatcherOption matcher;
267 isolate, matcher, Intl::GetLocaleMatcher(isolate, options, method_name),
269
270 // 6. Let numberingSystem be ? GetOption(options, "numberingSystem", "string",
271 // undefined, undefined).
272 //
273 // 7. If numberingSystem is not undefined, then
274 //
275 // a. If numberingSystem does not match the Unicode Locale Identifier type
276 // nonterminal, throw a RangeError exception.
277 // Note: The matching test and throw in Step 7-a is throw inside
278 // Intl::GetNumberingSystem.
279 std::unique_ptr<char[]> numbering_system_str = nullptr;
280 bool get;
282 isolate, get,
283 Intl::GetNumberingSystem(isolate, options, method_name,
284 &numbering_system_str),
286
287 // 8. Let opt be the Record { [[localeMatcher]]: matcher, [[nu]]:
288 // numberingSystem }.
289 // 9. Let r be ResolveLocale(%DurationFormat%.[[AvailableLocales]],
290 // requestedLocales, opt, %DurationFormat%.[[RelevantExtensionKeys]],
291 // %DurationFormat%.[[LocaleData]]).
292 std::set<std::string> relevant_extension_keys{"nu"};
295 isolate, r,
297 requested_locales, matcher, relevant_extension_keys),
299
300 // 10. Let locale be r.[[locale]].
301 icu::Locale r_locale = r.icu_locale;
302 UErrorCode status = U_ZERO_ERROR;
303 // 11. Set durationFormat.[[Locale]] to locale.
304 // 12. Set durationFormat.[[NumberingSystem]] to r.[[nu]].
305 if (numbering_system_str != nullptr) {
306 auto nu_extension_it = r.extensions.find("nu");
307 if (nu_extension_it != r.extensions.end() &&
308 nu_extension_it->second != numbering_system_str.get()) {
309 r_locale.setUnicodeKeywordValue("nu", nullptr, status);
310 DCHECK(U_SUCCESS(status));
311 }
312 }
313 icu::Locale icu_locale = r_locale;
314 if (numbering_system_str != nullptr &&
315 Intl::IsValidNumberingSystem(numbering_system_str.get())) {
316 r_locale.setUnicodeKeywordValue("nu", numbering_system_str.get(), status);
317 DCHECK(U_SUCCESS(status));
318 }
319 std::string numbering_system = Intl::GetNumberingSystem(r_locale);
320 Separator separator = GetSeparator(r_locale);
321
322 // 13. Let style be ? GetOption(options, "style", "string", « "long", "short",
323 // "narrow", "digital" », "long").
324 Style style;
326 isolate, style,
328 isolate, options, "style", method_name,
329 {"long", "short", "narrow", "digital"},
333
334 // 14. Set durationFormat.[[Style]] to style.
335 // 15. Set durationFormat.[[DataLocale]] to r.[[dataLocale]].
336 DirectHandle<Managed<icu::Locale>> managed_locale =
338 isolate, 0, std::shared_ptr<icu::Locale>{icu_locale.clone()});
339 // 16. Let prevStyle be the empty String.
340 // 17. For each row of Table 1, except the header row, in table order, do
341 // a. Let styleSlot be the Style Slot value of the current row.
342 // b. Let displaySlot be the Display Slot value of the current row.
343 // c. Let unit be the Unit value.
344 // d. Let valueList be the Values value.
345 // e. Let digitalBase be the Digital Default value.
346 // f. Let unitOptions be ? GetDurationUnitOptions(unit, options, style,
347 // valueList, digitalBase, prevStyle).
348 // of durationFormat to unitOptions.[[Style]].
349 // h. Set the value of the
350 // displaySlot slot of durationFormat to unitOptions.[[Display]].
351 // i. If unit is one of "hours", "minutes", "seconds", "milliseconds",
352 // or "microseconds", then
353 // i. Set prevStyle to unitOptions.[[Style]].
354 // g. Set the value of the styleSlot slot
355 DurationUnitOptions years_option;
356 DurationUnitOptions months_option;
357 DurationUnitOptions weeks_option;
358 DurationUnitOptions days_option;
359 DurationUnitOptions hours_option;
360 DurationUnitOptions minutes_option;
361 DurationUnitOptions seconds_option;
362 DurationUnitOptions milliseconds_option;
363 DurationUnitOptions microseconds_option;
364 DurationUnitOptions nanoseconds_option;
365
366#define CALL_GET_DURATION_UNIT_OPTIONS(unit, property, strings, enums, \
367 digital_base, prev_style) \
368 MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE( \
369 isolate, property##_option, \
370 GetDurationUnitOptions( \
371 isolate, Unit::unit, #property, #property "Display", options, style, \
372 strings, enums, JSDurationFormat::FieldStyle::digital_base, \
373 prev_style), \
374 DirectHandle<JSDurationFormat>());
375
376 // #table-durationformat
377 // Table 3: Internal slots and property names of DurationFormat instances
378 // relevant to Intl.DurationFormat constructor
379 // [[YearsStyle]] [[YearsDisplay]] "years" « "long", "short",
380 // "narrow" » "short"
381 CALL_GET_DURATION_UNIT_OPTIONS(kYears, years, kLongShortNarrowStrings,
382 kLongShortNarrowEnums, kShort,
384 // [[MonthsStyle]] [[MonthsDisplay]] "months" « "long",
385 // "short", "narrow" » "short"
386 CALL_GET_DURATION_UNIT_OPTIONS(kMonths, months, kLongShortNarrowStrings,
387 kLongShortNarrowEnums, kShort,
388 years_option.style)
389 // [[WeeksStyle]] [[WeeksDisplay]] "weeks" « "long", "short",
390 // "narrow" » "short"
391 CALL_GET_DURATION_UNIT_OPTIONS(kWeeks, weeks, kLongShortNarrowStrings,
392 kLongShortNarrowEnums, kShort,
393 months_option.style)
394 // [[DaysStyle]] [[DaysDisplay]] "days" « "long", "short", "narrow" »
395 // "short"
396 CALL_GET_DURATION_UNIT_OPTIONS(kDays, days, kLongShortNarrowStrings,
397 kLongShortNarrowEnums, kShort,
398 weeks_option.style)
399
400 // [[HoursStyle]] [[HoursDisplay]] "hours" « "long", "short",
401 // "narrow", "numeric", "2-digit" » "numeric"
403 kHours, hours, kLongShortNarrowNumeric2DigitStrings,
404 kLongShortNarrowNumeric2DigitEnums, kNumeric, days_option.style)
405 // [[MinutesStyle]] [[MinutesDisplay]] "minutes" « "long",
406 // "short", "narrow", "numeric", "2-digit" » "numeric"
408 kMinutes, minutes, kLongShortNarrowNumeric2DigitStrings,
409 kLongShortNarrowNumeric2DigitEnums, kNumeric, hours_option.style)
410
411 // [[SecondsStyle]] [[SecondsDisplay]] "seconds" « "long",
412 // "short", "narrow", "numeric", "2-digit" »
414 kSeconds, seconds, kLongShortNarrowNumeric2DigitStrings,
415 kLongShortNarrowNumeric2DigitEnums, kNumeric, minutes_option.style)
416
417 // [[MillisecondsStyle]] [[MillisecondsDisplay]] "milliseconds" «
418 // "long", "short", "narrow", "numeric" » "numeric"
420 kMilliseconds, milliseconds, kLongShortNarrowNumericStrings,
421 kLongShortNarrowNumericEnums, kNumeric, seconds_option.style)
422
423 // [[MicrosecondsStyle]] [[MicrosecondsDisplay]] "microseconds" «
424 // "long", "short", "narrow", "numeric" » "numeric"
426 kMicroseconds, microseconds, kLongShortNarrowNumericStrings,
427 kLongShortNarrowNumericEnums, kNumeric, milliseconds_option.style)
428
429 // [[NanosecondsStyle]] [[NanosecondsDisplay]] "nanoseconds" «
430 // "long", "short", "narrow", "numeric" » "numeric"
432 kNanoseconds, nanoseconds, kLongShortNarrowNumericStrings,
433 kLongShortNarrowNumericEnums, kNumeric, microseconds_option.style)
434
435#undef CALL_GET_DURATION_UNIT_OPTIONS
436 // 18. Set durationFormat.[[FractionalDigits]] to ? GetNumberOption(options,
437 // "fractionalDigits", 0, 9, undefined).
440 isolate, fractional_digits,
441 GetNumberOption(isolate, options, factory->fractionalDigits_string(), 0,
444
445 icu::number::LocalizedNumberFormatter fmt =
446 icu::number::UnlocalizedNumberFormatter()
447 .roundingMode(UNUM_ROUND_HALFUP)
448 .locale(icu_locale);
449 if (!numbering_system.empty() && numbering_system != "latn") {
450 fmt = fmt.adoptSymbols(icu::NumberingSystem::createInstanceByName(
451 numbering_system.c_str(), status));
452 DCHECK(U_SUCCESS(status));
453 }
455 managed_number_formatter =
457 isolate, 0,
458 std::make_shared<icu::number::LocalizedNumberFormatter>(fmt));
459
460 // 19. Return durationFormat.
461 DirectHandle<JSDurationFormat> duration_format =
463 duration_format->set_style_flags(0);
464 duration_format->set_display_flags(0);
465 duration_format->set_style(style);
466 duration_format->set_years_style(years_option.style);
467 duration_format->set_months_style(months_option.style);
468 duration_format->set_weeks_style(weeks_option.style);
469 duration_format->set_days_style(days_option.style);
470 duration_format->set_hours_style(hours_option.style);
471 duration_format->set_minutes_style(minutes_option.style);
472 duration_format->set_seconds_style(seconds_option.style);
473 duration_format->set_milliseconds_style(milliseconds_option.style);
474 duration_format->set_microseconds_style(microseconds_option.style);
475 duration_format->set_nanoseconds_style(nanoseconds_option.style);
476 duration_format->set_separator(separator);
477
478 duration_format->set_years_display(years_option.display);
479 duration_format->set_months_display(months_option.display);
480 duration_format->set_weeks_display(weeks_option.display);
481 duration_format->set_days_display(days_option.display);
482 duration_format->set_hours_display(hours_option.display);
483 duration_format->set_minutes_display(minutes_option.display);
484 duration_format->set_seconds_display(seconds_option.display);
485 duration_format->set_milliseconds_display(milliseconds_option.display);
486 duration_format->set_microseconds_display(microseconds_option.display);
487 duration_format->set_nanoseconds_display(nanoseconds_option.display);
488
489 duration_format->set_fractional_digits(fractional_digits);
490
491 duration_format->set_icu_locale(*managed_locale);
492 duration_format->set_icu_number_formatter(*managed_number_formatter);
493
494 return duration_format;
495}
496
497namespace {
498
499DirectHandle<String> StyleToString(Isolate* isolate,
501 switch (style) {
503 return isolate->factory()->long_string();
505 return isolate->factory()->short_string();
507 return isolate->factory()->narrow_string();
509 return isolate->factory()->digital_string();
510 }
511 // Avoid undefined behavior for enum values not handled by the exhaustive
512 // switch, since they're read from inside the sandbox.
513 SBXCHECK(false);
514}
515
516DirectHandle<String> StyleToString(Isolate* isolate,
518 switch (style) {
520 return isolate->factory()->long_string();
522 return isolate->factory()->short_string();
524 return isolate->factory()->narrow_string();
526 return isolate->factory()->numeric_string();
528 return isolate->factory()->two_digit_string();
530 // Step 3 in Intl.DurationFormat.prototype.resolvedOptions ( )
531 // e. If v is "fractional", then
532 // ii. Set v to "numeric".
533 return isolate->factory()->numeric_string();
535 UNREACHABLE();
536 }
537 // Avoid undefined behavior for enum values not handled by the exhaustive
538 // switch, since they're read from inside the sandbox.
539 SBXCHECK(false);
540}
541
542DirectHandle<String> DisplayToString(Isolate* isolate,
544 switch (display) {
546 return isolate->factory()->auto_string();
548 return isolate->factory()->always_string();
549 }
550 // Avoid undefined behavior for enum values not handled by the exhaustive
551 // switch, since they're read from inside the sandbox.
552 SBXCHECK(false);
553}
554
555} // namespace
556
558 Isolate* isolate, DirectHandle<JSDurationFormat> format) {
559 Factory* factory = isolate->factory();
560 DirectHandle<JSObject> options =
561 factory->NewJSObject(isolate->object_function());
562
564 Intl::ToLanguageTag(*format->icu_locale()->raw()).FromJust().c_str());
565 UErrorCode status = U_ZERO_ERROR;
566 icu::UnicodeString skeleton =
567 format->icu_number_formatter()->raw()->toSkeleton(status);
568 DCHECK(U_SUCCESS(status));
569
570 DirectHandle<String> numbering_system;
571 CHECK(Intl::ToString(isolate,
573 .ToHandle(&numbering_system));
574
575 bool created;
576
577#define OUTPUT_PROPERTY(s, f) \
578 MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE( \
579 isolate, created, \
580 JSReceiver::CreateDataProperty(isolate, options, factory->s(), f, \
581 Just(kDontThrow)), \
582 DirectHandle<JSObject>()); \
583 CHECK(created);
584#define OUTPUT_STYLE_PROPERTY(p) \
585 OUTPUT_PROPERTY(p##_string, StyleToString(isolate, format->p##_style()))
586#define OUTPUT_DISPLAY_PROPERTY(p) \
587 OUTPUT_PROPERTY(p##Display_string, \
588 DisplayToString(isolate, format->p##_display()))
589#define OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(p) \
590 OUTPUT_STYLE_PROPERTY(p); \
591 OUTPUT_DISPLAY_PROPERTY(p);
592
593 // #table-durationformat-resolvedoptions-properties
594 // Table 4: Resolved Options of DurationFormat Instances
595 // [[Locale]] "locale"
596 OUTPUT_PROPERTY(locale_string, locale);
597 // [[NumberingSystem]] "numberingSystem"
598 OUTPUT_PROPERTY(numberingSystem_string, numbering_system);
599 // [[Style]] "style"
600 OUTPUT_PROPERTY(style_string, StyleToString(isolate, format->style()));
601
612
613 // [[FractionalDigits]] "fractionalDigits"
614
615 // c. If p is "fractionalDigits", then
616 int32_t fractional_digits = format->fractional_digits();
617 // i. If v is not undefined, set v to 𝔽(v).
619 DirectHandle<Smi> fractional_digits_obj =
621 // f. If v is not undefined, then
622 // i. Perform ! CreateDataPropertyOrThrow(options, p, v).
623 OUTPUT_PROPERTY(fractionalDigits_string, fractional_digits_obj);
624 }
625#undef OUTPUT_PROPERTY
626#undef OUTPUT_STYLE_PROPERTY
627#undef OUTPUT_DISPLAY_PROPERTY
628#undef OUTPUT_STYLE_AND_DISPLAY_PROPERTIES
629
630 return options;
631}
632
633namespace {
634
635UNumberUnitWidth ToUNumberUnitWidth(JSDurationFormat::FieldStyle style) {
636 switch (style) {
638 return UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT;
640 return UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME;
642 return UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW;
643 default:
644 UNREACHABLE();
645 }
646 // Avoid undefined behavior for enum values not handled by the exhaustive
647 // switch, since they're read from inside the sandbox.
648 SBXCHECK(false);
649}
650
651struct Part {
652 enum Type { kFormatted, kSeparator };
654 std::string type;
655 icu::number::FormattedNumber formatted;
656};
657
658char16_t SeparatorToChar(JSDurationFormat::Separator separator) {
659 switch (separator) {
661 return u':';
663 return u'.';
665 return u'\uFF1A';
667 return u'\u066B';
668 }
669}
670
671bool FormattedToParts(const char*, icu::number::FormattedNumber&, bool, bool,
673 std::vector<std::vector<Part>>*,
674 std::vector<icu::UnicodeString>*);
675
676bool Output(const char* type, double value,
677 const icu::number::LocalizedNumberFormatter& fmt, bool addToLast,
678 bool display_negative_sign, bool negative_duration,
680 std::vector<std::vector<Part>>* parts,
681 std::vector<icu::UnicodeString>* strings) {
682 icu::number::LocalizedNumberFormatter nfOpts(fmt);
683 // i. If displayNegativeSign is true, then
684 if (display_negative_sign) {
685 // 1. Set displayNegativeSign to false.
686 display_negative_sign = false;
687 // 2. If value is 0 and DurationRecordSign(duration) is -1, then
688 if (value == 0.0 && negative_duration) {
689 // a. Set value to negative-zero.
690 value = -0.0;
691 }
692 } else { // ii. Else,
693 // 1. Perform ! CreateDataPropertyOrThrow(nfOpts, "signDisplay", "never").
694 nfOpts = nfOpts.sign(UNumberSignDisplay::UNUM_SIGN_NEVER);
695 }
696
697 UErrorCode status = U_ZERO_ERROR;
698 icu::number::FormattedNumber formatted = nfOpts.formatDouble(value, status);
699 DCHECK(U_SUCCESS(status));
700 return FormattedToParts(type, formatted, addToLast, display_negative_sign,
701 separator, parts, strings);
702}
703
704bool FormattedToParts(const char* type, icu::number::FormattedNumber& formatted,
705 bool addToLast, bool display_negative_sign,
707 std::vector<std::vector<Part>>* parts,
708 std::vector<icu::UnicodeString>* strings) {
709 UErrorCode status = U_ZERO_ERROR;
710 icu::UnicodeString unit_string = formatted.toString(status);
711 DCHECK(U_SUCCESS(status));
712 Part p = {Part::Type::kFormatted, std::string(type), std::move(formatted)};
713 if (addToLast && !strings->empty()) {
714 strings->back().append(SeparatorToChar(separator));
715 strings->back() += unit_string;
716
717 if (parts != nullptr) {
718 icu::number::FormattedNumber dummy;
719 Part s = {Part::Type::kSeparator, std::string(), std::move(dummy)};
720 parts->back().push_back(std::move(s));
721 parts->back().push_back(std::move(p));
722 }
723 return display_negative_sign;
724 }
725 strings->push_back(unit_string);
726 if (parts != nullptr) {
727 std::vector<Part> v;
728 v.push_back(std::move(p));
729 parts->push_back(std::move(v));
730 }
731 return display_negative_sign;
732}
733
734bool OutputLongShortOrNarrow(const char* type, double value,
736 const icu::number::LocalizedNumberFormatter& fmt,
737 bool addToLast, bool display_negative_sign,
738 bool negative_duration,
740 std::vector<std::vector<Part>>* parts,
741 std::vector<icu::UnicodeString>* strings) {
742 if (value == 0 && display == JSDurationFormat::Display::kAuto)
743 return display_negative_sign;
744 return Output(type, value, fmt, addToLast, display_negative_sign,
745 negative_duration, separator, parts, strings);
746}
747
748bool OutputLongShortNarrowOrNumeric(
749 const char* type, double value, JSDurationFormat::Display display,
751 const icu::number::LocalizedNumberFormatter& fmt, icu::MeasureUnit unit,
752 bool addToLast, bool display_negative_sign, bool negative_duration,
754 std::vector<std::vector<Part>>* parts,
755 std::vector<icu::UnicodeString>* strings) {
756 if (value == 0 && display == JSDurationFormat::Display::kAuto)
757 return display_negative_sign;
759 return Output(type, value,
760 fmt.grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF),
761 addToLast, display_negative_sign, negative_duration,
762 separator, parts, strings);
763 }
764 return OutputLongShortOrNarrow(
765 type, value, display, fmt.unit(unit).unitWidth(ToUNumberUnitWidth(style)),
766 addToLast, display_negative_sign, negative_duration, separator, parts,
767 strings);
768}
769
770bool OutputLongShortNarrowNumericOr2Digit(
771 const char* type, double value, JSDurationFormat::Display display,
773 const icu::number::LocalizedNumberFormatter& fmt, icu::MeasureUnit unit,
774 bool maybeAddToLast, bool displayRequired, bool display_negative_sign,
775 bool negative_duration, JSDurationFormat::Separator separator,
776 std::vector<std::vector<Part>>* parts,
777 std::vector<icu::UnicodeString>* strings) {
778 // k. If value is not 0 or display is not "auto" or displayRequired is "true",
779 // then
780 if ((value != 0) || (display != JSDurationFormat::Display::kAuto) ||
781 displayRequired) {
783 return Output(type, value,
784 fmt.integerWidth(icu::number::IntegerWidth::zeroFillTo(2))
785 .grouping(UNumberGroupingStrategy::UNUM_GROUPING_OFF),
786 maybeAddToLast, display_negative_sign, negative_duration,
787 separator, parts, strings);
788 }
789 bool addToLast =
790 maybeAddToLast && (JSDurationFormat::FieldStyle::kNumeric == style);
791 return OutputLongShortNarrowOrNumeric(
792 type, value, display, style, fmt, unit, addToLast,
793 display_negative_sign, negative_duration, separator, parts, strings);
794 }
795 return display_negative_sign;
796}
797
798bool DisplayRequired(DirectHandle<JSDurationFormat> df,
799 const DurationRecord& record) {
800 // 9-h. Let displayRequired be "false".
801 // 9-i. Let hoursStyle be durationFormat.[[HoursStyle]].
802 // 9-j-i. If hoursStyle is "numeric" or "2-digit", then
803 if (df->hours_style() == JSDurationFormat::FieldStyle::kNumeric ||
804 df->hours_style() == JSDurationFormat::FieldStyle::k2Digit) {
805 // 1. Let hoursDisplay be durationFormat.[[HoursDisplay]].
806 // 2. Let hoursValue be durationFormat.[[HoursValue]].
807 // 3. If hoursDisplay is "always" or hoursValue is not 0, then
808 if (df->hours_display() == JSDurationFormat::Display::kAlways ||
810 // a. Let secondsDisplay be durationFormat.[[SecondsDisplay]].
811 // c. If secondsDisplay is "always" or duration.[[Second]] is not 0, or
812 // duration.[[Milliseconds]] is not 0, or duration.[[Microseconds]] is not
813 // 0, or duration.[[Nanoseconds]] is not 0, then
814 if (df->seconds_display() == JSDurationFormat::Display::kAlways ||
819 // i. Set displayRequired to "true".
820 return true;
821 }
822 }
823 }
824 return false;
825}
826
827void DurationRecordToListOfFormattedNumber(
828 DirectHandle<JSDurationFormat> df,
829 const icu::number::LocalizedNumberFormatter& fmt,
830 const DurationRecord& record, std::vector<std::vector<Part>>* parts,
831 std::vector<icu::UnicodeString>* strings) {
832 JSDurationFormat::Separator separator = df->separator();
833 // 4. Let displayNegativeSign be true.
834 bool display_negative_sign = true;
835 bool negative_duration = DurationRecord::Sign(record) == -1;
836
837 display_negative_sign = OutputLongShortOrNarrow(
838 "year", record.years, df->years_display(),
839 fmt.unit(icu::MeasureUnit::getYear())
840 .unitWidth(ToUNumberUnitWidth(df->years_style())),
841 false, display_negative_sign, negative_duration, separator, parts,
842 strings);
843 display_negative_sign = OutputLongShortOrNarrow(
844 "month", record.months, df->months_display(),
845 fmt.unit(icu::MeasureUnit::getMonth())
846 .unitWidth(ToUNumberUnitWidth(df->months_style())),
847 false, display_negative_sign, negative_duration, separator, parts,
848 strings);
849 display_negative_sign = OutputLongShortOrNarrow(
850 "week", record.weeks, df->weeks_display(),
851 fmt.unit(icu::MeasureUnit::getWeek())
852 .unitWidth(ToUNumberUnitWidth(df->weeks_style())),
853 false, display_negative_sign, negative_duration, separator, parts,
854 strings);
855 display_negative_sign = OutputLongShortOrNarrow(
856 "day", record.time_duration.days, df->days_display(),
857 fmt.unit(icu::MeasureUnit::getDay())
858 .unitWidth(ToUNumberUnitWidth(df->days_style())),
859 false, display_negative_sign, negative_duration, separator, parts,
860 strings);
861 display_negative_sign = OutputLongShortNarrowNumericOr2Digit(
862 "hour", record.time_duration.hours, df->hours_display(),
863 df->hours_style(), fmt, icu::MeasureUnit::getHour(), false, false,
864 display_negative_sign, negative_duration, separator, parts, strings);
865 bool minuteCouldAddToLast =
866 df->hours_style() == JSDurationFormat::FieldStyle::kNumeric ||
867 df->hours_style() == JSDurationFormat::FieldStyle::k2Digit;
868 display_negative_sign = OutputLongShortNarrowNumericOr2Digit(
869 "minute", record.time_duration.minutes, df->minutes_display(),
870 df->minutes_style(), fmt, icu::MeasureUnit::getMinute(),
871 minuteCouldAddToLast, DisplayRequired(df, record), display_negative_sign,
872 negative_duration, separator, parts, strings);
873 int32_t fractional_digits = df->fractional_digits();
874 int32_t maximumFractionDigits;
875 int32_t minimumFractionDigits;
876 // 2. If durationFormat.[[FractionalDigits]] is undefined, then
877 if (fractional_digits == JSDurationFormat::kUndefinedFractionalDigits) {
878 // a. Let maximumFractionDigits be 9𝔽.
879 maximumFractionDigits = 9;
880 // b. Let minimumFractionDigits be +0𝔽.
881 minimumFractionDigits = 0;
882 } else { // 3. Else,
883 // a. Let maximumFractionDigits be 𝔽(durationFormat.[[FractionalDigits]]).
884 maximumFractionDigits = fractional_digits;
885 // b. Let minimumFractionDigits be 𝔽(durationFormat.[[FractionalDigits]]).
886 minimumFractionDigits = fractional_digits;
887 }
888 // 4. Perform ! CreateDataPropertyOrThrow(nfOpts, "maximumFractionDigits",
889 // maximumFractionDigits ).
890 // 5. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumFractionDigits",
891 // minimumFractionDigits ).
892 icu::number::LocalizedNumberFormatter nfOps =
893 fmt.precision(icu::number::Precision::minMaxFraction(
894 minimumFractionDigits, maximumFractionDigits))
895 // 6. Perform ! CreateDataPropertyOrThrow(nfOpts, "roundingMode",
896 // "trunc").
897 .roundingMode(UNumberFormatRoundingMode::UNUM_ROUND_DOWN);
898
899 if (df->milliseconds_style() == JSDurationFormat::FieldStyle::kFractional) {
900 // 1. Set value to value + AddFractionalDigits(durationFormat, duration).
901 double value = record.time_duration.nanoseconds / 1e9 +
905
906 OutputLongShortNarrowNumericOr2Digit(
907 "second", value, df->seconds_display(), df->seconds_style(), nfOps,
908 icu::MeasureUnit::getSecond(), true, false, display_negative_sign,
909 negative_duration, separator, parts, strings);
910 return;
911 }
912 display_negative_sign = OutputLongShortNarrowNumericOr2Digit(
913 "second", record.time_duration.seconds, df->seconds_display(),
914 df->seconds_style(), fmt, icu::MeasureUnit::getSecond(), true, false,
915 display_negative_sign, negative_duration, separator, parts, strings);
916
917 if (df->microseconds_style() == JSDurationFormat::FieldStyle::kFractional) {
918 // 1. Set value to value + AddFractionalDigits(durationFormat, duration).
919 double value = record.time_duration.nanoseconds / 1e6 +
922
923 OutputLongShortNarrowOrNumeric(
924 "millisecond", value, df->milliseconds_display(),
925 df->milliseconds_style(), nfOps, icu::MeasureUnit::getMillisecond(),
926 false, display_negative_sign, negative_duration, separator, parts,
927 strings);
928 return;
929 }
930 display_negative_sign = OutputLongShortNarrowOrNumeric(
931 "millisecond", record.time_duration.milliseconds,
932 df->milliseconds_display(), df->milliseconds_style(), fmt,
933 icu::MeasureUnit::getMillisecond(), false, display_negative_sign,
934 negative_duration, separator, parts, strings);
935
936 if (df->nanoseconds_style() == JSDurationFormat::FieldStyle::kFractional) {
937 // 1. Set value to value + AddFractionalDigits(durationFormat, duration).
938 double value = record.time_duration.nanoseconds / 1e3 +
940 OutputLongShortNarrowOrNumeric(
941 "microsecond", value, df->microseconds_display(),
942 df->microseconds_style(), nfOps, icu::MeasureUnit::getMicrosecond(),
943 false, display_negative_sign, negative_duration, separator, parts,
944 strings);
945 return;
946 }
947 display_negative_sign = OutputLongShortNarrowOrNumeric(
948 "microsecond", record.time_duration.microseconds,
949 df->microseconds_display(), df->microseconds_style(), fmt,
950 icu::MeasureUnit::getMicrosecond(), false, display_negative_sign,
951 negative_duration, separator, parts, strings);
952
953 OutputLongShortNarrowOrNumeric(
954 "nanosecond", record.time_duration.nanoseconds, df->nanoseconds_display(),
955 df->nanoseconds_style(), fmt, icu::MeasureUnit::getNanosecond(), false,
956 display_negative_sign, negative_duration, separator, parts, strings);
957}
958
959UListFormatterWidth StyleToWidth(JSDurationFormat::Style style) {
960 switch (style) {
962 return ULISTFMT_WIDTH_WIDE;
964 return ULISTFMT_WIDTH_NARROW;
967 return ULISTFMT_WIDTH_SHORT;
968 }
969 UNREACHABLE();
970}
971
972// The last two arguments passed to the Format function is only needed
973// for Format function to output detail structure and not needed if the
974// Format only needs to output a String.
975template <typename T, bool Details,
976 MaybeDirectHandle<T> (*Format)(Isolate*, const icu::FormattedValue&,
977 const std::vector<std::vector<Part>>*,
979MaybeDirectHandle<T> PartitionDurationFormatPattern(
980 Isolate* isolate, DirectHandle<JSDurationFormat> df,
981 const DurationRecord& record, const char* method_name) {
982 // 4. Let lfOpts be ! OrdinaryObjectCreate(null).
983 // 5. Perform ! CreateDataPropertyOrThrow(lfOpts, "type", "unit").
984 UListFormatterType type = ULISTFMT_TYPE_UNITS;
985 // 6. Let listStyle be durationFormat.[[Style]].
986 // 7. If listStyle is "digital", then
987 // a. Set listStyle to "short".
988 // 8. Perform ! CreateDataPropertyOrThrow(lfOpts, "style", listStyle).
989 UListFormatterWidth list_style = StyleToWidth(df->style());
990 // 9. Let lf be ! Construct(%ListFormat%, « durationFormat.[[Locale]], lfOpts
991 // »).
992 UErrorCode status = U_ZERO_ERROR;
993 icu::Locale icu_locale = *df->icu_locale()->raw();
994 std::unique_ptr<icu::ListFormatter> formatter(
995 icu::ListFormatter::createInstance(icu_locale, type, list_style, status));
996 DCHECK(U_SUCCESS(status));
997
998 std::vector<std::vector<Part>> list;
999 std::vector<std::vector<Part>>* parts = Details ? &list : nullptr;
1000 std::vector<icu::UnicodeString> string_list;
1001
1002 DurationRecordToListOfFormattedNumber(
1003 df, *(df->icu_number_formatter()->raw()), record, parts, &string_list);
1004
1005 icu::FormattedList formatted = formatter->formatStringsToValue(
1006 string_list.data(), static_cast<int32_t>(string_list.size()), status);
1007 DCHECK(U_SUCCESS(status));
1008 return Format(isolate, formatted, parts, df->separator());
1009}
1010
1011// #sec-todurationrecord
1012// ToDurationRecord is almost the same as temporal::ToPartialDuration
1013// except:
1014// 1) In the beginning it will throw RangeError if the type of input is String,
1015// 2) In the end it will throw RangeError if IsValidDurationRecord return false.
1016Maybe<DurationRecord> ToDurationRecord(Isolate* isolate, Handle<Object> input,
1017 const DurationRecord& default_value) {
1018 // 1-a. If Type(input) is String, throw a RangeError exception.
1019 if (IsString(*input)) {
1021 isolate,
1022 NewRangeError(MessageTemplate::kInvalid,
1023 isolate->factory()->object_string(), input),
1025 }
1026 // Step 1-b - 23. Same as ToTemporalPartialDurationRecord.
1027 DurationRecord record;
1029 isolate, record,
1030 temporal::ToPartialDuration(isolate, input, default_value),
1032 // 24. If IsValidDurationRecord(result) is false, throw a RangeError
1033 // exception.
1034 if (!temporal::IsValidDuration(isolate, record)) {
1036 isolate,
1037 NewRangeError(MessageTemplate::kInvalid,
1038 isolate->factory()->object_string(), input),
1040 }
1041 return Just(record);
1042}
1043
1044template <typename T, bool Details,
1045 MaybeDirectHandle<T> (*Format)(Isolate*, const icu::FormattedValue&,
1046 const std::vector<std::vector<Part>>*,
1048MaybeDirectHandle<T> FormatCommon(Isolate* isolate,
1049 DirectHandle<JSDurationFormat> df,
1050 Handle<Object> duration,
1051 const char* method_name) {
1052 // 1. Let df be this value.
1053 // 2. Perform ? RequireInternalSlot(df, [[InitializedDurationFormat]]).
1054 // 3. Let record be ? ToDurationRecord(duration).
1055 DurationRecord record;
1057 isolate, record,
1058 ToDurationRecord(isolate, duration, {0, 0, 0, {0, 0, 0, 0, 0, 0, 0}}),
1059 DirectHandle<T>());
1060 // 5. Let parts be ! PartitionDurationFormatPattern(df, record).
1061 return PartitionDurationFormatPattern<T, Details, Format>(isolate, df, record,
1062 method_name);
1063}
1064
1065} // namespace
1066
1068 Isolate* isolate, const icu::FormattedValue& formatted,
1069 const std::vector<std::vector<Part>>* parts, JSDurationFormat::Separator) {
1070 DCHECK_NULL(parts);
1071 return Intl::FormattedToString(isolate, formatted);
1072}
1073
1075 Isolate* isolate, const icu::FormattedValue& formatted,
1076 const std::vector<std::vector<Part>>* parts,
1078 DCHECK_NOT_NULL(parts);
1079 Factory* factory = isolate->factory();
1080 DirectHandle<JSArray> array = factory->NewJSArray(0);
1081 icu::ConstrainedFieldPosition cfpos;
1082 cfpos.constrainCategory(UFIELD_CATEGORY_LIST);
1083 int index = 0;
1084 int part_index = 0;
1085 UErrorCode status = U_ZERO_ERROR;
1086 icu::UnicodeString string = formatted.toString(status);
1087 while (formatted.nextPosition(cfpos, status) && U_SUCCESS(status)) {
1088 if (cfpos.getField() == ULISTFMT_ELEMENT_FIELD) {
1089 for (auto& it : parts->at(part_index++)) {
1090 switch (it.part_type) {
1091 case Part::Type::kSeparator: {
1092 icu::UnicodeString sep(SeparatorToChar(separator));
1093 DirectHandle<String> separator_string;
1094 ASSIGN_RETURN_ON_EXCEPTION(isolate, separator_string,
1095 Intl::ToString(isolate, sep));
1096 Intl::AddElement(isolate, array, index++, factory->literal_string(),
1097 separator_string);
1098 } break;
1099 case Part::Type::kFormatted:
1100 DirectHandle<String> type_string =
1101 factory->NewStringFromAsciiChecked(it.type.c_str());
1102 Maybe<int> index_after_add = Intl::AddNumberElements(
1103 isolate, it.formatted, array, index, type_string);
1104 MAYBE_RETURN(index_after_add, MaybeDirectHandle<JSArray>());
1105 index = index_after_add.FromJust();
1106 break;
1107 }
1108 }
1109 } else {
1112 isolate, substring,
1113 Intl::ToString(isolate, string, cfpos.getStart(), cfpos.getLimit()));
1114 Intl::AddElement(isolate, array, index++, factory->literal_string(),
1115 substring);
1116 }
1117 }
1118 if (U_FAILURE(status)) {
1119 THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIcuError));
1120 }
1122 return array;
1123}
1124
1127 Handle<Object> duration) {
1128 const char* method_name = "Intl.DurationFormat.prototype.format";
1129 return FormatCommon<String, false, FormattedToString>(isolate, df, duration,
1130 method_name);
1131}
1132
1135 Handle<Object> duration) {
1136 const char* method_name = "Intl.DurationFormat.prototype.formatToParts";
1137 return FormatCommon<JSArray, true, FormattedListToJSArray>(
1138 isolate, df, duration, method_name);
1139}
1140
1141const std::set<std::string>& JSDurationFormat::GetAvailableLocales() {
1143}
1144
1145} // namespace internal
1146} // namespace v8
#define T
#define SBXCHECK(condition)
Definition check.h:61
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
Handle< String > NewStringFromAsciiChecked(const char *str, AllocationType allocation=AllocationType::kYoung)
Handle< JSArray > NewJSArray(ElementsKind elements_kind, int length, int capacity, ArrayStorageAllocationMode mode=ArrayStorageAllocationMode::DONT_INITIALIZE_ARRAY_ELEMENTS, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:3211
Handle< JSObject > NewJSObject(DirectHandle< JSFunction > constructor, AllocationType allocation=AllocationType::kYoung, NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
Definition factory.cc:2985
Handle< JSObject > NewFastOrSlowJSObjectFromMap(DirectHandle< Map > map, int number_of_slow_properties, AllocationType allocation=AllocationType::kYoung, DirectHandle< AllocationSite > allocation_site=DirectHandle< AllocationSite >::null(), NewJSObjectType=NewJSObjectType::kNoAPIWrapper)
static void AddElement(Isolate *isolate, DirectHandle< JSArray > array, int index, DirectHandle< String > field_type_string, DirectHandle< String > value)
static std::string GetNumberingSystem(const icu::Locale &icu_locale)
static V8_WARN_UNUSED_RESULT MaybeHandle< String > ToString(Isolate *isolate, const icu::UnicodeString &string)
static Maybe< int > AddNumberElements(Isolate *isolate, const icu::FormattedValue &formatted, DirectHandle< JSArray > result, int start_index, DirectHandle< String > unit)
static Maybe< std::vector< std::string > > CanonicalizeLocaleList(Isolate *isolate, DirectHandle< Object > locales, bool only_return_one_result=false)
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 Maybe< MatcherOption > GetLocaleMatcher(Isolate *isolate, DirectHandle< JSReceiver > options, const char *method_name)
static Maybe< std::string > ToLanguageTag(const icu::Locale &locale)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > FormattedToString(Isolate *isolate, const icu::FormattedValue &formatted)
static bool IsValidNumberingSystem(const std::string &value)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSArray > FormatToParts(Isolate *isolate, DirectHandle< JSDurationFormat > df, Handle< Object > duration)
static V8_EXPORT_PRIVATE const std::set< std::string > & GetAvailableLocales()
static const uint32_t kUndefinedFractionalDigits
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< String > Format(Isolate *isolate, DirectHandle< JSDurationFormat > df, Handle< Object > duration)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< JSDurationFormat > New(Isolate *isolate, DirectHandle< Map > map, DirectHandle< Object > locales, DirectHandle< Object > options)
static V8_WARN_UNUSED_RESULT DirectHandle< JSObject > ResolvedOptions(Isolate *isolate, DirectHandle< JSDurationFormat > format_holder)
static V8_EXPORT_PRIVATE const std::set< std::string > & GetAvailableLocales()
static const icu::UnicodeString NumberingSystemFromSkeleton(const icu::UnicodeString &skeleton)
static void ValidateElements(Tagged< JSObject > object)
static DirectHandle< Managed< CppType > > From(Isolate *isolate, size_t estimated_size, std::shared_ptr< CppType > shared_ptr, AllocationType allocation_type=AllocationType::kYoung)
Definition managed-inl.h:27
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
#define THROW_NEW_ERROR_RETURN_VALUE(isolate, call, value)
Definition isolate.h:300
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define THROW_NEW_ERROR(isolate, call)
Definition isolate.h:307
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
#define MAYBE_ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
Definition isolate.h:440
#define OUTPUT_STYLE_AND_DISPLAY_PROPERTIES(p)
JSDurationFormat::Display display
#define CALL_GET_DURATION_UNIT_OPTIONS(unit, property, strings, enums, digital_base, prev_style)
#define OUTPUT_PROPERTY(s, f)
icu::number::FormattedNumber formatted
JSDurationFormat::FieldStyle style
Type part_type
double years
DirectHandle< JSReceiver > options
double months
double weeks
double days
DurationRecord record
int r
Definition mul-fft.cc:298
int int32_t
Definition unicode.cc:40
Maybe< DurationRecord > ToPartialDuration(Isolate *isolate, DirectHandle< Object > temporal_duration_like_obj, const DurationRecord &input)
bool IsValidDuration(Isolate *isolate, const DurationRecord &dur)
MaybeDirectHandle< String > FormattedToString(Isolate *isolate, const icu::FormattedValue &formatted, const std::vector< std::vector< Part > > *parts, JSDurationFormat::Separator)
MaybeDirectHandle< JSReceiver > GetOptionsObject(Isolate *isolate, DirectHandle< Object > options, const char *method_name)
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
Maybe< int > GetNumberOption(Isolate *isolate, DirectHandle< JSReceiver > options, DirectHandle< String > property, int min, int max, int fallback)
MaybeDirectHandle< JSArray > FormattedListToJSArray(Isolate *isolate, const icu::FormattedValue &formatted, const std::vector< std::vector< Part > > *parts, JSDurationFormat::Separator separator)
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)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Maybe< T > Nothing()
Definition v8-maybe.h:112
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
uint32_t substring
#define DCHECK_NULL(val)
Definition logging.h:491
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
static int32_t Sign(const DurationRecord &dur)