diff --git a/icu4c/source/i18n/i18n.vcxproj b/icu4c/source/i18n/i18n.vcxproj
index 96c8726a787..8ada6edd09b 100644
--- a/icu4c/source/i18n/i18n.vcxproj
+++ b/icu4c/source/i18n/i18n.vcxproj
@@ -250,6 +250,7 @@
+
@@ -484,6 +485,7 @@
+
diff --git a/icu4c/source/i18n/i18n.vcxproj.filters b/icu4c/source/i18n/i18n.vcxproj.filters
index a4ad63a1edb..778c912bcca 100644
--- a/icu4c/source/i18n/i18n.vcxproj.filters
+++ b/icu4c/source/i18n/i18n.vcxproj.filters
@@ -651,6 +651,9 @@
formatting
+
+ formatting
+
@@ -995,6 +998,9 @@
formatting
+
+ formatting
+
formatting
diff --git a/icu4c/source/i18n/i18n_uwp.vcxproj b/icu4c/source/i18n/i18n_uwp.vcxproj
index c33be615895..9bc6c3d434b 100644
--- a/icu4c/source/i18n/i18n_uwp.vcxproj
+++ b/icu4c/source/i18n/i18n_uwp.vcxproj
@@ -481,6 +481,7 @@
+
@@ -715,6 +716,7 @@
+
diff --git a/icu4c/source/i18n/sources.txt b/icu4c/source/i18n/sources.txt
index faaa14ec4c1..b9dd1a86f66 100644
--- a/icu4c/source/i18n/sources.txt
+++ b/icu4c/source/i18n/sources.txt
@@ -208,6 +208,7 @@ ulocdata.cpp
umsg.cpp
unesctrn.cpp
uni2name.cpp
+unitconverter.cpp
unum.cpp
unumsys.cpp
upluralrules.cpp
diff --git a/icu4c/source/i18n/unitconverter.cpp b/icu4c/source/i18n/unitconverter.cpp
new file mode 100644
index 00000000000..0e281344bf0
--- /dev/null
+++ b/icu4c/source/i18n/unitconverter.cpp
@@ -0,0 +1,19 @@
+// © 2020 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+U_NAMESPACE_BEGIN
+
+
+
+
+
+
+
+
+U_NAMESPACE_END
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
\ No newline at end of file
diff --git a/icu4c/source/i18n/unitconverter.h b/icu4c/source/i18n/unitconverter.h
new file mode 100644
index 00000000000..9a112f2f0a5
--- /dev/null
+++ b/icu4c/source/i18n/unitconverter.h
@@ -0,0 +1,22 @@
+// © 2020 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+#ifndef __UNITCONVERTER_H__
+#define __UNITCONVERTER_H__
+
+
+#include
+
+U_NAMESPACE_BEGIN
+
+
+
+U_NAMESPACE_END
+
+
+#endif //__UNITCONVERTER_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/test/intltest/Makefile.in b/icu4c/source/test/intltest/Makefile.in
index bcab2c98ba2..594d491f6f7 100644
--- a/icu4c/source/test/intltest/Makefile.in
+++ b/icu4c/source/test/intltest/Makefile.in
@@ -68,7 +68,8 @@ numbertest_modifiers.o numbertest_patternmodifier.o numbertest_patternstring.o \
string_segment_test.o \
numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
static_unisets_test.o numfmtdatadriventest.o numbertest_range.o erarulestest.o \
-formattedvaluetest.o formatted_string_builder_test.o numbertest_permutation.o
+formattedvaluetest.o formatted_string_builder_test.o numbertest_permutation.o \
+unitstest.o
DEPS = $(OBJECTS:.o=.d)
diff --git a/icu4c/source/test/intltest/intltest.vcxproj b/icu4c/source/test/intltest/intltest.vcxproj
index 6e956d9fc38..4fdaa2359a3 100644
--- a/icu4c/source/test/intltest/intltest.vcxproj
+++ b/icu4c/source/test/intltest/intltest.vcxproj
@@ -285,6 +285,7 @@
+
diff --git a/icu4c/source/test/intltest/intltest.vcxproj.filters b/icu4c/source/test/intltest/intltest.vcxproj.filters
index 0bf336b01ab..f068ff80e7f 100644
--- a/icu4c/source/test/intltest/intltest.vcxproj.filters
+++ b/icu4c/source/test/intltest/intltest.vcxproj.filters
@@ -550,6 +550,9 @@
locales & resources
+
+ formatting
+
diff --git a/icu4c/source/test/intltest/itformat.cpp b/icu4c/source/test/intltest/itformat.cpp
index 870728a9a0a..9126d528fa2 100644
--- a/icu4c/source/test/intltest/itformat.cpp
+++ b/icu4c/source/test/intltest/itformat.cpp
@@ -74,6 +74,7 @@ extern IntlTest *createScientificNumberFormatterTest();
extern IntlTest *createFormattedValueTest();
extern IntlTest *createFormattedStringBuilderTest();
extern IntlTest *createStringSegmentTest();
+extern IntlTest *createUnitsTest();
#define TESTCLASS(id, TestClass) \
@@ -247,6 +248,15 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam
callTest(*test, par);
}
break;
+ case 56:
+ name = "UnitsTest";
+ if (exec) {
+ logln("UnitsTest test---");
+ logln((UnicodeString)"");
+ LocalPointer test(createUnitsTest());
+ callTest(*test, par);
+ }
+ break;
default: name = ""; break; //needed to end loop
}
if (exec) {
diff --git a/icu4c/source/test/intltest/unitstest.cpp b/icu4c/source/test/intltest/unitstest.cpp
new file mode 100644
index 00000000000..05a02f73cbf
--- /dev/null
+++ b/icu4c/source/test/intltest/unitstest.cpp
@@ -0,0 +1,163 @@
+// © 2020 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html#License
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+
+#include "intltest.h"
+#include "unicode/unistr.h"
+
+class UnitsTest : public IntlTest {
+ public:
+ UnitsTest() {}
+
+ void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = NULL);
+
+ void testBasic();
+ void testSiPrefixes();
+ void testMass();
+ void testTemperature();
+ void testArea();
+};
+
+extern IntlTest *createUnitsTest() { return new UnitsTest(); }
+
+void UnitsTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) {
+ if (exec) {
+ logln("TestSuite UnitsTest: ");
+ }
+ TESTCASE_AUTO_BEGIN;
+ TESTCASE_AUTO(testBasic);
+ TESTCASE_AUTO(testSiPrefixes);
+ TESTCASE_AUTO(testMass);
+ TESTCASE_AUTO(testTemperature);
+ TESTCASE_AUTO(testArea);
+ TESTCASE_AUTO_END;
+}
+
+// Just for testing quick conversion ability.
+double testConvert(UnicodeString source, UnicodeString target, double input) {
+ if (source == u"meter" && target == u"foot" && input == 1.0)
+ return 3.28084;
+
+ if ( source == u"kilometer" && target == u"foot" && input == 1.0)
+ return 328.084;
+
+ return -1;
+}
+
+void UnitsTest::testBasic() {
+ IcuTestErrorCode status(*this, "Units testBasic");
+
+ // Test Cases
+ struct TestCase {
+ const char16_t *source;
+ const char16_t *target;
+ const double inputValue;
+ const double expectedValue;
+ } testCases[]{{u"meter", u"foot", 1.0, 3.28084}, {u"kilometer", u"foot", 1.0, 328.084}};
+
+ for (const auto &testCase : testCases) {
+ assertEquals("test convert", testConvert(testCase.source, testCase.target, testCase.inputValue),
+ testCase.expectedValue);
+ }
+}
+
+void UnitsTest::testSiPrefixes() {
+ IcuTestErrorCode status(*this, "Units testSiPrefixes");
+ // Test Cases
+ struct TestCase {
+ const char16_t *source;
+ const char16_t *target;
+ const double inputValue;
+ const double expectedValue;
+ } testCases[]{
+ {u"gram", u"kilogram", 1.0, 0.001}, //
+ {u"milligram", u"kilogram", 1.0, 0.000001}, //
+ {u"microgram", u"kilogram", 1.0, 0.000000001}, //
+ {u"megawatt", u"watt", 1, 1000000}, //
+ {u"megawatt", u"kilowatt", 1.0, 1000}, //
+ {u"gigabyte", u"byte", 1, 1000000000} //
+ };
+
+ for (const auto &testCase : testCases) {
+ assertEquals("test convert", testConvert(testCase.source, testCase.target, testCase.inputValue),
+ testCase.expectedValue);
+ }
+}
+
+void UnitsTest::testMass() {
+ IcuTestErrorCode status(*this, "Units testMass");
+
+ // Test Cases
+ struct TestCase {
+ const char16_t *source;
+ const char16_t *target;
+ const double inputValue;
+ const double expectedValue;
+ } testCases[]{
+ {u"gram", u"kilogram", 1.0, 0.001}, //
+ {u"pound", u"kilogram", 1.0, 0.453592}, //
+ {u"pound", u"kilogram", 2.0, 0.907185}, //
+ {u"ounce", u"pound", 16.0, 1.0}, //
+ {u"ounce", u"kilogram", 16.0, 0.453592}, //
+ {u"ton", u"pound", 1.0, 2000}, //
+ {u"stone", u"pound", 1.0, 14}, //
+ {u"stone", u"kilogram", 1.0, 6.35029} //
+ };
+
+ for (const auto &testCase : testCases) {
+ assertEquals("test convert", testConvert(testCase.source, testCase.target, testCase.inputValue),
+ testCase.expectedValue);
+ }
+}
+
+void UnitsTest::testTemperature() {
+ IcuTestErrorCode status(*this, "Units testTemperature");
+ // Test Cases
+ struct TestCase {
+ const char16_t *source;
+ const char16_t *target;
+ const double inputValue;
+ const double expectedValue;
+ } testCases[]{
+ {u"celsius", u"fahrenheit", 0.0, 32.0}, //
+ {u"celsius", u"fahrenheit", 10.0, 50.0}, //
+ {u"fahrenheit", u"celsius", 32.0, 0.0}, //
+ {u"fahrenheit", u"celsius", 89.6, 32}, //
+ {u"kelvin", u"fahrenheit", 0.0, -459.67}, //
+ {u"kelvin", u"fahrenheit", 300, 80.33}, //
+ {u"kelvin", u"celsius", 0.0, -273.15}, //
+ {u"kelvin", u"celsius", 300.0, 26.85} //
+ };
+
+ for (const auto &testCase : testCases) {
+ assertEquals("test convert", testConvert(testCase.source, testCase.target, testCase.inputValue),
+ testCase.expectedValue);
+ }
+}
+
+void UnitsTest::testArea() {
+ IcuTestErrorCode status(*this, "Units Area");
+
+ // Test Cases
+ struct TestCase {
+ const char16_t *source;
+ const char16_t *target;
+ const double inputValue;
+ const double expectedValue;
+ } testCases[]{
+ {u"square-meter", u"square-yard", 10.0, 11.9599}, //
+ {u"hectare", u"square-yard", 1.0, 11959.9}, //
+ {u"square-mile", u"square-foot", 0.0001, 2787.84} //
+ };
+
+ for (const auto &testCase : testCases) {
+ assertEquals("test convert", testConvert(testCase.source, testCase.target, testCase.inputValue),
+ testCase.expectedValue);
+ }
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */