Title: [271224] trunk
Revision
271224
Author
[email protected]
Date
2021-01-06 22:11:42 -0800 (Wed, 06 Jan 2021)

Log Message

[JSC] DateTimeFormat#formatRange should generate the same output to DateTimeFormat#format if startDate and endDate are "practically-equal"
https://bugs.webkit.org/show_bug.cgi?id=220395

Reviewed by Ross Kirsling.

JSTests:

Imported some test262 tests. Updated, fixed some issues (`formatToParts` test was using `format`, we should upstream it to test262), and added more tests.

* stress/intl-datetimeformat-format-range-should-check-practically-equal.js: Added.
(shouldBe):
(vm.icuVersion):
* stress/intl-datetimeformat-format-range-to-parts-should-check-practically-equal.js: Added.
(shouldBe):
(zip):
(compare):
(vm.icuVersion):

Source/_javascript_Core:

Intl.DateTimeFormat.formatRange(startDate, endDate) also needs to generate the same formatted string to the Intl.DateTimeFormat.format
if startDate and endDate are *practically-equal* (spec term). However, due to CLDR, just using udtitvfmt_format generates different
formatted string to udat_format's result even though startDate and endDate are the same.

    new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" }).format(new Date())
    // "December 12, 2019 at 11:48 AM"
    new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" }).formatRange(new Date(), new Date())
    // "December 12, 2019, 11:48 AM"

In Intl.DateTimeFormat#formatRangeToParts, we deploys *practically-equal* checking to avoid this issue. The same thing should be done in
Intl.DateTimeFormat#formatRange too.

In this patch, we stop using udtitvfmt_format if ICU version is 64 or later to perform *practically-equal* checking.

[1]: https://github.com/tc39/proposal-intl-DateTimeFormat-formatRange/issues/19

* runtime/IntlDateTimeFormat.cpp:
(JSC::formattedValueFromDateRange):
(JSC::dateFieldsPracticallyEqual):
(JSC::IntlDateTimeFormat::formatRange):
(JSC::IntlDateTimeFormat::formatRangeToParts):
(JSC::definitelyAfterGregorianCalendarChangeDate): Deleted.

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (271223 => 271224)


--- trunk/JSTests/ChangeLog	2021-01-07 06:11:14 UTC (rev 271223)
+++ trunk/JSTests/ChangeLog	2021-01-07 06:11:42 UTC (rev 271224)
@@ -1,3 +1,21 @@
+2021-01-06  Yusuke Suzuki  <[email protected]>
+
+        [JSC] DateTimeFormat#formatRange should generate the same output to DateTimeFormat#format if startDate and endDate are "practically-equal"
+        https://bugs.webkit.org/show_bug.cgi?id=220395
+
+        Reviewed by Ross Kirsling.
+
+        Imported some test262 tests. Updated, fixed some issues (`formatToParts` test was using `format`, we should upstream it to test262), and added more tests.
+
+        * stress/intl-datetimeformat-format-range-should-check-practically-equal.js: Added.
+        (shouldBe):
+        (vm.icuVersion):
+        * stress/intl-datetimeformat-format-range-to-parts-should-check-practically-equal.js: Added.
+        (shouldBe):
+        (zip):
+        (compare):
+        (vm.icuVersion):
+
 2021-01-05  Yusuke Suzuki  <[email protected]>
 
         [WASM] [BigInt] Add I64 to BigInt conversion

Added: trunk/JSTests/stress/intl-datetimeformat-format-range-should-check-practically-equal.js (0 => 271224)


--- trunk/JSTests/stress/intl-datetimeformat-format-range-should-check-practically-equal.js	                        (rev 0)
+++ trunk/JSTests/stress/intl-datetimeformat-format-range-should-check-practically-equal.js	2021-01-07 06:11:42 UTC (rev 271224)
@@ -0,0 +1,73 @@
+// The << Software identified by reference to the Ecma Standard* ("Software)">>  is protected by copyright and is being
+// made available under the  "BSD License", included below. This Software may be subject to third party rights (rights
+// from parties other than Ecma International), including patent rights, and no licenses under such third party rights
+// are granted under this license even if the third party concerned is a member of Ecma International.  SEE THE ECMA
+// CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
+// INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*.
+//
+// Copyright (C) 2012-2013 Ecma International
+// Copyright (C) 2021 Google Inc. All rights reserved.
+// Copyright (C) 2021 Apple Inc. All rights reserved.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+// following conditions are met:
+// 1.   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+//      disclaimer.
+// 2.   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
+//      following disclaimer in the documentation and/or other materials provided with the distribution.
+// 3.   Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from
+//      this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+// SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+// DAMAGE.
+//
+// * Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+if ($vm.icuVersion() >= 64) {
+    {
+        const date = new Date(2019, 7, 10,  1, 2, 3, 234);
+
+        let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" });
+        shouldBe(dtf.formatRange(date, date), dtf.format(date));
+
+        dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" });
+        shouldBe(dtf.formatRange(date, date), dtf.format(date));
+
+        dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" });
+        shouldBe(dtf.formatRange(date, date), dtf.format(date));
+
+        dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" });
+        shouldBe(dtf.formatRange(date, date), dtf.format(date));
+    }
+
+    {
+        // date1 and date2 are practically equal since the following formats do not show milliseconds.
+        const date1 = new Date(2019, 7, 10,  1, 2, 3, 234);
+        const date2 = new Date(2019, 7, 10,  1, 2, 3, 235);
+
+        shouldBe(date1.getTime() !== date2.getTime(), true);
+
+        let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" });
+        shouldBe(dtf.formatRange(date1, date2), dtf.format(date1));
+
+        dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" });
+        shouldBe(dtf.formatRange(date1, date2), dtf.format(date1));
+
+        dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" });
+        shouldBe(dtf.formatRange(date1, date2), dtf.format(date1));
+
+        dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" });
+        shouldBe(dtf.formatRange(date1, date2), dtf.format(date1));
+    }
+}

Added: trunk/JSTests/stress/intl-datetimeformat-format-range-to-parts-should-check-practically-equal.js (0 => 271224)


--- trunk/JSTests/stress/intl-datetimeformat-format-range-to-parts-should-check-practically-equal.js	                        (rev 0)
+++ trunk/JSTests/stress/intl-datetimeformat-format-range-to-parts-should-check-practically-equal.js	2021-01-07 06:11:42 UTC (rev 271224)
@@ -0,0 +1,84 @@
+// The << Software identified by reference to the Ecma Standard* ("Software)">>  is protected by copyright and is being
+// made available under the  "BSD License", included below. This Software may be subject to third party rights (rights
+// from parties other than Ecma International), including patent rights, and no licenses under such third party rights
+// are granted under this license even if the third party concerned is a member of Ecma International.  SEE THE ECMA
+// CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR
+// INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS*.
+//
+// Copyright (C) 2012-2013 Ecma International
+// Copyright (C) 2021 Google Inc. All rights reserved.
+// Copyright (C) 2021 Apple Inc. All rights reserved.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+// following conditions are met:
+// 1.   Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+//      disclaimer.
+// 2.   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
+//      following disclaimer in the documentation and/or other materials provided with the distribution.
+// 3.   Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from
+//      this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+// SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+// DAMAGE.
+//
+// * Ecma International Standards hereafter means Ecma International Standards as well as Ecma Technical Reports
+
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+function* zip(a, b) {
+    shouldBe(a.length, b.length);
+    for (let i = 0; i < a.length; ++i) {
+        yield [i, a[i], b[i]];
+    }
+}
+
+function compare(actual, expected) {
+    for (const [i, actualEntry, expectedEntry] of zip(actual, expected)) {
+        shouldBe(actualEntry.type, expectedEntry.type);
+        shouldBe(actualEntry.value, expectedEntry.value);
+    }
+}
+
+if ($vm.icuVersion() >= 64) {
+    {
+        const date = new Date(2019, 7, 10,  1, 2, 3, 234);
+
+        let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" });
+        compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date));
+
+        dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" });
+        compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date));
+
+        dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" });
+        compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date));
+
+        dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" });
+        compare(dtf.formatRangeToParts(date, date), dtf.formatToParts(date));
+    }
+    {
+        // date1 and date2 are practically equal since the following formats do not show milliseconds.
+        const date1 = new Date(2019, 7, 10,  1, 2, 3, 234);
+        const date2 = new Date(2019, 7, 10,  1, 2, 3, 235);
+
+        let dtf = new Intl.DateTimeFormat("en", { year: "numeric", month: "short", day: "numeric" });
+        compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1));
+
+        dtf = new Intl.DateTimeFormat("en", { minute: "numeric", second: "numeric" });
+        compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1));
+
+        dtf = new Intl.DateTimeFormat("en", { month: "short", day: "numeric", minute: "numeric" });
+        compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1));
+
+        dtf = new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" });
+        compare(dtf.formatRangeToParts(date1, date2), dtf.formatToParts(date1));
+    }
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (271223 => 271224)


--- trunk/Source/_javascript_Core/ChangeLog	2021-01-07 06:11:14 UTC (rev 271223)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-01-07 06:11:42 UTC (rev 271224)
@@ -1,5 +1,35 @@
 2021-01-06  Yusuke Suzuki  <[email protected]>
 
+        [JSC] DateTimeFormat#formatRange should generate the same output to DateTimeFormat#format if startDate and endDate are "practically-equal"
+        https://bugs.webkit.org/show_bug.cgi?id=220395
+
+        Reviewed by Ross Kirsling.
+
+        Intl.DateTimeFormat.formatRange(startDate, endDate) also needs to generate the same formatted string to the Intl.DateTimeFormat.format
+        if startDate and endDate are *practically-equal* (spec term). However, due to CLDR, just using udtitvfmt_format generates different
+        formatted string to udat_format's result even though startDate and endDate are the same.
+
+            new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" }).format(new Date())
+            // "December 12, 2019 at 11:48 AM"
+            new Intl.DateTimeFormat("en", { dateStyle: "long", timeStyle: "short" }).formatRange(new Date(), new Date())
+            // "December 12, 2019, 11:48 AM"
+
+        In Intl.DateTimeFormat#formatRangeToParts, we deploys *practically-equal* checking to avoid this issue. The same thing should be done in
+        Intl.DateTimeFormat#formatRange too.
+
+        In this patch, we stop using udtitvfmt_format if ICU version is 64 or later to perform *practically-equal* checking.
+
+        [1]: https://github.com/tc39/proposal-intl-DateTimeFormat-formatRange/issues/19
+
+        * runtime/IntlDateTimeFormat.cpp:
+        (JSC::formattedValueFromDateRange):
+        (JSC::dateFieldsPracticallyEqual):
+        (JSC::IntlDateTimeFormat::formatRange):
+        (JSC::IntlDateTimeFormat::formatRangeToParts):
+        (JSC::definitelyAfterGregorianCalendarChangeDate): Deleted.
+
+2021-01-06  Yusuke Suzuki  <[email protected]>
+
         [JSC] Replace JSBigInt::toUint64 with JSBigInt::toBigUInt64
         https://bugs.webkit.org/show_bug.cgi?id=220378
 

Modified: trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp (271223 => 271224)


--- trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp	2021-01-07 06:11:14 UTC (rev 271223)
+++ trunk/Source/_javascript_Core/runtime/IntlDateTimeFormat.cpp	2021-01-07 06:11:42 UTC (rev 271224)
@@ -1382,16 +1382,6 @@
 
 #if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
 
-// If a date is after Oct 15, 1582, the configuration of gregorian calendar change date in UCalendar does not affect
-// on the formatted string. To ensure that it is after Oct 15 in all timezones, we add one day to gregorian calendar
-// change date in UTC, so that this check can conservatively answer whether the date is definitely after gregorian
-// calendar change date.
-static inline bool definitelyAfterGregorianCalendarChangeDate(double millisecondsFromEpoch)
-{
-    constexpr double gregorianCalendarReformDateInUTC = -12219292800000.0;
-    return millisecondsFromEpoch >= (gregorianCalendarReformDateInUTC + msPerDay);
-}
-
 static std::unique_ptr<UFormattedDateInterval, ICUDeleter<udtitvfmt_closeResult>> formattedValueFromDateRange(UDateIntervalFormat& dateIntervalFormat, UDateFormat& dateFormat, double startDate, double endDate, UErrorCode& status)
 {
     auto result = std::unique_ptr<UFormattedDateInterval, ICUDeleter<udtitvfmt_closeResult>>(udtitvfmt_openResult(&status));
@@ -1400,6 +1390,15 @@
 
     // After ICU 67, udtitvfmt_formatToResult's signature is changed.
 #if U_ICU_VERSION_MAJOR_NUM >= 67
+    // If a date is after Oct 15, 1582, the configuration of gregorian calendar change date in UCalendar does not affect
+    // on the formatted string. To ensure that it is after Oct 15 in all timezones, we add one day to gregorian calendar
+    // change date in UTC, so that this check can conservatively answer whether the date is definitely after gregorian
+    // calendar change date.
+    auto definitelyAfterGregorianCalendarChangeDate = [](double millisecondsFromEpoch) {
+        constexpr double gregorianCalendarReformDateInUTC = -12219292800000.0;
+        return millisecondsFromEpoch >= (gregorianCalendarReformDateInUTC + msPerDay);
+    };
+
     // UFormattedDateInterval does not have a way to configure gregorian calendar change date while ECMAScript requires that
     // gregorian calendar change should not have effect (we are setting ucal_setGregorianChange(cal, minECMAScriptTime, &status) explicitly).
     // As a result, if the input date is older than gregorian calendar change date (Oct 15, 1582), the formatted string becomes
@@ -1443,6 +1442,24 @@
     return result;
 }
 
+static bool dateFieldsPracticallyEqual(const UFormattedValue* formattedValue, UErrorCode& status)
+{
+    auto iterator = std::unique_ptr<UConstrainedFieldPosition, ICUDeleter<ucfpos_close>>(ucfpos_open(&status));
+    if (U_FAILURE(status))
+        return false;
+
+    // We only care about UFIELD_CATEGORY_DATE_INTERVAL_SPAN category.
+    ucfpos_constrainCategory(iterator.get(), UFIELD_CATEGORY_DATE_INTERVAL_SPAN, &status);
+    if (U_FAILURE(status))
+        return false;
+
+    bool hasSpan = ufmtval_nextPosition(formattedValue, iterator.get(), &status);
+    if (U_FAILURE(status))
+        return false;
+
+    return !hasSpan;
+}
+
 #endif // HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
 
 JSValue IntlDateTimeFormat::formatRange(JSGlobalObject* globalObject, double startDate, double endDate)
@@ -1464,35 +1481,42 @@
     RETURN_IF_EXCEPTION(scope, { });
 
 #if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
-    // If the date is older than gregorian calendar change date, we need to explicitly pass configured UCalendar to
-    // udtitvfmt_formatCalendarToResult to generate a correct formatted string.
-    // The comment in formattedValueFromDateRange describes the details.
-    if (!definitelyAfterGregorianCalendarChangeDate(startDate)) {
-        UErrorCode status = U_ZERO_ERROR;
-        auto result = formattedValueFromDateRange(*dateIntervalFormat, *m_dateFormat, startDate, endDate, status);
-        if (U_FAILURE(status)) {
-            throwTypeError(globalObject, scope, "Failed to format date interval"_s);
-            return { };
-        }
+    UErrorCode status = U_ZERO_ERROR;
+    auto result = formattedValueFromDateRange(*dateIntervalFormat, *m_dateFormat, startDate, endDate, status);
+    if (U_FAILURE(status)) {
+        throwTypeError(globalObject, scope, "Failed to format date interval"_s);
+        return { };
+    }
 
-        // UFormattedValue is owned by UFormattedDateInterval. We do not need to close it.
-        auto formattedValue = udtitvfmt_resultAsValue(result.get(), &status);
-        if (U_FAILURE(status)) {
-            throwTypeError(globalObject, scope, "Failed to format date interval"_s);
-            return { };
-        }
+    // UFormattedValue is owned by UFormattedDateInterval. We do not need to close it.
+    auto formattedValue = udtitvfmt_resultAsValue(result.get(), &status);
+    if (U_FAILURE(status)) {
+        throwTypeError(globalObject, scope, "Failed to format date interval"_s);
+        return { };
+    }
 
-        int32_t formattedStringLength = 0;
-        const UChar* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status);
-        if (U_FAILURE(status)) {
-            throwTypeError(globalObject, scope, "Failed to format date interval"_s);
-            return { };
-        }
+    // If the formatted parts of startDate and endDate are the same, it is possible that the resulted string does not look like range.
+    // For example, if the requested format only includes "year" and startDate and endDate are the same year, the result just contains one year.
+    // In that case, startDate and endDate are *practically-equal* (spec term), and we generate parts as we call `formatToParts(startDate)` with
+    // `source: "shared"` additional fields.
+    bool equal = dateFieldsPracticallyEqual(formattedValue, status);
+    if (U_FAILURE(status)) {
+        throwTypeError(globalObject, scope, "Failed to format date interval"_s);
+        return { };
+    }
 
-        return jsString(vm, String(formattedStringPointer, formattedStringLength));
+    if (equal)
+        RELEASE_AND_RETURN(scope, format(globalObject, startDate));
+
+    int32_t formattedStringLength = 0;
+    const UChar* formattedStringPointer = ufmtval_getString(formattedValue, &formattedStringLength, &status);
+    if (U_FAILURE(status)) {
+        throwTypeError(globalObject, scope, "Failed to format date interval"_s);
+        return { };
     }
-#endif
 
+    return jsString(vm, String(formattedStringPointer, formattedStringLength));
+#else
     Vector<UChar, 32> buffer;
     auto status = callBufferProducingFunction(udtitvfmt_format, dateIntervalFormat, startDate, endDate, buffer, nullptr);
     if (U_FAILURE(status)) {
@@ -1501,6 +1525,7 @@
     }
 
     return jsString(vm, String(buffer));
+#endif
 }
 
 JSValue IntlDateTimeFormat::formatRangeToParts(JSGlobalObject* globalObject, double startDate, double endDate)
@@ -1522,23 +1547,6 @@
     auto* dateIntervalFormat = createDateIntervalFormatIfNecessary(globalObject);
     RETURN_IF_EXCEPTION(scope, { });
 
-    auto dateFieldsPracticallyEqual = [](const UFormattedValue* formattedValue, UErrorCode& status) {
-        auto iterator = std::unique_ptr<UConstrainedFieldPosition, ICUDeleter<ucfpos_close>>(ucfpos_open(&status));
-        if (U_FAILURE(status))
-            return false;
-
-        // We only care about UFIELD_CATEGORY_DATE_INTERVAL_SPAN category.
-        ucfpos_constrainCategory(iterator.get(), UFIELD_CATEGORY_DATE_INTERVAL_SPAN, &status);
-        if (U_FAILURE(status))
-            return false;
-
-        bool hasSpan = ufmtval_nextPosition(formattedValue, iterator.get(), &status);
-        if (U_FAILURE(status))
-            return false;
-
-        return !hasSpan;
-    };
-
     UErrorCode status = U_ZERO_ERROR;
     auto result = formattedValueFromDateRange(*dateIntervalFormat, *m_dateFormat, startDate, endDate, status);
     if (U_FAILURE(status)) {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to