Skip to content

Commit

Permalink
Revert "Disable DateTimeFormat::formatToParts for Apple platform (#1155
Browse files Browse the repository at this point in the history
…)" (#1567) (#1567)

Summary:
Original Author: [email protected]
Original Git: ac557bb
Original Reviewed By: blakef
Original Revision: D66099176

This reverts commit c5a633f.

That commit removed the Intl.DateTimeFormat.formatToParts for Apple platforms from Hermes.
However, the community started depending on it, and we ended up manually reverting that commit in the release branch for the past 3 releases.

This is like reverting the commit in main, so we are proceeding with that approach to simplify the release process of React Native and Hermes to the OSS.

Pull Request resolved: #1567

Pulled By: cipolleschi

Reviewed By: neildhar

Differential Revision: D68868242

fbshipit-source-id: c06b9821feb57507c7380358a7181747b91b0de5
  • Loading branch information
lavenzg authored and facebook-github-bot committed Jan 30, 2025
1 parent bd7c89b commit e898af6
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 8 deletions.
1 change: 0 additions & 1 deletion doc/IntlAPIs.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ One popular implementation strategy followed by other engines, is to bundle an i
## Supported on Android only
- `Intl.NumberFormat`
- `Intl.NumberFormat.prototype.formatToParts`
- `Intl.DateTimeFormat.prototype.formatToParts`

## * Limitations on property support

Expand Down
72 changes: 71 additions & 1 deletion lib/Platform/Intl/PlatformIntlApple.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,8 @@ uint8_t getCurrencyDigits(std::u16string_view code) {

std::u16string format(double jsTimeValue) noexcept;

std::vector<Part> formatToParts(double x) noexcept;

private:
void initializeNSDateFormatter(NSLocale *nsLocale) noexcept;

Expand Down Expand Up @@ -1895,8 +1897,76 @@ uint8_t getCurrencyDigits(std::u16string_view code) {
return static_cast<DateTimeFormatApple *>(this)->format(jsTimeValue);
}

static std::u16string returnTypeOfDate(const char16_t &c16) {
if (c16 == u'a')
return u"dayPeriod";
if (c16 == u'z' || c16 == u'v' || c16 == u'O')
return u"timeZoneName";
if (c16 == u'G')
return u"era";
if (c16 == u'y')
return u"year";
if (c16 == u'M')
return u"month";
if (c16 == u'E')
return u"weekday";
if (c16 == u'd')
return u"day";
if (c16 == u'h' || c16 == u'k' || c16 == u'K' || c16 == u'H')
return u"hour";
if (c16 == u'm')
return u"minute";
if (c16 == u's')
return u"second";
if (c16 == u'S')
return u"fractionalSecond";
return u"literal";
}

// Implementer note: This method corresponds roughly to
// https://402.ecma-international.org/8.0/#sec-formatdatetimetoparts
std::vector<Part> DateTimeFormatApple::formatToParts(double x) noexcept {
// NOTE: We dont have access to localeData.patterns. Instead we use
// NSDateFormatter's foramt string, and break it into components.
// 1. Let parts be ? PartitionDateTimePattern(dateTimeFormat, x).
auto fmt = nsStringToU16String(nsDateFormatter_.dateFormat);
std::unique(fmt.begin(), fmt.end());
auto formattedDate = format(x);
// 2. Let result be ArrayCreate(0).
std::vector<Part> result;
// 3. Let n be 0.
// 4. For each Record { [[Type]], [[Value]] } part in parts, do
// a. Let O be OrdinaryObjectCreate(%Object.prototype%).
// b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
// c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
// d. Perform ! CreateDataProperty(result, ! ToString(n), O).
// e. Increment n by 1.
std::u16string currentPart;
unsigned n = 0;
static auto alphanumerics = NSCharacterSet.alphanumericCharacterSet;
for (char16_t c16 : formattedDate) {
if ([alphanumerics characterIsMember:c16]) {
currentPart += c16;
continue;
}
if (currentPart != u"") {
result.push_back(
{{u"type", returnTypeOfDate(fmt[n])}, {u"value", currentPart}});
currentPart = u"";
n++;
}
result.push_back({{u"type", u"literal"}, {u"value", {c16}}});
n++;
}
// Last format string component.
result.push_back(
{{u"type", returnTypeOfDate(fmt[n])}, {u"value", currentPart}});
// 5. Return result.
return result;
}

std::vector<Part> DateTimeFormat::formatToParts(double x) noexcept {
llvm_unreachable("formatToParts is unimplemented on Apple platforms");
return static_cast<DateTimeFormatApple *>(this)->formatToParts(x);
}

class NumberFormatApple : public NumberFormat {
Expand Down
2 changes: 0 additions & 2 deletions lib/VM/JSLib/Intl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,15 +910,13 @@ void defineIntlDateTimeFormat(Runtime &runtime, Handle<JSObject> intl) {
false,
true);

#ifndef __APPLE__
defineMethod(
runtime,
prototype,
Predefined::getSymbolID(Predefined::formatToParts),
nullptr,
intlDateTimeFormatPrototypeFormatToParts,
1);
#endif

defineMethod(
runtime,
Expand Down
19 changes: 19 additions & 0 deletions test/hermes/intl/date-time-format-apple.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,24 @@ print(new Intl.DateTimeFormat('en-US').resolvedOptions().numberingSystem);
print(new Intl.DateTimeFormat('en-US', { timeZone: 'SGT'}).resolvedOptions().timeZone);
// CHECK-NEXT: SGT

print(JSON.stringify(new Intl.DateTimeFormat('en-US').formatToParts(date)));
// CHECK-NEXT: [{"value":"1","type":"month"},{"value":"/","type":"literal"},{"value":"2","type":"day"},{"value":"/","type":"literal"},{"value":"2020","type":"year"}]

print(JSON.stringify(new Intl.DateTimeFormat('en-GB').formatToParts(date)));
// CHECK-NEXT: [{"value":"02","type":"day"},{"value":"/","type":"literal"},{"value":"01","type":"month"},{"value":"/","type":"literal"},{"value":"2020","type":"year"}]

print(JSON.stringify(new Intl.DateTimeFormat('en-US', {weekday: 'long',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
fractionalSecondDigits: 3,
hour12: true,
timeZone: 'UTC'
}).formatToParts(new Date(Date.UTC(2020, 0, 2, 3, 45, 00, 30)))));
// CHECK-NEXT: [{"value":"Thursday","type":"weekday"},{"value":",","type":"literal"},{"value":" ","type":"literal"},{"value":"1","type":"month"},{"value":"/","type":"literal"},{"value":"2","type":"day"},{"value":"/","type":"literal"},{"value":"2020","type":"year"},{"value":",","type":"literal"},{"value":" ","type":"literal"},{"value":"3","type":"hour"},{"value":":","type":"literal"},{"value":"45","type":"minute"},{"value":":","type":"literal"},{"value":"00","type":"second"},{"value":".","type":"literal"},{"value":"030","type":"fractionalSecond"},{"value":" ","type":"literal"},{"value":"AM","type":"dayPeriod"}]

print(new Date(Date.UTC(2020, 0, 2)).toLocaleString("en-US", {weekday: "short", timeZone: "UTC"}))
// CHECK-NEXT: Thu
4 changes: 1 addition & 3 deletions test/hermes/intl/intl.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,7 @@ testServiceGetterTypes(Intl.DateTimeFormat, 'format');
testServiceMethodTypes(Intl.DateTimeFormat, 'formatToParts');
testServiceMethodTypes(Intl.DateTimeFormat, 'resolvedOptions');
assert(typeof Intl.DateTimeFormat().format() === 'string');
if(Intl.DateTimeFormat.prototype.formatToParts) {
testParts(Intl.DateTimeFormat().formatToParts());
}
testParts(Intl.DateTimeFormat().formatToParts());

testServiceTypes(Intl.NumberFormat);
testServiceGetterTypes(Intl.NumberFormat, 'format');
Expand Down
8 changes: 7 additions & 1 deletion utils/testsuite/skiplist.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@
},
{
"paths": [
"test262/test/intl402/DateTimeFormat/prototype/formatToParts/",
"test262/test/intl402/DateTimeFormat/prototype/formatToParts/fractionalSecondDigits.js",
"test262/test/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-long-en.js",
"test262/test/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-narrow-en.js",
"test262/test/intl402/DateTimeFormat/prototype/formatToParts/dayPeriod-short-en.js",
"test262/test/intl402/DateTimeFormat/prototype/formatToParts/offset-timezone-correct.js",
"test262/test/intl402/DateTimeFormat/prototype/formatToParts/related-year.js",
"test262/test/intl402/DateTimeFormat/prototype/formatToParts/related-year-zh.js",
"test262/test/intl402/DateTimeFormat/prototype/formatRange/",
"test262/test/intl402/DateTimeFormat/prototype/formatRangeToParts/",
"test262/test/intl402/NumberFormat/prototype/formatToParts/"
Expand Down

0 comments on commit e898af6

Please sign in to comment.