]>
Commit | Line | Data |
---|---|---|
57a6839d A |
1 | /* |
2 | ****************************************************************************** | |
3 | * Copyright (C) 2014, International Business Machines Corporation and | |
4 | * others. All Rights Reserved. | |
5 | ****************************************************************************** | |
6 | * | |
7 | * File RELDATEFMT.CPP | |
8 | ****************************************************************************** | |
9 | */ | |
10 | ||
11 | #include "unicode/reldatefmt.h" | |
12 | ||
13 | #if !UCONFIG_NO_FORMATTING | |
14 | ||
15 | #include "unicode/localpointer.h" | |
16 | #include "quantityformatter.h" | |
17 | #include "unicode/plurrule.h" | |
18 | #include "unicode/msgfmt.h" | |
19 | #include "unicode/decimfmt.h" | |
20 | #include "unicode/numfmt.h" | |
21 | #include "lrucache.h" | |
22 | #include "uresimp.h" | |
23 | #include "unicode/ures.h" | |
24 | #include "cstring.h" | |
25 | #include "ucln_in.h" | |
26 | #include "mutex.h" | |
27 | #include "charstr.h" | |
28 | ||
29 | #include "sharedptr.h" | |
30 | #include "sharedpluralrules.h" | |
31 | #include "sharednumberformat.h" | |
32 | ||
33 | // Copied from uscript_props.cpp | |
34 | #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0])) | |
35 | ||
36 | static icu::LRUCache *gCache = NULL; | |
37 | static UMutex gCacheMutex = U_MUTEX_INITIALIZER; | |
38 | static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER; | |
39 | ||
40 | U_CDECL_BEGIN | |
41 | static UBool U_CALLCONV reldatefmt_cleanup() { | |
42 | gCacheInitOnce.reset(); | |
43 | if (gCache) { | |
44 | delete gCache; | |
45 | gCache = NULL; | |
46 | } | |
47 | return TRUE; | |
48 | } | |
49 | U_CDECL_END | |
50 | ||
51 | U_NAMESPACE_BEGIN | |
52 | ||
53 | // RelativeDateTimeFormatter specific data for a single locale | |
54 | class RelativeDateTimeCacheData: public SharedObject { | |
55 | public: | |
56 | RelativeDateTimeCacheData() : combinedDateAndTime(NULL) { } | |
57 | virtual ~RelativeDateTimeCacheData(); | |
58 | ||
59 | // no numbers: e.g Next Tuesday; Yesterday; etc. | |
60 | UnicodeString absoluteUnits[UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT]; | |
61 | ||
62 | // has numbers: e.g Next Tuesday; Yesterday; etc. For second index, 0 | |
63 | // means past e.g 5 days ago; 1 means future e.g in 5 days. | |
64 | QuantityFormatter relativeUnits[UDAT_RELATIVE_UNIT_COUNT][2]; | |
65 | ||
66 | void adoptCombinedDateAndTime(MessageFormat *mfToAdopt) { | |
67 | delete combinedDateAndTime; | |
68 | combinedDateAndTime = mfToAdopt; | |
69 | } | |
70 | const MessageFormat *getCombinedDateAndTime() const { | |
71 | return combinedDateAndTime; | |
72 | } | |
73 | private: | |
74 | MessageFormat *combinedDateAndTime; | |
75 | RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other); | |
76 | RelativeDateTimeCacheData& operator=( | |
77 | const RelativeDateTimeCacheData &other); | |
78 | }; | |
79 | ||
80 | RelativeDateTimeCacheData::~RelativeDateTimeCacheData() { | |
81 | delete combinedDateAndTime; | |
82 | } | |
83 | ||
84 | static UBool getStringWithFallback( | |
85 | const UResourceBundle *resource, | |
86 | const char *key, | |
87 | UnicodeString &result, | |
88 | UErrorCode &status) { | |
89 | int32_t len = 0; | |
90 | const UChar *resStr = ures_getStringByKeyWithFallback( | |
91 | resource, key, &len, &status); | |
92 | if (U_FAILURE(status)) { | |
93 | return FALSE; | |
94 | } | |
95 | result.setTo(TRUE, resStr, len); | |
96 | return TRUE; | |
97 | } | |
98 | ||
99 | static UBool getOptionalStringWithFallback( | |
100 | const UResourceBundle *resource, | |
101 | const char *key, | |
102 | UnicodeString &result, | |
103 | UErrorCode &status) { | |
104 | if (U_FAILURE(status)) { | |
105 | return FALSE; | |
106 | } | |
107 | int32_t len = 0; | |
108 | const UChar *resStr = ures_getStringByKey( | |
109 | resource, key, &len, &status); | |
110 | if (status == U_MISSING_RESOURCE_ERROR) { | |
111 | result.remove(); | |
112 | status = U_ZERO_ERROR; | |
113 | return TRUE; | |
114 | } | |
115 | if (U_FAILURE(status)) { | |
116 | return FALSE; | |
117 | } | |
118 | result.setTo(TRUE, resStr, len); | |
119 | return TRUE; | |
120 | } | |
121 | ||
122 | static UBool getString( | |
123 | const UResourceBundle *resource, | |
124 | UnicodeString &result, | |
125 | UErrorCode &status) { | |
126 | int32_t len = 0; | |
127 | const UChar *resStr = ures_getString(resource, &len, &status); | |
128 | if (U_FAILURE(status)) { | |
129 | return FALSE; | |
130 | } | |
131 | result.setTo(TRUE, resStr, len); | |
132 | return TRUE; | |
133 | } | |
134 | ||
135 | static UBool getStringByIndex( | |
136 | const UResourceBundle *resource, | |
137 | int32_t idx, | |
138 | UnicodeString &result, | |
139 | UErrorCode &status) { | |
140 | int32_t len = 0; | |
141 | const UChar *resStr = ures_getStringByIndex( | |
142 | resource, idx, &len, &status); | |
143 | if (U_FAILURE(status)) { | |
144 | return FALSE; | |
145 | } | |
146 | result.setTo(TRUE, resStr, len); | |
147 | return TRUE; | |
148 | } | |
149 | ||
150 | static void initAbsoluteUnit( | |
151 | const UResourceBundle *resource, | |
152 | const UnicodeString &unitName, | |
153 | UnicodeString *absoluteUnit, | |
154 | UErrorCode &status) { | |
155 | getStringWithFallback( | |
156 | resource, | |
157 | "-1", | |
158 | absoluteUnit[UDAT_DIRECTION_LAST], | |
159 | status); | |
160 | getStringWithFallback( | |
161 | resource, | |
162 | "0", | |
163 | absoluteUnit[UDAT_DIRECTION_THIS], | |
164 | status); | |
165 | getStringWithFallback( | |
166 | resource, | |
167 | "1", | |
168 | absoluteUnit[UDAT_DIRECTION_NEXT], | |
169 | status); | |
170 | getOptionalStringWithFallback( | |
171 | resource, | |
172 | "-2", | |
173 | absoluteUnit[UDAT_DIRECTION_LAST_2], | |
174 | status); | |
175 | getOptionalStringWithFallback( | |
176 | resource, | |
177 | "2", | |
178 | absoluteUnit[UDAT_DIRECTION_NEXT_2], | |
179 | status); | |
180 | absoluteUnit[UDAT_DIRECTION_PLAIN] = unitName; | |
181 | } | |
182 | ||
183 | static void initQuantityFormatter( | |
184 | const UResourceBundle *resource, | |
185 | QuantityFormatter &formatter, | |
186 | UErrorCode &status) { | |
187 | if (U_FAILURE(status)) { | |
188 | return; | |
189 | } | |
190 | int32_t size = ures_getSize(resource); | |
191 | for (int32_t i = 0; i < size; ++i) { | |
192 | LocalUResourceBundlePointer pluralBundle( | |
193 | ures_getByIndex(resource, i, NULL, &status)); | |
194 | if (U_FAILURE(status)) { | |
195 | return; | |
196 | } | |
197 | UnicodeString rawPattern; | |
198 | if (!getString(pluralBundle.getAlias(), rawPattern, status)) { | |
199 | return; | |
200 | } | |
201 | if (!formatter.add( | |
202 | ures_getKey(pluralBundle.getAlias()), | |
203 | rawPattern, | |
204 | status)) { | |
205 | return; | |
206 | } | |
207 | } | |
208 | } | |
209 | ||
210 | static void initRelativeUnit( | |
211 | const UResourceBundle *resource, | |
212 | QuantityFormatter *relativeUnit, | |
213 | UErrorCode &status) { | |
214 | LocalUResourceBundlePointer topLevel( | |
215 | ures_getByKeyWithFallback( | |
216 | resource, "relativeTime", NULL, &status)); | |
217 | if (U_FAILURE(status)) { | |
218 | return; | |
219 | } | |
220 | LocalUResourceBundlePointer futureBundle(ures_getByKeyWithFallback( | |
221 | topLevel.getAlias(), "future", NULL, &status)); | |
222 | if (U_FAILURE(status)) { | |
223 | return; | |
224 | } | |
225 | initQuantityFormatter( | |
226 | futureBundle.getAlias(), | |
227 | relativeUnit[1], | |
228 | status); | |
229 | LocalUResourceBundlePointer pastBundle(ures_getByKeyWithFallback( | |
230 | topLevel.getAlias(), "past", NULL, &status)); | |
231 | if (U_FAILURE(status)) { | |
232 | return; | |
233 | } | |
234 | initQuantityFormatter( | |
235 | pastBundle.getAlias(), | |
236 | relativeUnit[0], | |
237 | status); | |
238 | } | |
239 | ||
240 | static void initRelativeUnit( | |
241 | const UResourceBundle *resource, | |
242 | const char *path, | |
243 | QuantityFormatter *relativeUnit, | |
244 | UErrorCode &status) { | |
245 | LocalUResourceBundlePointer topLevel( | |
246 | ures_getByKeyWithFallback(resource, path, NULL, &status)); | |
247 | if (U_FAILURE(status)) { | |
248 | return; | |
249 | } | |
250 | initRelativeUnit(topLevel.getAlias(), relativeUnit, status); | |
251 | } | |
252 | ||
253 | static void addTimeUnit( | |
254 | const UResourceBundle *resource, | |
255 | const char *path, | |
256 | QuantityFormatter *relativeUnit, | |
257 | UnicodeString *absoluteUnit, | |
258 | UErrorCode &status) { | |
259 | LocalUResourceBundlePointer topLevel( | |
260 | ures_getByKeyWithFallback(resource, path, NULL, &status)); | |
261 | if (U_FAILURE(status)) { | |
262 | return; | |
263 | } | |
264 | initRelativeUnit(topLevel.getAlias(), relativeUnit, status); | |
265 | UnicodeString unitName; | |
266 | if (!getStringWithFallback(topLevel.getAlias(), "dn", unitName, status)) { | |
267 | return; | |
268 | } | |
269 | // TODO(Travis Keep): This is a hack to get around CLDR bug 6818. | |
270 | const char *localeId = ures_getLocaleByType( | |
271 | topLevel.getAlias(), ULOC_ACTUAL_LOCALE, &status); | |
272 | if (U_FAILURE(status)) { | |
273 | return; | |
274 | } | |
275 | Locale locale(localeId); | |
276 | if (uprv_strcmp("en", locale.getLanguage()) == 0) { | |
277 | unitName.toLower(); | |
278 | } | |
279 | // end hack | |
280 | ures_getByKeyWithFallback( | |
281 | topLevel.getAlias(), "relative", topLevel.getAlias(), &status); | |
282 | if (U_FAILURE(status)) { | |
283 | return; | |
284 | } | |
285 | initAbsoluteUnit( | |
286 | topLevel.getAlias(), | |
287 | unitName, | |
288 | absoluteUnit, | |
289 | status); | |
290 | } | |
291 | ||
292 | static void readDaysOfWeek( | |
293 | const UResourceBundle *resource, | |
294 | const char *path, | |
295 | UnicodeString *daysOfWeek, | |
296 | UErrorCode &status) { | |
297 | LocalUResourceBundlePointer topLevel( | |
298 | ures_getByKeyWithFallback(resource, path, NULL, &status)); | |
299 | if (U_FAILURE(status)) { | |
300 | return; | |
301 | } | |
302 | int32_t size = ures_getSize(topLevel.getAlias()); | |
303 | if (size != 7) { | |
304 | status = U_INTERNAL_PROGRAM_ERROR; | |
305 | return; | |
306 | } | |
307 | for (int32_t i = 0; i < size; ++i) { | |
308 | if (!getStringByIndex(topLevel.getAlias(), i, daysOfWeek[i], status)) { | |
309 | return; | |
310 | } | |
311 | } | |
312 | } | |
313 | ||
314 | static void addWeekDay( | |
315 | const UResourceBundle *resource, | |
316 | const char *path, | |
317 | const UnicodeString *daysOfWeek, | |
318 | UDateAbsoluteUnit absoluteUnit, | |
319 | UnicodeString absoluteUnits[][UDAT_DIRECTION_COUNT], | |
320 | UErrorCode &status) { | |
321 | LocalUResourceBundlePointer topLevel( | |
322 | ures_getByKeyWithFallback(resource, path, NULL, &status)); | |
323 | if (U_FAILURE(status)) { | |
324 | return; | |
325 | } | |
326 | initAbsoluteUnit( | |
327 | topLevel.getAlias(), | |
328 | daysOfWeek[absoluteUnit - UDAT_ABSOLUTE_SUNDAY], | |
329 | absoluteUnits[absoluteUnit], | |
330 | status); | |
331 | } | |
332 | ||
333 | static UBool loadUnitData( | |
334 | const UResourceBundle *resource, | |
335 | RelativeDateTimeCacheData &cacheData, | |
336 | UErrorCode &status) { | |
337 | addTimeUnit( | |
338 | resource, | |
339 | "fields/day", | |
340 | cacheData.relativeUnits[UDAT_RELATIVE_DAYS], | |
341 | cacheData.absoluteUnits[UDAT_ABSOLUTE_DAY], | |
342 | status); | |
343 | addTimeUnit( | |
344 | resource, | |
345 | "fields/week", | |
346 | cacheData.relativeUnits[UDAT_RELATIVE_WEEKS], | |
347 | cacheData.absoluteUnits[UDAT_ABSOLUTE_WEEK], | |
348 | status); | |
349 | addTimeUnit( | |
350 | resource, | |
351 | "fields/month", | |
352 | cacheData.relativeUnits[UDAT_RELATIVE_MONTHS], | |
353 | cacheData.absoluteUnits[UDAT_ABSOLUTE_MONTH], | |
354 | status); | |
355 | addTimeUnit( | |
356 | resource, | |
357 | "fields/year", | |
358 | cacheData.relativeUnits[UDAT_RELATIVE_YEARS], | |
359 | cacheData.absoluteUnits[UDAT_ABSOLUTE_YEAR], | |
360 | status); | |
361 | initRelativeUnit( | |
362 | resource, | |
363 | "fields/second", | |
364 | cacheData.relativeUnits[UDAT_RELATIVE_SECONDS], | |
365 | status); | |
366 | initRelativeUnit( | |
367 | resource, | |
368 | "fields/minute", | |
369 | cacheData.relativeUnits[UDAT_RELATIVE_MINUTES], | |
370 | status); | |
371 | initRelativeUnit( | |
372 | resource, | |
373 | "fields/hour", | |
374 | cacheData.relativeUnits[UDAT_RELATIVE_HOURS], | |
375 | status); | |
376 | getStringWithFallback( | |
377 | resource, | |
378 | "fields/second/relative/0", | |
379 | cacheData.absoluteUnits[UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN], | |
380 | status); | |
381 | UnicodeString daysOfWeek[7]; | |
382 | readDaysOfWeek( | |
383 | resource, | |
384 | "calendar/gregorian/dayNames/stand-alone/wide", | |
385 | daysOfWeek, | |
386 | status); | |
387 | addWeekDay( | |
388 | resource, | |
389 | "fields/mon/relative", | |
390 | daysOfWeek, | |
391 | UDAT_ABSOLUTE_MONDAY, | |
392 | cacheData.absoluteUnits, | |
393 | status); | |
394 | addWeekDay( | |
395 | resource, | |
396 | "fields/tue/relative", | |
397 | daysOfWeek, | |
398 | UDAT_ABSOLUTE_TUESDAY, | |
399 | cacheData.absoluteUnits, | |
400 | status); | |
401 | addWeekDay( | |
402 | resource, | |
403 | "fields/wed/relative", | |
404 | daysOfWeek, | |
405 | UDAT_ABSOLUTE_WEDNESDAY, | |
406 | cacheData.absoluteUnits, | |
407 | status); | |
408 | addWeekDay( | |
409 | resource, | |
410 | "fields/thu/relative", | |
411 | daysOfWeek, | |
412 | UDAT_ABSOLUTE_THURSDAY, | |
413 | cacheData.absoluteUnits, | |
414 | status); | |
415 | addWeekDay( | |
416 | resource, | |
417 | "fields/fri/relative", | |
418 | daysOfWeek, | |
419 | UDAT_ABSOLUTE_FRIDAY, | |
420 | cacheData.absoluteUnits, | |
421 | status); | |
422 | addWeekDay( | |
423 | resource, | |
424 | "fields/sat/relative", | |
425 | daysOfWeek, | |
426 | UDAT_ABSOLUTE_SATURDAY, | |
427 | cacheData.absoluteUnits, | |
428 | status); | |
429 | addWeekDay( | |
430 | resource, | |
431 | "fields/sun/relative", | |
432 | daysOfWeek, | |
433 | UDAT_ABSOLUTE_SUNDAY, | |
434 | cacheData.absoluteUnits, | |
435 | status); | |
436 | return U_SUCCESS(status); | |
437 | } | |
438 | ||
439 | static UBool getDateTimePattern( | |
440 | const UResourceBundle *resource, | |
441 | UnicodeString &result, | |
442 | UErrorCode &status) { | |
443 | UnicodeString defaultCalendarName; | |
444 | if (!getStringWithFallback( | |
445 | resource, | |
446 | "calendar/default", | |
447 | defaultCalendarName, | |
448 | status)) { | |
449 | return FALSE; | |
450 | } | |
451 | CharString pathBuffer; | |
452 | pathBuffer.append("calendar/", status) | |
453 | .appendInvariantChars(defaultCalendarName, status) | |
454 | .append("/DateTimePatterns", status); | |
455 | LocalUResourceBundlePointer topLevel( | |
456 | ures_getByKeyWithFallback( | |
457 | resource, pathBuffer.data(), NULL, &status)); | |
458 | if (U_FAILURE(status)) { | |
459 | return FALSE; | |
460 | } | |
461 | int32_t size = ures_getSize(topLevel.getAlias()); | |
462 | if (size <= 8) { | |
463 | // Oops, size is to small to access the index that we want, fallback | |
464 | // to a hard-coded value. | |
465 | result = UNICODE_STRING_SIMPLE("{1} {0}"); | |
466 | return TRUE; | |
467 | } | |
468 | return getStringByIndex(topLevel.getAlias(), 8, result, status); | |
469 | } | |
470 | ||
471 | // Creates RelativeDateTimeFormatter specific data for a given locale | |
472 | static SharedObject *U_CALLCONV createData( | |
473 | const char *localeId, UErrorCode &status) { | |
474 | LocalUResourceBundlePointer topLevel(ures_open(NULL, localeId, &status)); | |
475 | if (U_FAILURE(status)) { | |
476 | return NULL; | |
477 | } | |
478 | LocalPointer<RelativeDateTimeCacheData> result( | |
479 | new RelativeDateTimeCacheData()); | |
480 | if (result.isNull()) { | |
481 | status = U_MEMORY_ALLOCATION_ERROR; | |
482 | return NULL; | |
483 | } | |
484 | if (!loadUnitData( | |
485 | topLevel.getAlias(), | |
486 | *result, | |
487 | status)) { | |
488 | return NULL; | |
489 | } | |
490 | UnicodeString dateTimePattern; | |
491 | if (!getDateTimePattern(topLevel.getAlias(), dateTimePattern, status)) { | |
492 | return NULL; | |
493 | } | |
494 | result->adoptCombinedDateAndTime( | |
495 | new MessageFormat(dateTimePattern, localeId, status)); | |
496 | if (U_FAILURE(status)) { | |
497 | return NULL; | |
498 | } | |
499 | return result.orphan(); | |
500 | } | |
501 | ||
502 | static void U_CALLCONV cacheInit(UErrorCode &status) { | |
503 | U_ASSERT(gCache == NULL); | |
504 | ucln_i18n_registerCleanup(UCLN_I18N_RELDATEFMT, reldatefmt_cleanup); | |
505 | gCache = new SimpleLRUCache(100, &createData, status); | |
506 | if (U_FAILURE(status)) { | |
507 | delete gCache; | |
508 | gCache = NULL; | |
509 | } | |
510 | } | |
511 | ||
512 | static UBool getFromCache( | |
513 | const char *locale, | |
514 | const RelativeDateTimeCacheData *&ptr, | |
515 | UErrorCode &status) { | |
516 | umtx_initOnce(gCacheInitOnce, &cacheInit, status); | |
517 | if (U_FAILURE(status)) { | |
518 | return FALSE; | |
519 | } | |
520 | Mutex lock(&gCacheMutex); | |
521 | gCache->get(locale, ptr, status); | |
522 | return U_SUCCESS(status); | |
523 | } | |
524 | ||
525 | RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status) | |
526 | : cache(NULL), numberFormat(NULL), pluralRules(NULL) { | |
527 | init(Locale::getDefault(), NULL, status); | |
528 | } | |
529 | ||
530 | RelativeDateTimeFormatter::RelativeDateTimeFormatter( | |
531 | const Locale& locale, UErrorCode& status) | |
532 | : cache(NULL), numberFormat(NULL), pluralRules(NULL) { | |
533 | init(locale, NULL, status); | |
534 | } | |
535 | ||
536 | RelativeDateTimeFormatter::RelativeDateTimeFormatter( | |
537 | const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) | |
538 | : cache(NULL), numberFormat(NULL), pluralRules(NULL) { | |
539 | init(locale, nfToAdopt, status); | |
540 | } | |
541 | ||
542 | RelativeDateTimeFormatter::RelativeDateTimeFormatter( | |
543 | const RelativeDateTimeFormatter& other) | |
544 | : cache(other.cache), | |
545 | numberFormat(other.numberFormat), | |
546 | pluralRules(other.pluralRules) { | |
547 | cache->addRef(); | |
548 | numberFormat->addRef(); | |
549 | pluralRules->addRef(); | |
550 | } | |
551 | ||
552 | RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=( | |
553 | const RelativeDateTimeFormatter& other) { | |
554 | if (this != &other) { | |
555 | SharedObject::copyPtr(other.cache, cache); | |
556 | SharedObject::copyPtr(other.numberFormat, numberFormat); | |
557 | SharedObject::copyPtr(other.pluralRules, pluralRules); | |
558 | } | |
559 | return *this; | |
560 | } | |
561 | ||
562 | RelativeDateTimeFormatter::~RelativeDateTimeFormatter() { | |
563 | if (cache != NULL) { | |
564 | cache->removeRef(); | |
565 | } | |
566 | if (numberFormat != NULL) { | |
567 | numberFormat->removeRef(); | |
568 | } | |
569 | if (pluralRules != NULL) { | |
570 | pluralRules->removeRef(); | |
571 | } | |
572 | } | |
573 | ||
574 | const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const { | |
575 | return **numberFormat; | |
576 | } | |
577 | ||
578 | UnicodeString& RelativeDateTimeFormatter::format( | |
579 | double quantity, UDateDirection direction, UDateRelativeUnit unit, | |
580 | UnicodeString& appendTo, UErrorCode& status) const { | |
581 | if (U_FAILURE(status)) { | |
582 | return appendTo; | |
583 | } | |
584 | if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) { | |
585 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
586 | return appendTo; | |
587 | } | |
588 | int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0; | |
589 | FieldPosition pos(FieldPosition::DONT_CARE); | |
590 | return cache->relativeUnits[unit][bFuture].format( | |
591 | quantity, | |
592 | **numberFormat, | |
593 | **pluralRules, | |
594 | appendTo, | |
595 | pos, | |
596 | status); | |
597 | } | |
598 | ||
599 | UnicodeString& RelativeDateTimeFormatter::format( | |
600 | UDateDirection direction, UDateAbsoluteUnit unit, | |
601 | UnicodeString& appendTo, UErrorCode& status) const { | |
602 | if (U_FAILURE(status)) { | |
603 | return appendTo; | |
604 | } | |
605 | if (unit == UDAT_ABSOLUTE_NOW && direction != UDAT_DIRECTION_PLAIN) { | |
606 | status = U_ILLEGAL_ARGUMENT_ERROR; | |
607 | return appendTo; | |
608 | } | |
609 | return appendTo.append(cache->absoluteUnits[unit][direction]); | |
610 | } | |
611 | ||
612 | UnicodeString& RelativeDateTimeFormatter::combineDateAndTime( | |
613 | const UnicodeString& relativeDateString, const UnicodeString& timeString, | |
614 | UnicodeString& appendTo, UErrorCode& status) const { | |
615 | Formattable args[2] = {timeString, relativeDateString}; | |
616 | FieldPosition fpos(0); | |
617 | return cache->getCombinedDateAndTime()->format( | |
618 | args, 2, appendTo, fpos, status); | |
619 | } | |
620 | ||
621 | void RelativeDateTimeFormatter::init( | |
622 | const Locale &locale, NumberFormat *nfToAdopt, UErrorCode &status) { | |
623 | LocalPointer<NumberFormat> nf(nfToAdopt); | |
624 | if (!getFromCache(locale.getName(), cache, status)) { | |
625 | return; | |
626 | } | |
627 | SharedObject::copyPtr( | |
628 | PluralRules::createSharedInstance( | |
629 | locale, UPLURAL_TYPE_CARDINAL, status), | |
630 | pluralRules); | |
631 | if (U_FAILURE(status)) { | |
632 | return; | |
633 | } | |
634 | pluralRules->removeRef(); | |
635 | if (nf.isNull()) { | |
636 | SharedObject::copyPtr( | |
637 | NumberFormat::createSharedInstance( | |
638 | locale, UNUM_DECIMAL, status), | |
639 | numberFormat); | |
640 | if (U_FAILURE(status)) { | |
641 | return; | |
642 | } | |
643 | numberFormat->removeRef(); | |
644 | } else { | |
645 | SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias()); | |
646 | if (shared == NULL) { | |
647 | status = U_MEMORY_ALLOCATION_ERROR; | |
648 | return; | |
649 | } | |
650 | nf.orphan(); | |
651 | SharedObject::copyPtr(shared, numberFormat); | |
652 | } | |
653 | } | |
654 | ||
655 | ||
656 | U_NAMESPACE_END | |
657 | ||
658 | #endif /* !UCONFIG_NO_FORMATTING */ | |
659 |