1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 **********************************************************************
5 * Copyright (c) 2004-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
9 * Created: April 20, 2004
11 **********************************************************************
13 #include "utypeinfo.h" // for 'typeid' to work
14 #include "unicode/utypes.h"
16 #if !UCONFIG_NO_FORMATTING
18 #include "unicode/measfmt.h"
19 #include "unicode/numfmt.h"
21 #include "unicode/localpointer.h"
23 #include "unicode/simpleformatter.h"
24 #include "quantityformatter.h"
25 #include "unicode/plurrule.h"
26 #include "unicode/decimfmt.h"
28 #include "unicode/ures.h"
29 #include "unicode/ustring.h"
34 #include "unicode/listformatter.h"
36 #include "unicode/putil.h"
37 #include "unicode/smpdtfmt.h"
39 #include "unicode/numberformatter.h"
40 #include "number_longnames.h"
42 #include "unicode/uameasureformat.h"
45 #include "sharednumberformat.h"
46 #include "sharedpluralrules.h"
47 #include "standardplural.h"
48 #include "unifiedcache.h"
53 static constexpr int32_t WIDTH_INDEX_COUNT
= UMEASFMT_WIDTH_NARROW
+ 1;
55 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat
)
57 // Used to format durations like 5:47 or 21:35:42.
58 class NumericDateFormatters
: public UMemory
{
61 SimpleDateFormat hourMinute
;
64 SimpleDateFormat minuteSecond
;
66 // formats like H:mm:ss
67 SimpleDateFormat hourMinuteSecond
;
69 // Constructor that takes the actual patterns for hour-minute,
70 // minute-second, and hour-minute-second respectively.
71 NumericDateFormatters(
72 const UnicodeString
&hm
,
73 const UnicodeString
&ms
,
74 const UnicodeString
&hms
,
76 hourMinute(hm
, status
),
77 minuteSecond(ms
, status
),
78 hourMinuteSecond(hms
, status
) {
79 const TimeZone
*gmt
= TimeZone::getGMT();
80 hourMinute
.setTimeZone(*gmt
);
81 minuteSecond
.setTimeZone(*gmt
);
82 hourMinuteSecond
.setTimeZone(*gmt
);
85 NumericDateFormatters(const NumericDateFormatters
&other
);
86 NumericDateFormatters
&operator=(const NumericDateFormatters
&other
);
89 static UMeasureFormatWidth
getRegularWidth(UMeasureFormatWidth width
) {
90 if (width
>= WIDTH_INDEX_COUNT
) {
91 return UMEASFMT_WIDTH_NARROW
;
96 static UNumberUnitWidth
getUnitWidth(UMeasureFormatWidth width
) {
98 case UMEASFMT_WIDTH_WIDE
:
99 return UNUM_UNIT_WIDTH_FULL_NAME
;
100 case UMEASFMT_WIDTH_NARROW
:
101 case UMEASFMT_WIDTH_NUMERIC
:
102 return UNUM_UNIT_WIDTH_NARROW
;
103 case UMEASFMT_WIDTH_SHORT
:
105 return UNUM_UNIT_WIDTH_SHORT
;
110 * Instances contain all MeasureFormat specific data for a particular locale.
111 * This data is cached. It is never copied, but is shared via shared pointers.
113 * Note: We might change the cache data to have an array[WIDTH_INDEX_COUNT] of
114 * complete sets of unit & per patterns,
115 * to correspond to the resource data and its aliases.
117 * TODO: Maybe store more sparsely in general, with pointers rather than potentially-empty objects.
119 class MeasureFormatCacheData
: public SharedObject
{
123 * Redirection data from root-bundle, top-level sideways aliases.
124 * - UMEASFMT_WIDTH_COUNT: initial value, just fall back to root
125 * - UMEASFMT_WIDTH_WIDE/SHORT/NARROW: sideways alias for missing data
127 UMeasureFormatWidth widthFallback
[WIDTH_INDEX_COUNT
];
129 MeasureFormatCacheData();
130 virtual ~MeasureFormatCacheData();
132 void adoptCurrencyFormat(int32_t widthIndex
, NumberFormat
*nfToAdopt
) {
133 delete currencyFormats
[widthIndex
];
134 currencyFormats
[widthIndex
] = nfToAdopt
;
136 const NumberFormat
*getCurrencyFormat(UMeasureFormatWidth width
) const {
137 return currencyFormats
[getRegularWidth(width
)];
139 void adoptIntegerFormat(NumberFormat
*nfToAdopt
) {
140 delete integerFormat
;
141 integerFormat
= nfToAdopt
;
143 const NumberFormat
*getIntegerFormat() const {
144 return integerFormat
;
146 void adoptNumericDateFormatters(NumericDateFormatters
*formattersToAdopt
) {
147 delete numericDateFormatters
;
148 numericDateFormatters
= formattersToAdopt
;
150 const NumericDateFormatters
*getNumericDateFormatters() const {
151 return numericDateFormatters
;
155 NumberFormat
* currencyFormats
[WIDTH_INDEX_COUNT
];
156 NumberFormat
* integerFormat
;
157 NumericDateFormatters
* numericDateFormatters
;
159 MeasureFormatCacheData(const MeasureFormatCacheData
&other
);
160 MeasureFormatCacheData
&operator=(const MeasureFormatCacheData
&other
);
163 MeasureFormatCacheData::MeasureFormatCacheData()
164 : integerFormat(nullptr), numericDateFormatters(nullptr) {
165 for (int32_t i
= 0; i
< WIDTH_INDEX_COUNT
; ++i
) {
166 widthFallback
[i
] = UMEASFMT_WIDTH_COUNT
;
168 memset(currencyFormats
, 0, sizeof(currencyFormats
));
171 MeasureFormatCacheData::~MeasureFormatCacheData() {
172 for (int32_t i
= 0; i
< UPRV_LENGTHOF(currencyFormats
); ++i
) {
173 delete currencyFormats
[i
];
175 // Note: the contents of 'dnams' are pointers into the resource bundle
176 delete integerFormat
;
177 delete numericDateFormatters
;
180 static UBool
isCurrency(const MeasureUnit
&unit
) {
181 return (uprv_strcmp(unit
.getType(), "currency") == 0);
184 static UBool
getString(
185 const UResourceBundle
*resource
,
186 UnicodeString
&result
,
187 UErrorCode
&status
) {
189 const UChar
*resStr
= ures_getString(resource
, &len
, &status
);
190 if (U_FAILURE(status
)) {
193 result
.setTo(TRUE
, resStr
, len
);
197 static const UAMeasureUnit indexToUAMsasUnit
[] = {
198 // UAMeasureUnit // UAMeasUnit vals # MeasUnit.getIndex()
199 // # --- acceleration (0)
200 UAMEASUNIT_ACCELERATION_G_FORCE
, // (0 << 8) + 0, # 0 g-force
201 UAMEASUNIT_ACCELERATION_METER_PER_SECOND_SQUARED
, // (0 << 8) + 1, # 1 meter-per-second-squared
203 UAMEASUNIT_ANGLE_ARC_MINUTE
, // (1 << 8) + 1, # 2 arc-minute
204 UAMEASUNIT_ANGLE_ARC_SECOND
, // (1 << 8) + 2, # 3 arc-second
205 UAMEASUNIT_ANGLE_DEGREE
, // (1 << 8) + 0, # 4 degree
206 UAMEASUNIT_ANGLE_RADIAN
, // (1 << 8) + 3, # 5 radian
207 UAMEASUNIT_ANGLE_REVOLUTION
, // (1 << 8) + 4, # 6 revolution
209 UAMEASUNIT_AREA_ACRE
, // (2 << 8) + 4, # 7 acre
210 UAMEASUNIT_AREA_DUNAM
, // (2 << 8) + 9, # 8 dunam
211 UAMEASUNIT_AREA_HECTARE
, // (2 << 8) + 5, # 9 hectare
212 UAMEASUNIT_AREA_SQUARE_CENTIMETER
, // (2 << 8) + 6, # 10 square-centimeter
213 UAMEASUNIT_AREA_SQUARE_FOOT
, // (2 << 8) + 2, # 11 square-foot
214 UAMEASUNIT_AREA_SQUARE_INCH
, // (2 << 8) + 7, # 12 square-inch
215 UAMEASUNIT_AREA_SQUARE_KILOMETER
, // (2 << 8) + 1, # 13 square-kilometer
216 UAMEASUNIT_AREA_SQUARE_METER
, // (2 << 8) + 0, # 14 square-meter
217 UAMEASUNIT_AREA_SQUARE_MILE
, // (2 << 8) + 3, # 15 square-mile
218 UAMEASUNIT_AREA_SQUARE_YARD
, // (2 << 8) + 8, # 16 square-yard
219 // # --- concentr (17)
220 UAMEASUNIT_CONCENTRATION_KARAT
, // (18 << 8) + 0, # 17 karat
221 UAMEASUNIT_CONCENTRATION_MILLIGRAM_PER_DECILITER
, // (18 << 8) + 1, # 18 milligram-per-deciliter
222 UAMEASUNIT_CONCENTRATION_MILLIMOLE_PER_LITER
, // (18 << 8) + 2, # 19 millimole-per-liter
223 UAMEASUNIT_CONCENTRATION_MOLE
, // (18 << 8) + 7, # 20 mole
224 UAMEASUNIT_CONCENTRATION_PART_PER_MILLION
, // (18 << 8) + 3, # 21 part-per-million
225 UAMEASUNIT_CONCENTRATION_PERCENT
, // (18 << 8) + 4, # 22 percent
226 UAMEASUNIT_CONCENTRATION_PERMILLE
, // (18 << 8) + 5, # 23 permille
227 UAMEASUNIT_CONCENTRATION_PERMYRIAD
, // (18 << 8) + 6, # 24 permyriad
228 // # --- consumption (25)
229 UAMEASUNIT_CONSUMPTION_LITER_PER_100_KILOMETERs
, // (13 << 8) + 2, # 25 liter-per-100kilometers
230 UAMEASUNIT_CONSUMPTION_LITER_PER_KILOMETER
, // (13 << 8) + 0, # 26 liter-per-kilometer
231 UAMEASUNIT_CONSUMPTION_MILE_PER_GALLON
, // (13 << 8) + 1, # 27 mile-per-gallon
232 UAMEASUNIT_CONSUMPTION_MILE_PER_GALLON_IMPERIAL
, // (13 << 8) + 3, # 28 mile-per-gallon-imperial
233 // # --- currency (29)
234 // # --- digital (29)
235 UAMEASUNIT_DIGITAL_BIT
, // (14 << 8) + 0, # 29 bit
236 UAMEASUNIT_DIGITAL_BYTE
, // (14 << 8) + 1, # 30 byte
237 UAMEASUNIT_DIGITAL_GIGABIT
, // (14 << 8) + 2, # 31 gigabit
238 UAMEASUNIT_DIGITAL_GIGABYTE
, // (14 << 8) + 3, # 32 gigabyte
239 UAMEASUNIT_DIGITAL_KILOBIT
, // (14 << 8) + 4, # 33 kilobit
240 UAMEASUNIT_DIGITAL_KILOBYTE
, // (14 << 8) + 5, # 34 kilobyte
241 UAMEASUNIT_DIGITAL_MEGABIT
, // (14 << 8) + 6, # 35 megabit
242 UAMEASUNIT_DIGITAL_MEGABYTE
, // (14 << 8) + 7, # 36 megabyte
243 UAMEASUNIT_DIGITAL_PETABYTE
, // (14 << 8) + 10, # 37 petabyte
244 UAMEASUNIT_DIGITAL_TERABIT
, // (14 << 8) + 8, # 38 terabit
245 UAMEASUNIT_DIGITAL_TERABYTE
, // (14 << 8) + 9, # 39 terabyte
246 // # --- duration (40)
247 UAMEASUNIT_DURATION_CENTURY
, // (4 << 8) + 10, # 40 century
248 UAMEASUNIT_DURATION_DAY
, // (4 << 8) + 3, # 41 day
249 UAMEASUNIT_DURATION_DAY_PERSON
, // (4 << 8) + 14, # 42 day-person
250 UAMEASUNIT_DURATION_HOUR
, // (4 << 8) + 4, # 43 hour
251 UAMEASUNIT_DURATION_MICROSECOND
, // (4 << 8) + 8, # 44 microsecond
252 UAMEASUNIT_DURATION_MILLISECOND
, // (4 << 8) + 7, # 45 millisecond
253 UAMEASUNIT_DURATION_MINUTE
, // (4 << 8) + 5, # 46 minute
254 UAMEASUNIT_DURATION_MONTH
, // (4 << 8) + 1, # 47 month
255 UAMEASUNIT_DURATION_MONTH_PERSON
, // (4 << 8) + 12, # 48 month-person
256 UAMEASUNIT_DURATION_NANOSECOND
, // (4 << 8) + 9, # 49 nanosecond
257 UAMEASUNIT_DURATION_SECOND
, // (4 << 8) + 6, # 50 second
258 UAMEASUNIT_DURATION_WEEK
, // (4 << 8) + 2, # 51 week
259 UAMEASUNIT_DURATION_WEEK_PERSON
, // (4 << 8) + 13, # 52 week-person
260 UAMEASUNIT_DURATION_YEAR
, // (4 << 8) + 0, # 53 year
261 UAMEASUNIT_DURATION_YEAR_PERSON
, // (4 << 8) + 11, # 54 year-person
262 // # --- electric (55)
263 UAMEASUNIT_ELECTRIC_AMPERE
, // (15 << 8) + 0, # 55 ampere
264 UAMEASUNIT_ELECTRIC_MILLIAMPERE
, // (15 << 8) + 1, # 56 milliampere
265 UAMEASUNIT_ELECTRIC_OHM
, // (15 << 8) + 2, # 57 ohm
266 UAMEASUNIT_ELECTRIC_VOLT
, // (15 << 8) + 3, # 58 volt
268 UAMEASUNIT_ENERGY_BRITISH_THERMAL_UNIT
, // (12 << 8) + 7, # 59 british-thermal-unit
269 UAMEASUNIT_ENERGY_CALORIE
, // (12 << 8) + 0, # 60 calorie
270 UAMEASUNIT_ENERGY_ELECTRONVOLT
, // (12 << 8) + 6, # 61 electronvolt
271 UAMEASUNIT_ENERGY_FOODCALORIE
, // (12 << 8) + 1, # 62 foodcalorie
272 UAMEASUNIT_ENERGY_JOULE
, // (12 << 8) + 2, # 63 joule
273 UAMEASUNIT_ENERGY_KILOCALORIE
, // (12 << 8) + 3, # 64 kilocalorie
274 UAMEASUNIT_ENERGY_KILOJOULE
, // (12 << 8) + 4, # 65 kilojoule
275 UAMEASUNIT_ENERGY_KILOWATT_HOUR
, // (12 << 8) + 5, # 66 kilowatt-hour
277 UAMEASUNIT_FORCE_NEWTON
, // (19 << 8) + 0, # 67 newton
278 UAMEASUNIT_FORCE_POUND_FORCE
, // (19 << 8) + 1, # 68 pound-force
279 // # --- frequency (69)
280 UAMEASUNIT_FREQUENCY_GIGAHERTZ
, // (16 << 8) + 3, # 69 gigahertz
281 UAMEASUNIT_FREQUENCY_HERTZ
, // (16 << 8) + 0, # 70 hertz
282 UAMEASUNIT_FREQUENCY_KILOHERTZ
, // (16 << 8) + 1, # 71 kilohertz
283 UAMEASUNIT_FREQUENCY_MEGAHERTZ
, // (16 << 8) + 2, # 72 megahertz
285 UAMEASUNIT_LENGTH_ASTRONOMICAL_UNIT
, // (5 << 8) + 16, # 73 astronomical-unit
286 UAMEASUNIT_LENGTH_CENTIMETER
, // (5 << 8) + 1, # 74 centimeter
287 UAMEASUNIT_LENGTH_DECIMETER
, // (5 << 8) + 10, # 75 decimeter
288 UAMEASUNIT_LENGTH_FATHOM
, // (5 << 8) + 14, # 76 fathom
289 UAMEASUNIT_LENGTH_FOOT
, // (5 << 8) + 5, # 77 foot
290 UAMEASUNIT_LENGTH_FURLONG
, // (5 << 8) + 15, # 78 furlong
291 UAMEASUNIT_LENGTH_INCH
, // (5 << 8) + 6, # 79 inch
292 UAMEASUNIT_LENGTH_KILOMETER
, // (5 << 8) + 2, # 80 kilometer
293 UAMEASUNIT_LENGTH_LIGHT_YEAR
, // (5 << 8) + 9, # 81 light-year
294 UAMEASUNIT_LENGTH_METER
, // (5 << 8) + 0, # 82 meter
295 UAMEASUNIT_LENGTH_MICROMETER
, // (5 << 8) + 11, # 83 micrometer
296 UAMEASUNIT_LENGTH_MILE
, // (5 << 8) + 7, # 84 mile
297 UAMEASUNIT_LENGTH_MILE_SCANDINAVIAN
, // (5 << 8) + 18, # 85 mile-scandinavian
298 UAMEASUNIT_LENGTH_MILLIMETER
, // (5 << 8) + 3, # 86 millimeter
299 UAMEASUNIT_LENGTH_NANOMETER
, // (5 << 8) + 12, # 87 nanometer
300 UAMEASUNIT_LENGTH_NAUTICAL_MILE
, // (5 << 8) + 13, # 88 nautical-mile
301 UAMEASUNIT_LENGTH_PARSEC
, // (5 << 8) + 17, # 89 parsec
302 UAMEASUNIT_LENGTH_PICOMETER
, // (5 << 8) + 4, # 90 picometer
303 UAMEASUNIT_LENGTH_POINT
, // (5 << 8) + 19, # 91 point
304 UAMEASUNIT_LENGTH_SOLAR_RADIUS
, // (5 << 8) + 20, # 92 solar-radius
305 UAMEASUNIT_LENGTH_YARD
, // (5 << 8) + 8, # 93 yard
307 UAMEASUNIT_LIGHT_LUX
, // (17 << 8) + 0, # 94 lux
308 UAMEASUNIT_LIGHT_SOLAR_LUMINOSITY
, // (17 << 8) + 1, # 95 solar-luminosity
310 UAMEASUNIT_MASS_CARAT
, // (6 << 8) + 9, # 96 carat
311 UAMEASUNIT_MASS_DALTON
, // (6 << 8) + 11, # 97 dalton
312 UAMEASUNIT_MASS_EARTH_MASS
, // (6 << 8) + 12, # 98 earth-mass
313 UAMEASUNIT_MASS_GRAM
, // (6 << 8) + 0, # 99 gram
314 UAMEASUNIT_MASS_KILOGRAM
, // (6 << 8) + 1, # 100 kilogram
315 UAMEASUNIT_MASS_METRIC_TON
, // (6 << 8) + 7, # 101 metric-ton
316 UAMEASUNIT_MASS_MICROGRAM
, // (6 << 8) + 5, # 102 microgram
317 UAMEASUNIT_MASS_MILLIGRAM
, // (6 << 8) + 6, # 103 milligram
318 UAMEASUNIT_MASS_OUNCE
, // (6 << 8) + 2, # 104 ounce
319 UAMEASUNIT_MASS_OUNCE_TROY
, // (6 << 8) + 10, # 105 ounce-troy
320 UAMEASUNIT_MASS_POUND
, // (6 << 8) + 3, # 106 pound
321 UAMEASUNIT_MASS_SOLAR_MASS
, // (6 << 8) + 13, # 107 solar-mass
322 UAMEASUNIT_MASS_STONE
, // (6 << 8) + 4, # 108 stone
323 UAMEASUNIT_MASS_TON
, // (6 << 8) + 8, # 109 ton
325 UAMEASUNIT_CONCENTRATION_PERCENT
, // BOGUS # 110 base
326 UAMEASUNIT_CONCENTRATION_PERCENT
, // BOGUS # 111 percent
327 UAMEASUNIT_CONCENTRATION_PERMILLE
, // BOGUS # 112 permille
329 UAMEASUNIT_POWER_GIGAWATT
, // (7 << 8) + 5, # 113 gigawatt
330 UAMEASUNIT_POWER_HORSEPOWER
, // (7 << 8) + 2, # 114 horsepower
331 UAMEASUNIT_POWER_KILOWATT
, // (7 << 8) + 1, # 115 kilowatt
332 UAMEASUNIT_POWER_MEGAWATT
, // (7 << 8) + 4, # 116 megawatt
333 UAMEASUNIT_POWER_MILLIWATT
, // (7 << 8) + 3, # 117 milliwatt
334 UAMEASUNIT_POWER_WATT
, // (7 << 8) + 0, # 118 watt
335 // # --- pressure (119)
336 UAMEASUNIT_PRESSURE_ATMOSPHERE
, // (8 << 8) + 5, # 119 atmosphere
337 UAMEASUNIT_PRESSURE_HECTOPASCAL
, // (8 << 8) + 0, # 120 hectopascal
338 UAMEASUNIT_PRESSURE_INCH_HG
, // (8 << 8) + 1, # 121 inch-hg
339 UAMEASUNIT_PRESSURE_KILOPASCAL
, // (8 << 8) + 6, # 122 kilopascal
340 UAMEASUNIT_PRESSURE_MEGAPASCAL
, // (8 << 8) + 7, # 123 megapascal
341 UAMEASUNIT_PRESSURE_MILLIBAR
, // (8 << 8) + 2, # 124 millibar
342 UAMEASUNIT_PRESSURE_MILLIMETER_OF_MERCURY
, // (8 << 8) + 3, # 125 millimeter-of-mercury
343 UAMEASUNIT_PRESSURE_POUND_PER_SQUARE_INCH
, // (8 << 8) + 4, # 126 pound-per-square-inch
345 UAMEASUNIT_SPEED_KILOMETER_PER_HOUR
, // (9 << 8) + 1, # 127 kilometer-per-hour
346 UAMEASUNIT_SPEED_KNOT
, // (9 << 8) + 3, # 128 knot
347 UAMEASUNIT_SPEED_METER_PER_SECOND
, // (9 << 8) + 0, # 129 meter-per-second
348 UAMEASUNIT_SPEED_MILE_PER_HOUR
, // (9 << 8) + 2, # 130 mile-per-hour
349 // # --- temperature (131)
350 UAMEASUNIT_TEMPERATURE_CELSIUS
, // (10 << 8) + 0, # 131 celsius
351 UAMEASUNIT_TEMPERATURE_FAHRENHEIT
, // (10 << 8) + 1, # 132 fahrenheit
352 UAMEASUNIT_TEMPERATURE_GENERIC
, // (10 << 8) + 3, # 133 generic
353 UAMEASUNIT_TEMPERATURE_KELVIN
, // (10 << 8) + 2, # 134 kelvin
354 // # --- torque (135)
355 UAMEASUNIT_TORQUE_NEWTON_METER
, // (20 << 8) + 0, # 135 newton-meter
356 UAMEASUNIT_TORQUE_POUND_FOOT
, // (20 << 8) + 1, # 136 pound-foot
357 // # --- volume (137)
358 UAMEASUNIT_VOLUME_ACRE_FOOT
, // (11 << 8) + 13, # 137 acre-foot
359 UAMEASUNIT_VOLUME_BARREL
, // (11 << 8) + 26, # 138 barrel
360 UAMEASUNIT_VOLUME_BUSHEL
, // (11 << 8) + 14, # 139 bushel
361 UAMEASUNIT_VOLUME_CENTILITER
, // (11 << 8) + 4, # 140 centiliter
362 UAMEASUNIT_VOLUME_CUBIC_CENTIMETER
, // (11 << 8) + 8, # 141 cubic-centimeter
363 UAMEASUNIT_VOLUME_CUBIC_FOOT
, // (11 << 8) + 11, # 142 cubic-foot
364 UAMEASUNIT_VOLUME_CUBIC_INCH
, // (11 << 8) + 10, # 143 cubic-inch
365 UAMEASUNIT_VOLUME_CUBIC_KILOMETER
, // (11 << 8) + 1, # 144 cubic-kilometer
366 UAMEASUNIT_VOLUME_CUBIC_METER
, // (11 << 8) + 9, # 145 cubic-meter
367 UAMEASUNIT_VOLUME_CUBIC_MILE
, // (11 << 8) + 2, # 146 cubic-mile
368 UAMEASUNIT_VOLUME_CUBIC_YARD
, // (11 << 8) + 12, # 147 cubic-yard
369 UAMEASUNIT_VOLUME_CUP
, // (11 << 8) + 18, # 148 cup
370 UAMEASUNIT_VOLUME_CUP_METRIC
, // (11 << 8) + 22, # 149 cup-metric
371 UAMEASUNIT_VOLUME_DECILITER
, // (11 << 8) + 5, # 150 deciliter
372 UAMEASUNIT_VOLUME_FLUID_OUNCE
, // (11 << 8) + 17, # 151 fluid-ounce
373 UAMEASUNIT_VOLUME_FLUID_OUNCE_IMPERIAL
, // (11 << 8) + 25, # 152 fluid-ounce-imperial
374 UAMEASUNIT_VOLUME_GALLON
, // (11 << 8) + 21, # 153 gallon
375 UAMEASUNIT_VOLUME_GALLON_IMPERIAL
, // (11 << 8) + 24, # 154 gallon-imperial
376 UAMEASUNIT_VOLUME_HECTOLITER
, // (11 << 8) + 6, # 155 hectoliter
377 UAMEASUNIT_VOLUME_LITER
, // (11 << 8) + 0, # 156 liter
378 UAMEASUNIT_VOLUME_MEGALITER
, // (11 << 8) + 7, # 157 megaliter
379 UAMEASUNIT_VOLUME_MILLILITER
, // (11 << 8) + 3, # 158 milliliter
380 UAMEASUNIT_VOLUME_PINT
, // (11 << 8) + 19, # 159 pint
381 UAMEASUNIT_VOLUME_PINT_METRIC
, // (11 << 8) + 23, # 160 pint-metric
382 UAMEASUNIT_VOLUME_QUART
, // (11 << 8) + 20, # 161 quart
383 UAMEASUNIT_VOLUME_TABLESPOON
, // (11 << 8) + 16, # 162 tablespoon
384 UAMEASUNIT_VOLUME_TEASPOON
, // (11 << 8) + 15, # 163 teaspoon
387 static UnicodeString
loadNumericDateFormatterPattern(
388 const UResourceBundle
*resource
,
390 UErrorCode
&status
) {
391 UnicodeString result
;
392 if (U_FAILURE(status
)) {
396 chs
.append("durationUnits", status
)
397 .append("/", status
).append(pattern
, status
);
398 LocalUResourceBundlePointer
patternBundle(
399 ures_getByKeyWithFallback(
404 if (U_FAILURE(status
)) {
407 getString(patternBundle
.getAlias(), result
, status
);
408 // Replace 'h' with 'H'
409 int32_t len
= result
.length();
410 UChar
*buffer
= result
.getBuffer(len
);
411 for (int32_t i
= 0; i
< len
; ++i
) {
412 if (buffer
[i
] == 0x68) { // 'h'
413 buffer
[i
] = 0x48; // 'H'
416 result
.releaseBuffer(len
);
420 static NumericDateFormatters
*loadNumericDateFormatters(
421 const UResourceBundle
*resource
,
422 UErrorCode
&status
) {
423 if (U_FAILURE(status
)) {
426 NumericDateFormatters
*result
= new NumericDateFormatters(
427 loadNumericDateFormatterPattern(resource
, "hm", status
),
428 loadNumericDateFormatterPattern(resource
, "ms", status
),
429 loadNumericDateFormatterPattern(resource
, "hms", status
),
431 if (U_FAILURE(status
)) {
438 template<> U_I18N_API
439 const MeasureFormatCacheData
*LocaleCacheKey
<MeasureFormatCacheData
>::createObject(
440 const void * /*unused*/, UErrorCode
&status
) const {
441 const char *localeId
= fLoc
.getName();
442 LocalUResourceBundlePointer
unitsBundle(ures_open(U_ICUDATA_UNIT
, localeId
, &status
));
443 static UNumberFormatStyle currencyStyles
[] = {
444 UNUM_CURRENCY_PLURAL
, UNUM_CURRENCY_ISO
, UNUM_CURRENCY
};
445 LocalPointer
<MeasureFormatCacheData
> result(new MeasureFormatCacheData(), status
);
446 if (U_FAILURE(status
)) {
449 result
->adoptNumericDateFormatters(loadNumericDateFormatters(
450 unitsBundle
.getAlias(), status
));
451 if (U_FAILURE(status
)) {
455 for (int32_t i
= 0; i
< WIDTH_INDEX_COUNT
; ++i
) {
456 // NumberFormat::createInstance can erase warning codes from status, so pass it
457 // a separate status instance
458 UErrorCode localStatus
= U_ZERO_ERROR
;
459 result
->adoptCurrencyFormat(i
, NumberFormat::createInstance(
460 localeId
, currencyStyles
[i
], localStatus
));
461 if (localStatus
!= U_ZERO_ERROR
) {
462 status
= localStatus
;
464 if (U_FAILURE(status
)) {
468 NumberFormat
*inf
= NumberFormat::createInstance(
469 localeId
, UNUM_DECIMAL
, status
);
470 if (U_FAILURE(status
)) {
473 inf
->setMaximumFractionDigits(0);
474 DecimalFormat
*decfmt
= dynamic_cast<DecimalFormat
*>(inf
);
475 if (decfmt
!= NULL
) {
476 decfmt
->setRoundingMode(DecimalFormat::kRoundDown
);
478 result
->adoptIntegerFormat(inf
);
480 return result
.orphan();
483 static UBool
isTimeUnit(const MeasureUnit
&mu
, const char *tu
) {
484 return uprv_strcmp(mu
.getType(), "duration") == 0 &&
485 uprv_strcmp(mu
.getSubtype(), tu
) == 0;
488 // Converts a composite measure into hours-minutes-seconds and stores at hms
489 // array. [0] is hours; [1] is minutes; [2] is seconds. Returns a bit map of
490 // units found: 1=hours, 2=minutes, 4=seconds. For example, if measures
491 // contains hours-minutes, this function would return 3.
493 // If measures cannot be converted into hours, minutes, seconds or if amounts
494 // are negative, or if hours, minutes, seconds are out of order, returns 0.
495 static int32_t toHMS(
496 const Measure
*measures
,
497 int32_t measureCount
,
499 UErrorCode
&status
) {
500 if (U_FAILURE(status
)) {
504 if (U_FAILURE(status
)) {
507 // We use copy constructor to ensure that both sides of equality operator
508 // are instances of MeasureUnit base class and not a subclass. Otherwise,
509 // operator== will immediately return false.
510 for (int32_t i
= 0; i
< measureCount
; ++i
) {
511 if (isTimeUnit(measures
[i
].getUnit(), "hour")) {
512 // hour must come first
516 hms
[0] = measures
[i
].getNumber();
517 if (hms
[0].getDouble() < 0.0) {
521 } else if (isTimeUnit(measures
[i
].getUnit(), "minute")) {
522 // minute must come after hour
526 hms
[1] = measures
[i
].getNumber();
527 if (hms
[1].getDouble() < 0.0) {
531 } else if (isTimeUnit(measures
[i
].getUnit(), "second")) {
532 // second must come after hour and minute
536 hms
[2] = measures
[i
].getNumber();
537 if (hms
[2].getDouble() < 0.0) {
549 MeasureFormat::MeasureFormat(
550 const Locale
&locale
, UMeasureFormatWidth w
, UErrorCode
&status
)
554 fWidth((w
==UMEASFMT_WIDTH_SHORTER
)? UMEASFMT_WIDTH_SHORT
: w
),
555 stripPatternSpaces(w
==UMEASFMT_WIDTH_SHORTER
),
557 listFormatterStd(NULL
) {
558 initMeasureFormat(locale
, (w
==UMEASFMT_WIDTH_SHORTER
)? UMEASFMT_WIDTH_SHORT
: w
, NULL
, status
);
561 MeasureFormat::MeasureFormat(
562 const Locale
&locale
,
563 UMeasureFormatWidth w
,
564 NumberFormat
*nfToAdopt
,
569 fWidth((w
==UMEASFMT_WIDTH_SHORTER
)? UMEASFMT_WIDTH_SHORT
: w
),
570 stripPatternSpaces(w
==UMEASFMT_WIDTH_SHORTER
),
572 listFormatterStd(NULL
) {
573 initMeasureFormat(locale
, (w
==UMEASFMT_WIDTH_SHORTER
)? UMEASFMT_WIDTH_SHORT
: w
, nfToAdopt
, status
);
576 MeasureFormat::MeasureFormat(const MeasureFormat
&other
) :
579 numberFormat(other
.numberFormat
),
580 pluralRules(other
.pluralRules
),
581 fWidth(other
.fWidth
),
582 stripPatternSpaces(other
.stripPatternSpaces
),
584 listFormatterStd(NULL
) {
586 numberFormat
->addRef();
587 pluralRules
->addRef();
588 if (other
.listFormatter
!= NULL
) {
589 listFormatter
= new ListFormatter(*other
.listFormatter
);
591 if (other
.listFormatterStd
!= NULL
) {
592 listFormatterStd
= new ListFormatter(*other
.listFormatterStd
);
596 MeasureFormat
&MeasureFormat::operator=(const MeasureFormat
&other
) {
597 if (this == &other
) {
600 Format::operator=(other
);
601 SharedObject::copyPtr(other
.cache
, cache
);
602 SharedObject::copyPtr(other
.numberFormat
, numberFormat
);
603 SharedObject::copyPtr(other
.pluralRules
, pluralRules
);
604 fWidth
= other
.fWidth
;
605 stripPatternSpaces
= other
.stripPatternSpaces
;
606 delete listFormatter
;
607 if (other
.listFormatter
!= NULL
) {
608 listFormatter
= new ListFormatter(*other
.listFormatter
);
610 listFormatter
= NULL
;
612 delete listFormatterStd
;
613 if (other
.listFormatterStd
!= NULL
) {
614 listFormatterStd
= new ListFormatter(*other
.listFormatterStd
);
616 listFormatterStd
= NULL
;
621 MeasureFormat::MeasureFormat() :
625 fWidth(UMEASFMT_WIDTH_SHORT
),
626 stripPatternSpaces(FALSE
),
628 listFormatterStd(NULL
) {
631 MeasureFormat::~MeasureFormat() {
635 if (numberFormat
!= NULL
) {
636 numberFormat
->removeRef();
638 if (pluralRules
!= NULL
) {
639 pluralRules
->removeRef();
641 delete listFormatter
;
642 delete listFormatterStd
;
645 UBool
MeasureFormat::operator==(const Format
&other
) const {
646 if (this == &other
) { // Same object, equal
649 if (!Format::operator==(other
)) {
652 const MeasureFormat
&rhs
= static_cast<const MeasureFormat
&>(other
);
654 // Note: Since the ListFormatter depends only on Locale and width, we
655 // don't have to check it here.
657 // differing widths aren't equivalent
658 if (fWidth
!= rhs
.fWidth
|| stripPatternSpaces
!= rhs
.stripPatternSpaces
) {
661 // Width the same check locales.
662 // We don't need to check locales if both objects have same cache.
663 if (cache
!= rhs
.cache
) {
664 UErrorCode status
= U_ZERO_ERROR
;
665 const char *localeId
= getLocaleID(status
);
666 const char *rhsLocaleId
= rhs
.getLocaleID(status
);
667 if (U_FAILURE(status
)) {
668 // On failure, assume not equal
671 if (uprv_strcmp(localeId
, rhsLocaleId
) != 0) {
675 // Locales same, check NumberFormat if shared data differs.
677 numberFormat
== rhs
.numberFormat
||
678 **numberFormat
== **rhs
.numberFormat
);
681 Format
*MeasureFormat::clone() const {
682 return new MeasureFormat(*this);
685 UnicodeString
&MeasureFormat::format(
686 const Formattable
&obj
,
687 UnicodeString
&appendTo
,
689 UErrorCode
&status
) const {
690 if (U_FAILURE(status
)) return appendTo
;
691 if (obj
.getType() == Formattable::kObject
) {
692 const UObject
* formatObj
= obj
.getObject();
693 const Measure
* amount
= dynamic_cast<const Measure
*>(formatObj
);
694 if (amount
!= NULL
) {
695 return formatMeasure(
696 *amount
, **numberFormat
, appendTo
, pos
, status
);
699 status
= U_ILLEGAL_ARGUMENT_ERROR
;
703 void MeasureFormat::parseObject(
704 const UnicodeString
& /*source*/,
705 Formattable
& /*result*/,
706 ParsePosition
& /*pos*/) const {
710 UnicodeString
&MeasureFormat::formatMeasurePerUnit(
711 const Measure
&measure
,
712 const MeasureUnit
&perUnit
,
713 UnicodeString
&appendTo
,
715 UErrorCode
&status
) const {
716 if (U_FAILURE(status
)) {
719 auto* df
= dynamic_cast<const DecimalFormat
*>(&getNumberFormatInternal());
721 // Don't know how to handle other types of NumberFormat
722 status
= U_UNSUPPORTED_ERROR
;
725 number::FormattedNumber result
;
726 if (auto* lnf
= df
->toNumberFormatter(status
)) {
727 result
= lnf
->unit(measure
.getUnit())
729 .unitWidth(getUnitWidth(fWidth
))
730 .formatDouble(measure
.getNumber().getDouble(status
), status
);
732 DecimalFormat::fieldPositionHelper(result
, pos
, appendTo
.length(), status
);
733 appendTo
.append(result
.toTempString(status
));
737 UnicodeString
&MeasureFormat::formatMeasures(
738 const Measure
*measures
,
739 int32_t measureCount
,
740 UnicodeString
&appendTo
,
742 UErrorCode
&status
) const {
743 if (U_FAILURE(status
)) {
746 if (measureCount
== 0) {
749 if (measureCount
== 1) {
750 return formatMeasure(measures
[0], **numberFormat
, appendTo
, pos
, status
);
752 if (fWidth
== UMEASFMT_WIDTH_NUMERIC
) {
754 int32_t bitMap
= toHMS(measures
, measureCount
, hms
, status
);
756 FieldPositionIteratorHandler
handler((FieldPositionIterator
*)NULL
, status
);
757 return formatNumeric(hms
, bitMap
, appendTo
, handler
, status
);
760 if (pos
.getField() != FieldPosition::DONT_CARE
) {
761 return formatMeasuresSlowTrack(
762 measures
, measureCount
, appendTo
, pos
, status
);
764 UnicodeString
*results
= new UnicodeString
[measureCount
];
765 if (results
== NULL
) {
766 status
= U_MEMORY_ALLOCATION_ERROR
;
769 for (int32_t i
= 0; i
< measureCount
; ++i
) {
770 const NumberFormat
*nf
= cache
->getIntegerFormat();
771 if (i
== measureCount
- 1) {
772 nf
= numberFormat
->get();
781 listFormatter
->format(results
, measureCount
, appendTo
, status
);
786 // Apple-specific version for now;
787 // uses FieldPositionIterator* instead of FieldPosition&
788 UnicodeString
&MeasureFormat::formatMeasures(
789 const Measure
*measures
,
790 int32_t measureCount
,
791 UnicodeString
&appendTo
,
792 FieldPositionIterator
* posIter
,
793 UErrorCode
&status
) const {
794 if (U_FAILURE(status
)) {
797 FieldPositionIteratorHandler
handler(posIter
, status
);
798 if (measureCount
== 0) {
801 if (measureCount
== 1) {
802 int32_t start
= appendTo
.length();
803 int32_t field
= indexToUAMsasUnit
[measures
[0].getUnit().getIndex()];
804 FieldPosition
pos(UAMEASFMT_NUMERIC_FIELD_FLAG
); // special field value to request range of entire numeric part
805 formatMeasure(measures
[0], **numberFormat
, appendTo
, pos
, status
);
806 handler
.addAttribute(field
, start
, appendTo
.length());
807 handler
.addAttribute(field
| UAMEASFMT_NUMERIC_FIELD_FLAG
, pos
.getBeginIndex(), pos
.getEndIndex());
810 if (fWidth
== UMEASFMT_WIDTH_NUMERIC
) {
812 int32_t bitMap
= toHMS(measures
, measureCount
, hms
, status
);
814 return formatNumeric(hms
, bitMap
, appendTo
, handler
, status
);
817 UnicodeString
*results
= new UnicodeString
[measureCount
];
818 if (results
== NULL
) {
819 status
= U_MEMORY_ALLOCATION_ERROR
;
822 FieldPosition
*numPositions
= new FieldPosition
[measureCount
];
823 if (results
== NULL
) {
825 status
= U_MEMORY_ALLOCATION_ERROR
;
829 for (int32_t i
= 0; i
< measureCount
; ++i
) {
830 const NumberFormat
*nf
= cache
->getIntegerFormat();
831 if (i
== measureCount
- 1) {
832 nf
= numberFormat
->get();
834 numPositions
[i
].setField(UAMEASFMT_NUMERIC_FIELD_FLAG
);
842 listFormatter
->format(results
, measureCount
, appendTo
, status
);
843 for (int32_t i
= 0; i
< measureCount
; ++i
) {
844 int32_t begin
= appendTo
.indexOf(results
[i
]);
846 int32_t field
= indexToUAMsasUnit
[measures
[i
].getUnit().getIndex()];
847 handler
.addAttribute(field
, begin
, begin
+ results
[i
].length());
848 int32_t numPosBegin
= numPositions
[i
].getBeginIndex();
849 int32_t numPosEnd
= numPositions
[i
].getEndIndex();
850 if (numPosBegin
>= 0 && numPosEnd
> numPosBegin
) {
851 handler
.addAttribute(field
| UAMEASFMT_NUMERIC_FIELD_FLAG
, begin
+ numPosBegin
, begin
+ numPosEnd
);
856 delete [] numPositions
;
860 UnicodeString
MeasureFormat::getUnitDisplayName(const MeasureUnit
& unit
, UErrorCode
& status
) const {
861 return number::impl::LongNameHandler::getUnitDisplayName(
864 getUnitWidth(fWidth
),
868 void MeasureFormat::initMeasureFormat(
869 const Locale
&locale
,
870 UMeasureFormatWidth w
,
871 NumberFormat
*nfToAdopt
,
872 UErrorCode
&status
) {
873 static const char *listStyles
[] = {"unit", "unit-short", "unit-narrow"};
874 LocalPointer
<NumberFormat
> nf(nfToAdopt
);
875 if (U_FAILURE(status
)) {
878 const char *name
= locale
.getName();
879 setLocaleIDs(name
, name
);
881 UnifiedCache::getByLocale(locale
, cache
, status
);
882 if (U_FAILURE(status
)) {
886 const SharedPluralRules
*pr
= PluralRules::createSharedInstance(
887 locale
, UPLURAL_TYPE_CARDINAL
, status
);
888 if (U_FAILURE(status
)) {
891 SharedObject::copyPtr(pr
, pluralRules
);
894 // TODO: Clean this up
895 const SharedNumberFormat
*shared
= NumberFormat::createSharedInstance(
896 locale
, UNUM_DECIMAL
, status
);
897 if (U_FAILURE(status
)) {
900 SharedObject::copyPtr(shared
, numberFormat
);
903 adoptNumberFormat(nf
.orphan(), status
);
904 if (U_FAILURE(status
)) {
909 if (stripPatternSpaces
) {
910 w
= UMEASFMT_WIDTH_NARROW
;
912 delete listFormatter
;
913 listFormatter
= ListFormatter::createInstance(
915 listStyles
[getRegularWidth(w
)],
917 delete listFormatterStd
;
918 listFormatterStd
= ListFormatter::createInstance(
924 void MeasureFormat::adoptNumberFormat(
925 NumberFormat
*nfToAdopt
, UErrorCode
&status
) {
926 LocalPointer
<NumberFormat
> nf(nfToAdopt
);
927 if (U_FAILURE(status
)) {
930 SharedNumberFormat
*shared
= new SharedNumberFormat(nf
.getAlias());
931 if (shared
== NULL
) {
932 status
= U_MEMORY_ALLOCATION_ERROR
;
936 SharedObject::copyPtr(shared
, numberFormat
);
939 UBool
MeasureFormat::setMeasureFormatLocale(const Locale
&locale
, UErrorCode
&status
) {
940 if (U_FAILURE(status
) || locale
== getLocale(status
)) {
943 initMeasureFormat(locale
, fWidth
, NULL
, status
);
944 return U_SUCCESS(status
);
947 // Apple-specific for now
948 UMeasureFormatWidth
MeasureFormat::getWidth() const {
952 const NumberFormat
&MeasureFormat::getNumberFormatInternal() const {
953 return **numberFormat
;
956 const NumberFormat
&MeasureFormat::getCurrencyFormatInternal() const {
957 return *cache
->getCurrencyFormat(UMEASFMT_WIDTH_NARROW
);
960 const PluralRules
&MeasureFormat::getPluralRules() const {
961 return **pluralRules
;
964 Locale
MeasureFormat::getLocale(UErrorCode
&status
) const {
965 return Format::getLocale(ULOC_VALID_LOCALE
, status
);
968 const char *MeasureFormat::getLocaleID(UErrorCode
&status
) const {
969 return Format::getLocaleID(ULOC_VALID_LOCALE
, status
);
973 // now just re-implement using standard getUnitDisplayName
974 // so we no longer use cache->getDisplayName
975 UnicodeString
&MeasureFormat::getUnitName(
976 const MeasureUnit
* unit
,
977 UnicodeString
&result
) const {
978 UErrorCode status
= U_ZERO_ERROR
;
979 result
= getUnitDisplayName(*unit
, status
); // does not use or set status
984 UnicodeString
&MeasureFormat::getMultipleUnitNames(
985 const MeasureUnit
** units
,
987 UAMeasureNameListStyle listStyle
,
988 UnicodeString
&result
) const {
989 if (unitCount
== 0) {
990 return result
.remove();
992 if (unitCount
== 1) {
993 return getUnitName(units
[0], result
);
995 UnicodeString
*results
= new UnicodeString
[unitCount
];
996 if (results
!= NULL
) {
997 for (int32_t i
= 0; i
< unitCount
; ++i
) {
998 getUnitName(units
[i
], results
[i
]);
1000 UErrorCode status
= U_ZERO_ERROR
;
1001 if (listStyle
== UAMEASNAME_LIST_STANDARD
) {
1002 listFormatterStd
->format(results
, unitCount
, result
, status
);
1004 listFormatter
->format(results
, unitCount
, result
, status
);
1007 if (U_SUCCESS(status
)) {
1011 result
.setToBogus();
1015 UnicodeString
&MeasureFormat::formatMeasure(
1016 const Measure
&measure
,
1017 const NumberFormat
&nf
,
1018 UnicodeString
&appendTo
,
1020 UErrorCode
&status
) const {
1021 if (U_FAILURE(status
)) {
1024 const Formattable
& amtNumber
= measure
.getNumber();
1025 const MeasureUnit
& amtUnit
= measure
.getUnit();
1026 if (isCurrency(amtUnit
)) {
1028 u_charsToUChars(amtUnit
.getSubtype(), isoCode
, 4);
1029 return cache
->getCurrencyFormat(fWidth
)->format(
1030 new CurrencyAmount(amtNumber
, isoCode
, status
),
1035 int32_t cur
= appendTo
.length();
1036 UBool posForFullNumericPart
= (pos
.getField() == UAMEASFMT_NUMERIC_FIELD_FLAG
);
1037 if (posForFullNumericPart
) {
1038 pos
.setField(FieldPosition::DONT_CARE
);
1041 auto* df
= dynamic_cast<const DecimalFormat
*>(&nf
);
1042 if (df
== nullptr) {
1043 // Handle other types of NumberFormat using the old code, Apple restore for <rdar://problem/49131922>
1044 UnicodeString formattedNumber
;
1045 StandardPlural::Form pluralForm
= QuantityFormatter::selectPlural(
1046 amtNumber
, nf
, **pluralRules
, formattedNumber
, pos
, status
);
1047 if (posForFullNumericPart
) {
1048 pos
.setField(UAMEASFMT_NUMERIC_FIELD_FLAG
);
1049 pos
.setBeginIndex(0);
1050 pos
.setEndIndex(formattedNumber
.length());
1052 UnicodeString pattern
= number::impl::LongNameHandler::getUnitPattern(getLocale(status
),
1053 amtUnit
, getUnitWidth(fWidth
), pluralForm
, status
);
1054 // The above already handles fallback from other widths to short
1055 if (pattern
.isBogus() && pluralForm
!= StandardPlural::Form::OTHER
) {
1056 pattern
= number::impl::LongNameHandler::getUnitPattern(getLocale(status
),
1057 amtUnit
, getUnitWidth(fWidth
), StandardPlural::Form::OTHER
, status
);
1059 if (U_FAILURE(status
)) {
1062 SimpleFormatter
formatter(pattern
, 0, 1, status
);
1063 QuantityFormatter::format(formatter
, formattedNumber
, appendTo
, pos
, status
);
1065 // This is the current code
1066 number::FormattedNumber result
;
1067 if (auto* lnf
= df
->toNumberFormatter(status
)) {
1068 result
= lnf
->unit(amtUnit
)
1069 .unitWidth(getUnitWidth(fWidth
))
1070 .formatDouble(amtNumber
.getDouble(status
), status
);
1072 DecimalFormat::fieldPositionHelper(result
, pos
, appendTo
.length(), status
);
1073 if (posForFullNumericPart
) {
1074 pos
.setField(UNUM_INTEGER_FIELD
);
1075 DecimalFormat::fieldPositionHelper(result
, pos
, appendTo
.length(), status
);
1076 int32_t intBegin
= pos
.getBeginIndex();
1077 int32_t intEnd
= pos
.getEndIndex();
1078 pos
.setField(UNUM_FRACTION_FIELD
);
1079 DecimalFormat::fieldPositionHelper(result
, pos
, appendTo
.length(), status
);
1080 int32_t fracBegin
= pos
.getBeginIndex();
1081 int32_t fracEnd
= pos
.getEndIndex();
1082 if (intBegin
>= 0 && intEnd
> intBegin
) {
1083 // we have an integer part
1084 pos
.setBeginIndex(intBegin
);
1085 if (fracBegin
>= intEnd
&& fracEnd
> fracBegin
) {
1086 // we have a fraction part, include it too
1087 pos
.setEndIndex(fracEnd
);
1089 pos
.setEndIndex(intEnd
);
1091 } else if (fracBegin
>= 0 && fracEnd
> fracBegin
) {
1092 // only a fract part, use it
1093 pos
.setBeginIndex(fracBegin
);
1094 pos
.setEndIndex(fracEnd
);
1097 pos
.setBeginIndex(0);
1100 pos
.setField(UAMEASFMT_NUMERIC_FIELD_FLAG
);
1102 appendTo
.append(result
.toTempString(status
));
1105 if (stripPatternSpaces
) {
1106 // Get the narrow pattern for OTHER.
1107 // If there are spaces in that, then do not continue to strip spaces
1108 // (i.e. even in the narrowest form this locale keeps spaces).
1109 UnicodeString narrowPattern
= number::impl::LongNameHandler::getUnitPattern(getLocale(status
),
1110 amtUnit
, UNUM_UNIT_WIDTH_NARROW
, StandardPlural::Form::OTHER
, status
);
1111 if (U_SUCCESS(status
)) {
1112 if (narrowPattern
.indexOf((UChar
)0x0020) == -1 && narrowPattern
.indexOf((UChar
)0x00A0) == -1) {
1113 int32_t end
= appendTo
.length();
1114 for (; cur
< end
; cur
++) {
1115 if (appendTo
.charAt(cur
) == 0x0020) {
1116 appendTo
.remove(cur
, 1);
1117 if (pos
.getBeginIndex() > cur
) {
1118 pos
.setBeginIndex(pos
.getBeginIndex() - 1);
1119 pos
.setEndIndex(pos
.getEndIndex() - 1);
1129 // Formats hours-minutes-seconds as 5:37:23 or similar.
1130 UnicodeString
&MeasureFormat::formatNumeric(
1131 const Formattable
*hms
, // always length 3
1132 int32_t bitMap
, // 1=hourset, 2=minuteset, 4=secondset
1133 UnicodeString
&appendTo
,
1134 FieldPositionHandler
& handler
,
1135 UErrorCode
&status
) const {
1136 if (U_FAILURE(status
)) {
1140 (UDate
) (((uprv_trunc(hms
[0].getDouble(status
)) * 60.0
1141 + uprv_trunc(hms
[1].getDouble(status
))) * 60.0
1142 + uprv_trunc(hms
[2].getDouble(status
))) * 1000.0);
1146 return formatNumeric(
1148 cache
->getNumericDateFormatters()->hourMinuteSecond
,
1156 return formatNumeric(
1158 cache
->getNumericDateFormatters()->minuteSecond
,
1166 return formatNumeric(
1168 cache
->getNumericDateFormatters()->hourMinute
,
1176 status
= U_INTERNAL_PROGRAM_ERROR
;
1182 static void appendRange(
1183 const UnicodeString
&src
,
1186 UnicodeString
&dest
) {
1187 dest
.append(src
, start
, end
- start
);
1190 static void appendRange(
1191 const UnicodeString
&src
,
1193 UnicodeString
&dest
) {
1194 dest
.append(src
, end
, src
.length() - end
);
1197 // Formats time like 5:37:23
1198 UnicodeString
&MeasureFormat::formatNumeric(
1199 UDate date
, // Time since epoch 1:30:00 would be 5400000
1200 const DateFormat
&dateFmt
, // h:mm, m:ss, or h:mm:ss
1201 UDateFormatField smallestField
, // seconds in 5:37:23.5
1202 const Formattable
&smallestAmount
, // 23.5 for 5:37:23.5
1203 UnicodeString
&appendTo
,
1204 FieldPositionHandler
& handler
,
1205 UErrorCode
&status
) const {
1206 if (U_FAILURE(status
)) {
1209 // Format the smallest amount with this object's NumberFormat
1210 UnicodeString smallestAmountFormatted
;
1212 // We keep track of the integer part of smallest amount so that
1213 // we can replace it later so that we get '0:00:09.3' instead of
1215 FieldPosition
intFieldPosition(UNUM_INTEGER_FIELD
);
1216 (*numberFormat
)->format(
1217 smallestAmount
, smallestAmountFormatted
, intFieldPosition
, status
);
1219 intFieldPosition
.getBeginIndex() == 0 &&
1220 intFieldPosition
.getEndIndex() == 0) {
1221 status
= U_INTERNAL_PROGRAM_ERROR
;
1225 // Format time. draft becomes something like '5:30:45'
1226 // #13606: DateFormat is not thread-safe, but MeasureFormat advertises itself as thread-safe.
1227 FieldPositionIterator posIter
;
1228 UnicodeString draft
;
1229 static UMutex
*dateFmtMutex
= STATIC_NEW(UMutex
);
1230 umtx_lock(dateFmtMutex
);
1231 dateFmt
.format(date
, draft
, &posIter
, status
);
1232 umtx_unlock(dateFmtMutex
);
1234 int32_t start
= appendTo
.length();
1235 FieldPosition
smallestFieldPosition(smallestField
);
1237 int32_t measField
= -1;
1238 while (posIter
.next(fp
)) {
1239 int32_t dateField
= fp
.getField();
1240 switch (dateField
) {
1241 case UDAT_HOUR_OF_DAY1_FIELD
:
1242 case UDAT_HOUR_OF_DAY0_FIELD
:
1243 case UDAT_HOUR1_FIELD
:
1244 case UDAT_HOUR0_FIELD
:
1245 measField
= UAMEASUNIT_DURATION_HOUR
; break;
1246 case UDAT_MINUTE_FIELD
:
1247 measField
= UAMEASUNIT_DURATION_MINUTE
; break;
1248 case UDAT_SECOND_FIELD
:
1249 measField
= UAMEASUNIT_DURATION_SECOND
; break;
1251 measField
= -1; break;
1253 if (dateField
!= smallestField
) {
1254 if (measField
>= 0) {
1255 handler
.addAttribute(measField
, start
+ fp
.getBeginIndex(), start
+ fp
.getEndIndex());
1256 handler
.addAttribute(measField
| UAMEASFMT_NUMERIC_FIELD_FLAG
, start
+ fp
.getBeginIndex(), start
+ fp
.getEndIndex());
1259 smallestFieldPosition
.setBeginIndex(fp
.getBeginIndex());
1260 smallestFieldPosition
.setEndIndex(fp
.getEndIndex());
1265 // If we find field for smallest amount replace it with the formatted
1266 // smallest amount from above taking care to replace the integer part
1267 // with what is in original time. For example, If smallest amount
1268 // is 9.35s and the formatted time is 0:00:09 then 9.35 becomes 09.35
1269 // and replacing yields 0:00:09.35
1270 if (smallestFieldPosition
.getBeginIndex() != 0 ||
1271 smallestFieldPosition
.getEndIndex() != 0) {
1272 appendRange(draft
, 0, smallestFieldPosition
.getBeginIndex(), appendTo
);
1274 smallestAmountFormatted
,
1276 intFieldPosition
.getBeginIndex(),
1280 smallestFieldPosition
.getBeginIndex(),
1281 smallestFieldPosition
.getEndIndex(),
1284 smallestAmountFormatted
,
1285 intFieldPosition
.getEndIndex(),
1289 smallestFieldPosition
.getEndIndex(),
1291 handler
.addAttribute(measField
, start
+ smallestFieldPosition
.getBeginIndex(), appendTo
.length());
1292 handler
.addAttribute(measField
| UAMEASFMT_NUMERIC_FIELD_FLAG
, start
+ smallestFieldPosition
.getBeginIndex(), appendTo
.length());
1294 appendTo
.append(draft
);
1299 UnicodeString
&MeasureFormat::formatMeasuresSlowTrack(
1300 const Measure
*measures
,
1301 int32_t measureCount
,
1302 UnicodeString
& appendTo
,
1304 UErrorCode
& status
) const {
1305 if (U_FAILURE(status
)) {
1308 FieldPosition
dontCare(FieldPosition::DONT_CARE
);
1309 FieldPosition
fpos(pos
.getField());
1310 LocalArray
<UnicodeString
> results(new UnicodeString
[measureCount
], status
);
1311 int32_t fieldPositionFoundIndex
= -1;
1312 for (int32_t i
= 0; i
< measureCount
; ++i
) {
1313 const NumberFormat
*nf
= cache
->getIntegerFormat();
1314 if (i
== measureCount
- 1) {
1315 nf
= numberFormat
->get();
1317 if (fieldPositionFoundIndex
== -1) {
1318 formatMeasure(measures
[i
], *nf
, results
[i
], fpos
, status
);
1319 if (U_FAILURE(status
)) {
1322 if (fpos
.getBeginIndex() != 0 || fpos
.getEndIndex() != 0) {
1323 fieldPositionFoundIndex
= i
;
1326 formatMeasure(measures
[i
], *nf
, results
[i
], dontCare
, status
);
1330 listFormatter
->format(
1334 fieldPositionFoundIndex
,
1337 if (U_FAILURE(status
)) {
1340 // Fix up FieldPosition indexes if our field is found.
1342 pos
.setBeginIndex(fpos
.getBeginIndex() + offset
);
1343 pos
.setEndIndex(fpos
.getEndIndex() + offset
);
1348 MeasureFormat
* U_EXPORT2
MeasureFormat::createCurrencyFormat(const Locale
& locale
,
1350 if (U_FAILURE(ec
)) {
1353 LocalPointer
<CurrencyFormat
> fmt(new CurrencyFormat(locale
, ec
), ec
);
1354 return fmt
.orphan();
1357 MeasureFormat
* U_EXPORT2
MeasureFormat::createCurrencyFormat(UErrorCode
& ec
) {
1358 if (U_FAILURE(ec
)) {
1361 return MeasureFormat::createCurrencyFormat(Locale::getDefault(), ec
);
1366 #endif /* #if !UCONFIG_NO_FORMATTING */