ICU-22105 Fixed the unit-conversion logic to work correctly with negative temperature values.
diff --git a/icu4c/source/i18n/units_complexconverter.cpp b/icu4c/source/i18n/units_complexconverter.cpp
index ecbe3c7..8c9c334 100644
--- a/icu4c/source/i18n/units_complexconverter.cpp
+++ b/icu4c/source/i18n/units_complexconverter.cpp
@@ -143,7 +143,7 @@
// TODO: return an error for "foot-and-foot"?
MaybeStackVector<Measure> result;
int sign = 1;
- if (quantity < 0) {
+ if (quantity < 0 && unitsConverters_.length() > 1) {
quantity *= -1;
sign = -1;
}
diff --git a/icu4c/source/test/cintltst/unumberformattertst.c b/icu4c/source/test/cintltst/unumberformattertst.c
index ddba7fb..08e10de 100644
--- a/icu4c/source/test/cintltst/unumberformattertst.c
+++ b/icu4c/source/test/cintltst/unumberformattertst.c
@@ -34,6 +34,8 @@
static void Test21674_State(void);
+static void TestNegativeDegrees(void);
+
void addUNumberFormatterTest(TestNode** root);
#define TESTCASE(x) addTest(root, &x, "tsformat/unumberformatter/" #x)
@@ -47,6 +49,7 @@
TESTCASE(TestToDecimalNumber);
TESTCASE(TestPerUnitInArabic);
TESTCASE(Test21674_State);
+ TESTCASE(TestNegativeDegrees);
}
@@ -420,5 +423,43 @@
unumf_closeResult(result);
}
+// Test for ICU-22105
+static void TestNegativeDegrees(void) {
+ typedef struct {
+ const UChar* skeleton;
+ double value;
+ const UChar* expectedResult;
+ } TestCase;
+
+ TestCase testCases[] = {
+ { u"measure-unit/temperature-celsius unit-width-short", 0, u"0°C" },
+ { u"measure-unit/temperature-celsius unit-width-short usage/default", 0, u"32°F" },
+ { u"measure-unit/temperature-celsius unit-width-short usage/weather", 0, u"32°F" },
+
+ { u"measure-unit/temperature-celsius unit-width-short", -1, u"-1°C" },
+ { u"measure-unit/temperature-celsius unit-width-short usage/default", -1, u"30°F" },
+ { u"measure-unit/temperature-celsius unit-width-short usage/weather", -1, u"30°F" }
+ };
+
+ for (int32_t i = 0; i < UPRV_LENGTHOF(testCases); i++) {
+ UErrorCode err = U_ZERO_ERROR;
+ UNumberFormatter* nf = unumf_openForSkeletonAndLocale(testCases[i].skeleton, -1, "en_US", &err);
+ UFormattedNumber* fn = unumf_openResult(&err);
+
+ if (assertSuccess("Failed to create formatter or result", &err)) {
+ UChar result[200];
+ unumf_formatDouble(nf, testCases[i].value, fn, &err);
+ unumf_resultToString(fn, result, 200, &err);
+
+ if (assertSuccess("Formatting number failed", &err)) {
+ assertUEquals("Got wrong result", testCases[i].expectedResult, result);
+ }
+ }
+
+ unumf_closeResult(fn);
+ unumf_close(nf);
+ }
+}
+
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index 9ac9204..14cf310 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -1899,6 +1899,17 @@
Locale("en-US"), //
1, //
"0.019 psi");
+
+ assertFormatSingle(u"negative temperature conversion", //
+ u"measure-unit/temperature-celsius unit-width-short usage/default", //
+ u"measure-unit/temperature-celsius unit-width-short usage/default", //
+ NumberFormatter::with() //
+ .unit(MeasureUnit::forIdentifier("celsius", status)) //
+ .usage("default") //
+ .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_SHORT), //
+ Locale("en-US"), //
+ -1, //
+ u"30°F");
}
void NumberFormatterApiTest::unitUsageErrorCodes() {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/units/ComplexUnitsConverter.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/units/ComplexUnitsConverter.java
index af9843a..1bc2aaa 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/units/ComplexUnitsConverter.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/units/ComplexUnitsConverter.java
@@ -168,7 +168,7 @@
*/
public ComplexConverterResult convert(BigDecimal quantity, Precision rounder) {
BigInteger sign = BigInteger.ONE;
- if (quantity.compareTo(BigDecimal.ZERO) < 0) {
+ if (quantity.compareTo(BigDecimal.ZERO) < 0 && unitsConverters_.size() > 1) {
quantity = quantity.abs();
sign = sign.negate();
}
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
index a84e431..adafd98 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/NumberFormatterApiTest.java
@@ -1839,6 +1839,18 @@
new ULocale("en-US"),
1,
"0.019 psi");
+
+ // ICU-22105
+ assertFormatSingle("negative temperature conversion",
+ "measure-unit/temperature-celsius unit-width-short usage/default",
+ "measure-unit/temperature-celsius unit-width-short usage/default",
+ NumberFormatter.with()
+ .unit(MeasureUnit.forIdentifier("celsius"))
+ .usage("default")
+ .unitWidth(UnitWidth.SHORT),
+ new ULocale("en-US"),
+ -1,
+ "30°F");
}
@Test