diff --git a/icu4c/source/data/build.xml b/icu4c/source/data/build.xml
index 5fd1a993a12..a6eb039ea0b 100644
--- a/icu4c/source/data/build.xml
+++ b/icu4c/source/data/build.xml
@@ -27,7 +27,7 @@
-
+
@@ -47,8 +47,11 @@
+
+
+
-
+
diff --git a/icu4c/source/data/cldr-icu-readme.txt b/icu4c/source/data/cldr-icu-readme.txt
index b6f8ebe7bfc..d4ce2fd08e7 100644
--- a/icu4c/source/data/cldr-icu-readme.txt
+++ b/icu4c/source/data/cldr-icu-readme.txt
@@ -69,9 +69,8 @@
#
# CLDR_DIR: Path to root of CLDR sources, below which are the common and
# tools directories.
-# CLDR_CLASSES: Defined relative to CLDR_DIR. It only needs to be set if you
-# are not running ant jar for CLDR and have a non-default output
-# folder for cldr-tools classes.
+# CLDR_CLASSES: Path to the CLDR Tools classes directory. If not set, defaults
+# to $CLDR_DIR/tools/java/classes
#
# c) ICU-related variables
# These variables only need to be set if you're directly reusing the
@@ -140,7 +139,6 @@ export ANT_OPTS="-Xmx3072m -DCLDR_DTD_CACHE=/tmp"
# CLDR_DIR=`cygpath -wp /build/cldr`
export CLDR_DIR=$HOME/cldr/trunk
-#export CLDR_CLASSES=$CLDR_DIR/tools/java/classes
# 1c. ICU variables
@@ -148,9 +146,11 @@ export ICU4C_DIR=$HOME/icu/trunk/icu4c
export ICU4J_ROOT=$HOME/icu/trunk/icu4j
# 2. Build the CLDR Java tools
+# Optionally build the jar, but ant will look inside the classes directory anyway
cd $CLDR_DIR/tools/java
-ant jar
+ant all
+#ant jar
# 3. Configure ICU4C, build and test without new data first, to verify that
# there are no pre-existing errors (configure shown here for MacOSX, adjust
@@ -169,12 +169,16 @@ make check 2>&1 | tee /tmp/icu4c-oldData-makeCheck.txt
# This process will take several minutes.
# Keep a log so you can investigate anything that looks suspicious.
#
+# Running "ant setup" is not required, but it will print useful errors to
+# debug issues with your path when it fails.
+#
# If you see timeout errors when building the rbnf data, for example, then the
# system you are building on likely does not have its IP address whitelisted with
# Unicode for access to the CLDR repository, see note on "IP address whitelisting"
# near the top of this file.
cd $ICU4C_DIR/source/data
+ant setup
ant clean
ant all 2>&1 | tee /tmp/cldr-newData-buildLog.txt
diff --git a/icu4c/source/data/unit/root.txt b/icu4c/source/data/unit/root.txt
index 5ce0bf9b566..9410db52d08 100644
--- a/icu4c/source/data/unit/root.txt
+++ b/icu4c/source/data/unit/root.txt
@@ -198,6 +198,7 @@ root{
other{"{0} d"}
per{"{0}/d"}
}
+ day-person:alias{"/LOCALE/unitsShort/duration/day"}
hour{
dnam{"hr"}
other{"{0} h"}
@@ -221,6 +222,7 @@ root{
other{"{0} m"}
per{"{0}/m"}
}
+ month-person:alias{"/LOCALE/unitsShort/duration/month"}
nanosecond{
dnam{"ns"}
other{"{0} ns"}
@@ -235,11 +237,13 @@ root{
other{"{0} w"}
per{"{0}/w"}
}
+ week-person:alias{"/LOCALE/unitsShort/duration/week"}
year{
dnam{"yr"}
other{"{0} y"}
per{"{0}/y"}
}
+ year-person:alias{"/LOCALE/unitsShort/duration/year"}
}
electric{
ampere{
diff --git a/icu4c/source/i18n/measfmt.cpp b/icu4c/source/i18n/measfmt.cpp
index 9830dc889e1..477341b4469 100644
--- a/icu4c/source/i18n/measfmt.cpp
+++ b/icu4c/source/i18n/measfmt.cpp
@@ -47,7 +47,7 @@ U_NAMESPACE_BEGIN
static constexpr int32_t PER_UNIT_INDEX = StandardPlural::COUNT;
static constexpr int32_t PATTERN_COUNT = PER_UNIT_INDEX + 1;
-static constexpr int32_t MEAS_UNIT_COUNT = 142; // see assertion in MeasureFormatCacheData constructor
+static constexpr int32_t MEAS_UNIT_COUNT = 146; // see assertion in MeasureFormatCacheData constructor
static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1;
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat)
diff --git a/icu4c/source/i18n/measunit.cpp b/icu4c/source/i18n/measunit.cpp
index a0c30b4ad30..e061cb458a2 100644
--- a/icu4c/source/i18n/measunit.cpp
+++ b/icu4c/source/i18n/measunit.cpp
@@ -43,19 +43,19 @@ static const int32_t gOffsets[] = {
26,
325,
336,
- 347,
351,
- 357,
+ 355,
361,
- 381,
- 382,
- 393,
- 396,
- 402,
- 408,
+ 365,
+ 385,
+ 386,
+ 397,
+ 400,
+ 406,
412,
416,
- 441
+ 420,
+ 445
};
static const int32_t gIndexes[] = {
@@ -67,19 +67,19 @@ static const int32_t gIndexes[] = {
26,
26,
37,
- 48,
52,
- 58,
+ 56,
62,
- 82,
- 83,
- 94,
- 97,
- 103,
- 109,
+ 66,
+ 86,
+ 87,
+ 98,
+ 101,
+ 107,
113,
117,
- 142
+ 121,
+ 146
};
// Must be sorted alphabetically.
@@ -446,15 +446,19 @@ static const char * const gSubTypes[] = {
"terabyte",
"century",
"day",
+ "day-person",
"hour",
"microsecond",
"millisecond",
"minute",
"month",
+ "month-person",
"nanosecond",
"second",
"week",
+ "week-person",
"year",
+ "year-person",
"ampere",
"milliampere",
"ohm",
@@ -553,14 +557,14 @@ static const char * const gSubTypes[] = {
// Must be sorted by first value and then second value.
static int32_t unitPerUnitToSingleUnit[][4] = {
- {368, 338, 17, 0},
- {370, 344, 17, 2},
- {372, 338, 17, 3},
- {372, 430, 4, 2},
- {372, 431, 4, 3},
- {387, 428, 3, 1},
- {390, 11, 16, 5},
- {433, 368, 4, 1}
+ {372, 339, 17, 0},
+ {374, 346, 17, 2},
+ {376, 339, 17, 3},
+ {376, 434, 4, 2},
+ {376, 435, 4, 3},
+ {391, 432, 3, 1},
+ {394, 11, 16, 5},
+ {437, 372, 4, 1}
};
// Shortcuts to the base unit in order to make the default constructor fast
@@ -879,78 +883,110 @@ MeasureUnit MeasureUnit::getDay() {
return MeasureUnit(7, 1);
}
-MeasureUnit *MeasureUnit::createHour(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createDayPerson(UErrorCode &status) {
return MeasureUnit::create(7, 2, status);
}
-MeasureUnit MeasureUnit::getHour() {
+MeasureUnit MeasureUnit::getDayPerson() {
return MeasureUnit(7, 2);
}
-MeasureUnit *MeasureUnit::createMicrosecond(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createHour(UErrorCode &status) {
return MeasureUnit::create(7, 3, status);
}
-MeasureUnit MeasureUnit::getMicrosecond() {
+MeasureUnit MeasureUnit::getHour() {
return MeasureUnit(7, 3);
}
-MeasureUnit *MeasureUnit::createMillisecond(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createMicrosecond(UErrorCode &status) {
return MeasureUnit::create(7, 4, status);
}
-MeasureUnit MeasureUnit::getMillisecond() {
+MeasureUnit MeasureUnit::getMicrosecond() {
return MeasureUnit(7, 4);
}
-MeasureUnit *MeasureUnit::createMinute(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createMillisecond(UErrorCode &status) {
return MeasureUnit::create(7, 5, status);
}
-MeasureUnit MeasureUnit::getMinute() {
+MeasureUnit MeasureUnit::getMillisecond() {
return MeasureUnit(7, 5);
}
-MeasureUnit *MeasureUnit::createMonth(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createMinute(UErrorCode &status) {
return MeasureUnit::create(7, 6, status);
}
-MeasureUnit MeasureUnit::getMonth() {
+MeasureUnit MeasureUnit::getMinute() {
return MeasureUnit(7, 6);
}
-MeasureUnit *MeasureUnit::createNanosecond(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createMonth(UErrorCode &status) {
return MeasureUnit::create(7, 7, status);
}
-MeasureUnit MeasureUnit::getNanosecond() {
+MeasureUnit MeasureUnit::getMonth() {
return MeasureUnit(7, 7);
}
-MeasureUnit *MeasureUnit::createSecond(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createMonthPerson(UErrorCode &status) {
return MeasureUnit::create(7, 8, status);
}
-MeasureUnit MeasureUnit::getSecond() {
+MeasureUnit MeasureUnit::getMonthPerson() {
return MeasureUnit(7, 8);
}
-MeasureUnit *MeasureUnit::createWeek(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createNanosecond(UErrorCode &status) {
return MeasureUnit::create(7, 9, status);
}
-MeasureUnit MeasureUnit::getWeek() {
+MeasureUnit MeasureUnit::getNanosecond() {
return MeasureUnit(7, 9);
}
-MeasureUnit *MeasureUnit::createYear(UErrorCode &status) {
+MeasureUnit *MeasureUnit::createSecond(UErrorCode &status) {
return MeasureUnit::create(7, 10, status);
}
-MeasureUnit MeasureUnit::getYear() {
+MeasureUnit MeasureUnit::getSecond() {
return MeasureUnit(7, 10);
}
+MeasureUnit *MeasureUnit::createWeek(UErrorCode &status) {
+ return MeasureUnit::create(7, 11, status);
+}
+
+MeasureUnit MeasureUnit::getWeek() {
+ return MeasureUnit(7, 11);
+}
+
+MeasureUnit *MeasureUnit::createWeekPerson(UErrorCode &status) {
+ return MeasureUnit::create(7, 12, status);
+}
+
+MeasureUnit MeasureUnit::getWeekPerson() {
+ return MeasureUnit(7, 12);
+}
+
+MeasureUnit *MeasureUnit::createYear(UErrorCode &status) {
+ return MeasureUnit::create(7, 13, status);
+}
+
+MeasureUnit MeasureUnit::getYear() {
+ return MeasureUnit(7, 13);
+}
+
+MeasureUnit *MeasureUnit::createYearPerson(UErrorCode &status) {
+ return MeasureUnit::create(7, 14, status);
+}
+
+MeasureUnit MeasureUnit::getYearPerson() {
+ return MeasureUnit(7, 14);
+}
+
MeasureUnit *MeasureUnit::createAmpere(UErrorCode &status) {
return MeasureUnit::create(8, 0, status);
}
diff --git a/icu4c/source/i18n/number_longnames.cpp b/icu4c/source/i18n/number_longnames.cpp
index 0d12e56a91f..fc4517916ba 100644
--- a/icu4c/source/i18n/number_longnames.cpp
+++ b/icu4c/source/i18n/number_longnames.cpp
@@ -101,7 +101,16 @@ void getMeasureData(const Locale &locale, const MeasureUnit &unit, const UNumber
key.append("/", status);
key.append(unit.getType(), status);
key.append("/", status);
- key.append(unit.getSubtype(), status);
+
+ // Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ...
+ // TODO(ICU-20400): Get duration-*-person data properly with aliases.
+ int32_t subtypeLen = static_cast(uprv_strlen(unit.getSubtype()));
+ if (subtypeLen > 7 && uprv_strcmp(unit.getSubtype() + subtypeLen - 7, "-person") == 0) {
+ key.append({unit.getSubtype(), subtypeLen - 7}, status);
+ } else {
+ key.append(unit.getSubtype(), status);
+ }
+
ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), sink, status);
}
diff --git a/icu4c/source/i18n/unicode/measunit.h b/icu4c/source/i18n/unicode/measunit.h
index c0406e11c06..54390305157 100644
--- a/icu4c/source/i18n/unicode/measunit.h
+++ b/icu4c/source/i18n/unicode/measunit.h
@@ -838,6 +838,24 @@ class U_I18N_API MeasureUnit: public UObject {
*/
static MeasureUnit getDay();
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Returns by pointer, unit of duration: day-person.
+ * Caller owns returned value and must free it.
+ * Also see {@link #getDayPerson()}.
+ * @param status ICU error code.
+ * @draft ICU 63
+ */
+ static MeasureUnit *createDayPerson(UErrorCode &status);
+
+ /**
+ * Returns by value, unit of duration: day-person.
+ * Also see {@link #createDayPerson()}.
+ * @draft ICU 64
+ */
+ static MeasureUnit getDayPerson();
+#endif /* U_HIDE_DRAFT_API */
+
/**
* Returns by pointer, unit of duration: hour.
* Caller owns returned value and must free it.
@@ -918,6 +936,24 @@ class U_I18N_API MeasureUnit: public UObject {
*/
static MeasureUnit getMonth();
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Returns by pointer, unit of duration: month-person.
+ * Caller owns returned value and must free it.
+ * Also see {@link #getMonthPerson()}.
+ * @param status ICU error code.
+ * @draft ICU 63
+ */
+ static MeasureUnit *createMonthPerson(UErrorCode &status);
+
+ /**
+ * Returns by value, unit of duration: month-person.
+ * Also see {@link #createMonthPerson()}.
+ * @draft ICU 64
+ */
+ static MeasureUnit getMonthPerson();
+#endif /* U_HIDE_DRAFT_API */
+
/**
* Returns by pointer, unit of duration: nanosecond.
* Caller owns returned value and must free it.
@@ -966,6 +1002,24 @@ class U_I18N_API MeasureUnit: public UObject {
*/
static MeasureUnit getWeek();
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Returns by pointer, unit of duration: week-person.
+ * Caller owns returned value and must free it.
+ * Also see {@link #getWeekPerson()}.
+ * @param status ICU error code.
+ * @draft ICU 63
+ */
+ static MeasureUnit *createWeekPerson(UErrorCode &status);
+
+ /**
+ * Returns by value, unit of duration: week-person.
+ * Also see {@link #createWeekPerson()}.
+ * @draft ICU 64
+ */
+ static MeasureUnit getWeekPerson();
+#endif /* U_HIDE_DRAFT_API */
+
/**
* Returns by pointer, unit of duration: year.
* Caller owns returned value and must free it.
@@ -982,6 +1036,24 @@ class U_I18N_API MeasureUnit: public UObject {
*/
static MeasureUnit getYear();
+#ifndef U_HIDE_DRAFT_API
+ /**
+ * Returns by pointer, unit of duration: year-person.
+ * Caller owns returned value and must free it.
+ * Also see {@link #getYearPerson()}.
+ * @param status ICU error code.
+ * @draft ICU 63
+ */
+ static MeasureUnit *createYearPerson(UErrorCode &status);
+
+ /**
+ * Returns by value, unit of duration: year-person.
+ * Also see {@link #createYearPerson()}.
+ * @draft ICU 64
+ */
+ static MeasureUnit getYearPerson();
+#endif /* U_HIDE_DRAFT_API */
+
/**
* Returns by pointer, unit of electric: ampere.
* Caller owns returned value and must free it.
diff --git a/icu4c/source/test/intltest/measfmttest.cpp b/icu4c/source/test/intltest/measfmttest.cpp
index 4fb9ee8320e..c8ec4dce4ed 100644
--- a/icu4c/source/test/intltest/measfmttest.cpp
+++ b/icu4c/source/test/intltest/measfmttest.cpp
@@ -74,6 +74,7 @@ private:
void TestDoubleZero();
void TestUnitPerUnitResolution();
void TestIndividualPluralFallback();
+ void Test20332_PersonUnits();
void verifyFormat(
const char *description,
const MeasureFormat &fmt,
@@ -173,6 +174,7 @@ void MeasureFormatTest::runIndexedTest(
TESTCASE_AUTO(TestDoubleZero);
TESTCASE_AUTO(TestUnitPerUnitResolution);
TESTCASE_AUTO(TestIndividualPluralFallback);
+ TESTCASE_AUTO(Test20332_PersonUnits);
TESTCASE_AUTO_END;
}
@@ -2615,6 +2617,38 @@ void MeasureFormatTest::TestIndividualPluralFallback() {
assertEquals("2 deg temp in fr_CA", expected, mf.format(twoDeg.orphan(), actual, errorCode), TRUE);
}
+void MeasureFormatTest::Test20332_PersonUnits() {
+ if (logKnownIssue("ICU-20400")) {
+ return;
+ }
+ IcuTestErrorCode status(*this, "Test20332_PersonUnits");
+ const struct TestCase {
+ const char* locale;
+ MeasureUnit* unitToAdopt;
+ UMeasureFormatWidth width;
+ const char* expected;
+ } cases[] = {
+ {"en-us", MeasureUnit::createYearPerson(status), UMEASFMT_WIDTH_NARROW, "25y"},
+ {"en-us", MeasureUnit::createYearPerson(status), UMEASFMT_WIDTH_SHORT, "25 yrs"},
+ {"en-us", MeasureUnit::createYearPerson(status), UMEASFMT_WIDTH_WIDE, "25 years"},
+ {"en-us", MeasureUnit::createMonthPerson(status), UMEASFMT_WIDTH_NARROW, "25m"},
+ {"en-us", MeasureUnit::createMonthPerson(status), UMEASFMT_WIDTH_SHORT, "25 mths"},
+ {"en-us", MeasureUnit::createMonthPerson(status), UMEASFMT_WIDTH_WIDE, "25 months"},
+ {"en-us", MeasureUnit::createWeekPerson(status), UMEASFMT_WIDTH_NARROW, "25w"},
+ {"en-us", MeasureUnit::createWeekPerson(status), UMEASFMT_WIDTH_SHORT, "25 wks"},
+ {"en-us", MeasureUnit::createWeekPerson(status), UMEASFMT_WIDTH_WIDE, "25 weeks"},
+ {"en-us", MeasureUnit::createDayPerson(status), UMEASFMT_WIDTH_NARROW, "25d"},
+ {"en-us", MeasureUnit::createDayPerson(status), UMEASFMT_WIDTH_SHORT, "25 Days"},
+ {"en-us", MeasureUnit::createDayPerson(status), UMEASFMT_WIDTH_WIDE, "25 days"}
+ };
+ for (const auto& cas : cases) {
+ MeasureFormat mf(cas.locale, cas.width, status);
+ Measure measure(25, cas.unitToAdopt, status);
+ verifyFormat(cas.locale, mf, &measure, 1, cas.expected);
+ }
+}
+
+
void MeasureFormatTest::verifyFieldPosition(
const char *description,
const MeasureFormat &fmt,
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index 910818ec5d8..b95807e6228 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -562,6 +562,15 @@ void NumberFormatterApiTest::unitMeasure() {
Locale("es-MX"),
1,
u"kelvin");
+
+ assertFormatSingle(
+ u"Person unit not in short form",
+ u"measure-unit/duration-year-person unit-width-full-name",
+ NumberFormatter::with().unit(MeasureUnit::getYearPerson())
+ .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME),
+ Locale("es-MX"),
+ 5,
+ u"5 a\u00F1os");
}
void NumberFormatterApiTest::unitCompoundMeasure() {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java
index dbdc550c576..e31ea8b18a8 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java
@@ -97,7 +97,15 @@ public class LongNameHandler implements MicroPropsGenerator, ModifierStore {
key.append("/");
key.append(unit.getType());
key.append("/");
- key.append(unit.getSubtype());
+
+ // Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ...
+ // TODO(ICU-20400): Get duration-*-person data properly with aliases.
+ if (unit.getSubtype().endsWith("-person")) {
+ key.append(unit.getSubtype(), 0, unit.getSubtype().length() - 7);
+ } else {
+ key.append(unit.getSubtype());
+ }
+
try {
resource.getAllItemsWithFallback(key.toString(), sink);
} catch (MissingResourceException e) {
diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/MeasureUnit.java b/icu4j/main/classes/core/src/com/ibm/icu/util/MeasureUnit.java
index c2e0c04e5db..3c46c06606d 100644
--- a/icu4j/main/classes/core/src/com/ibm/icu/util/MeasureUnit.java
+++ b/icu4j/main/classes/core/src/com/ibm/icu/util/MeasureUnit.java
@@ -610,6 +610,13 @@ public class MeasureUnit implements Serializable {
*/
public static final TimeUnit DAY = (TimeUnit) MeasureUnit.internalGetInstance("duration", "day");
+ /**
+ * Constant for unit of duration: day-person
+ * @draft ICU 64
+ * @provisional This API might change or be removed in a future release.
+ */
+ public static final MeasureUnit DAY_PERSON = MeasureUnit.internalGetInstance("duration", "day-person");
+
/**
* Constant for unit of duration: hour
* @stable ICU 4.0
@@ -640,6 +647,13 @@ public class MeasureUnit implements Serializable {
*/
public static final TimeUnit MONTH = (TimeUnit) MeasureUnit.internalGetInstance("duration", "month");
+ /**
+ * Constant for unit of duration: month-person
+ * @draft ICU 64
+ * @provisional This API might change or be removed in a future release.
+ */
+ public static final MeasureUnit MONTH_PERSON = MeasureUnit.internalGetInstance("duration", "month-person");
+
/**
* Constant for unit of duration: nanosecond
* @stable ICU 54
@@ -658,12 +672,26 @@ public class MeasureUnit implements Serializable {
*/
public static final TimeUnit WEEK = (TimeUnit) MeasureUnit.internalGetInstance("duration", "week");
+ /**
+ * Constant for unit of duration: week-person
+ * @draft ICU 64
+ * @provisional This API might change or be removed in a future release.
+ */
+ public static final MeasureUnit WEEK_PERSON = MeasureUnit.internalGetInstance("duration", "week-person");
+
/**
* Constant for unit of duration: year
* @stable ICU 4.0
*/
public static final TimeUnit YEAR = (TimeUnit) MeasureUnit.internalGetInstance("duration", "year");
+ /**
+ * Constant for unit of duration: year-person
+ * @draft ICU 64
+ * @provisional This API might change or be removed in a future release.
+ */
+ public static final MeasureUnit YEAR_PERSON = MeasureUnit.internalGetInstance("duration", "year-person");
+
/**
* Constant for unit of electric: ampere
* @stable ICU 54
diff --git a/icu4j/main/shared/data/icudata.jar b/icu4j/main/shared/data/icudata.jar
index d2de6e8764d..f7f146e8d1f 100644
--- a/icu4j/main/shared/data/icudata.jar
+++ b/icu4j/main/shared/data/icudata.jar
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:22491b0308503cc3a472815b978444811c3ab5fcf7cae071832c39a7ba178465
-size 12694176
+oid sha256:bff554a5fd35fddf6a105bb560ec56d120cee51c4655e941f2306a90297ebe53
+size 12696138
diff --git a/icu4j/main/shared/data/icutzdata.jar b/icu4j/main/shared/data/icutzdata.jar
index 26ce352ba30..aabfe5762cd 100644
--- a/icu4j/main/shared/data/icutzdata.jar
+++ b/icu4j/main/shared/data/icutzdata.jar
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:d72644d74c804bede2359aa1ae18164b45dbab98d997826c98e82dca5dd685e9
-size 94046
+oid sha256:9e8b58bfaaf6e5d236337ee6bc0a7aee7dcb32e5d7054a8bd584650416490d2f
+size 94059
diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java
index c843e9abd4e..76548071e1b 100644
--- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java
+++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java
@@ -2193,6 +2193,34 @@ public class MeasureUnitTest extends TestFmwk {
// Should not throw an exception.
}
+ @Test
+ public void test20332_PersonUnits() {
+ Object[][] cases = new Object[][] {
+ {ULocale.US, MeasureUnit.YEAR_PERSON, MeasureFormat.FormatWidth.NARROW, "25y"},
+ {ULocale.US, MeasureUnit.YEAR_PERSON, MeasureFormat.FormatWidth.SHORT, "25 yrs"},
+ {ULocale.US, MeasureUnit.YEAR_PERSON, MeasureFormat.FormatWidth.WIDE, "25 years"},
+ {ULocale.US, MeasureUnit.MONTH_PERSON, MeasureFormat.FormatWidth.NARROW, "25m"},
+ {ULocale.US, MeasureUnit.MONTH_PERSON, MeasureFormat.FormatWidth.SHORT, "25 mths"},
+ {ULocale.US, MeasureUnit.MONTH_PERSON, MeasureFormat.FormatWidth.WIDE, "25 months"},
+ {ULocale.US, MeasureUnit.WEEK_PERSON, MeasureFormat.FormatWidth.NARROW, "25w"},
+ {ULocale.US, MeasureUnit.WEEK_PERSON, MeasureFormat.FormatWidth.SHORT, "25 wks"},
+ {ULocale.US, MeasureUnit.WEEK_PERSON, MeasureFormat.FormatWidth.WIDE, "25 weeks"},
+ {ULocale.US, MeasureUnit.DAY_PERSON, MeasureFormat.FormatWidth.NARROW, "25d"},
+ {ULocale.US, MeasureUnit.DAY_PERSON, MeasureFormat.FormatWidth.SHORT, "25 days"},
+ {ULocale.US, MeasureUnit.DAY_PERSON, MeasureFormat.FormatWidth.WIDE, "25 days"}
+ };
+ for (Object[] cas : cases) {
+ ULocale locale = (ULocale) cas[0];
+ MeasureUnit unit = (MeasureUnit) cas[1];
+ MeasureFormat.FormatWidth width = (MeasureFormat.FormatWidth) cas[2];
+ String expected = (String) cas[3];
+
+ MeasureFormat fmt = MeasureFormat.getInstance(locale, width);
+ String result = fmt.formatMeasures(new Measure(25, unit));
+ assertEquals("" + locale + " " + unit + " " + width, expected, result);
+ }
+ }
+
// DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code
// for MeasureFormat during the release process.
static Map> getUnitsToPerParts() {