• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ******************************************************************************
5 * Copyright (C) 2014-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 ******************************************************************************
8 *
9 * File reldatefmt.cpp
10 ******************************************************************************
11 */
12 
13 #include "unicode/reldatefmt.h"
14 
15 #if !UCONFIG_NO_FORMATTING && !UCONFIG_NO_BREAK_ITERATION
16 
17 #include <cmath>
18 #include <functional>
19 #include "unicode/calendar.h"
20 #include "unicode/datefmt.h"
21 #include "unicode/dtfmtsym.h"
22 #include "unicode/ucasemap.h"
23 #include "unicode/ureldatefmt.h"
24 #include "unicode/udisplaycontext.h"
25 #include "unicode/unum.h"
26 #include "unicode/localpointer.h"
27 #include "unicode/plurrule.h"
28 #include "unicode/simpleformatter.h"
29 #include "unicode/decimfmt.h"
30 #include "unicode/numfmt.h"
31 #include "unicode/brkiter.h"
32 #include "unicode/simpleformatter.h"
33 #include "uresimp.h"
34 #include "unicode/ures.h"
35 #include "cstring.h"
36 #include "ucln_in.h"
37 #include "mutex.h"
38 #include "charstr.h"
39 #include "uassert.h"
40 #include "quantityformatter.h"
41 #include "resource.h"
42 #include "sharedbreakiterator.h"
43 #include "sharedpluralrules.h"
44 #include "sharednumberformat.h"
45 #include "standardplural.h"
46 #include "unifiedcache.h"
47 #include "util.h"
48 #include "formatted_string_builder.h"
49 #include "number_utypes.h"
50 #include "number_modifiers.h"
51 #include "formattedval_impl.h"
52 #include "number_utils.h"
53 
54 // Copied from uscript_props.cpp
55 
56 U_NAMESPACE_BEGIN
57 
58 // RelativeDateTimeFormatter specific data for a single locale
59 class RelativeDateTimeCacheData: public SharedObject {
60 public:
RelativeDateTimeCacheData()61     RelativeDateTimeCacheData() : combinedDateAndTime(nullptr) {
62         // Initialize the cache arrays
63         for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
64             for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) {
65                 for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) {
66                     relativeUnitsFormatters[style][relUnit][0][pl] = nullptr;
67                     relativeUnitsFormatters[style][relUnit][1][pl] = nullptr;
68                 }
69             }
70         }
71         for (int32_t i = 0; i < UDAT_STYLE_COUNT; ++i) {
72           fallBackCache[i] = -1;
73         }
74     }
75     virtual ~RelativeDateTimeCacheData();
76 
77     // no numbers: e.g Next Tuesday; Yesterday; etc.
78     UnicodeString absoluteUnits[UDAT_STYLE_COUNT][UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT];
79 
80     // SimpleFormatter pointers for relative unit format,
81     // e.g., Next Tuesday; Yesterday; etc. For third index, 0
82     // means past, e.g., 5 days ago; 1 means future, e.g., in 5 days.
83     SimpleFormatter *relativeUnitsFormatters[UDAT_STYLE_COUNT]
84         [UDAT_REL_UNIT_COUNT][2][StandardPlural::COUNT];
85 
86     const UnicodeString& getAbsoluteUnitString(int32_t fStyle,
87                                                UDateAbsoluteUnit unit,
88                                                UDateDirection direction) const;
89     const SimpleFormatter* getRelativeUnitFormatter(int32_t fStyle,
90                                                     UDateRelativeUnit unit,
91                                                     int32_t pastFutureIndex,
92                                                     int32_t pluralUnit) const;
93     const SimpleFormatter* getRelativeDateTimeUnitFormatter(int32_t fStyle,
94                                                     URelativeDateTimeUnit unit,
95                                                     int32_t pastFutureIndex,
96                                                     int32_t pluralUnit) const;
97 
98     const UnicodeString emptyString;
99 
100     // Mapping from source to target styles for alias fallback.
101     int32_t fallBackCache[UDAT_STYLE_COUNT];
102 
adoptCombinedDateAndTime(SimpleFormatter * fmtToAdopt)103     void adoptCombinedDateAndTime(SimpleFormatter *fmtToAdopt) {
104         delete combinedDateAndTime;
105         combinedDateAndTime = fmtToAdopt;
106     }
getCombinedDateAndTime() const107     const SimpleFormatter *getCombinedDateAndTime() const {
108         return combinedDateAndTime;
109     }
110 
111 private:
112     SimpleFormatter *combinedDateAndTime;
113     RelativeDateTimeCacheData(const RelativeDateTimeCacheData &other);
114     RelativeDateTimeCacheData& operator=(
115             const RelativeDateTimeCacheData &other);
116 };
117 
~RelativeDateTimeCacheData()118 RelativeDateTimeCacheData::~RelativeDateTimeCacheData() {
119     // clear out the cache arrays
120     for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
121         for (int32_t relUnit = 0; relUnit < UDAT_REL_UNIT_COUNT; ++relUnit) {
122             for (int32_t pl = 0; pl < StandardPlural::COUNT; ++pl) {
123                 delete relativeUnitsFormatters[style][relUnit][0][pl];
124                 delete relativeUnitsFormatters[style][relUnit][1][pl];
125             }
126         }
127     }
128     delete combinedDateAndTime;
129 }
130 
131 
132 // Use fallback cache for absolute units.
getAbsoluteUnitString(int32_t fStyle,UDateAbsoluteUnit unit,UDateDirection direction) const133 const UnicodeString& RelativeDateTimeCacheData::getAbsoluteUnitString(
134         int32_t fStyle, UDateAbsoluteUnit unit, UDateDirection direction) const {
135     int32_t style = fStyle;
136     do {
137         if (!absoluteUnits[style][unit][direction].isEmpty()) {
138             return absoluteUnits[style][unit][direction];
139         }
140         style = fallBackCache[style];
141     } while (style != -1);
142     return emptyString;
143 }
144 
getRelativeUnitFormatter(int32_t fStyle,UDateRelativeUnit unit,int32_t pastFutureIndex,int32_t pluralUnit) const145  const SimpleFormatter* RelativeDateTimeCacheData::getRelativeUnitFormatter(
146         int32_t fStyle,
147         UDateRelativeUnit unit,
148         int32_t pastFutureIndex,
149         int32_t pluralUnit) const {
150    URelativeDateTimeUnit rdtunit = UDAT_REL_UNIT_COUNT;
151    switch (unit) {
152        case UDAT_RELATIVE_YEARS:   rdtunit = UDAT_REL_UNIT_YEAR; break;
153        case UDAT_RELATIVE_MONTHS:  rdtunit = UDAT_REL_UNIT_MONTH; break;
154        case UDAT_RELATIVE_WEEKS:   rdtunit = UDAT_REL_UNIT_WEEK; break;
155        case UDAT_RELATIVE_DAYS:    rdtunit = UDAT_REL_UNIT_DAY; break;
156        case UDAT_RELATIVE_HOURS:   rdtunit = UDAT_REL_UNIT_HOUR; break;
157        case UDAT_RELATIVE_MINUTES: rdtunit = UDAT_REL_UNIT_MINUTE; break;
158        case UDAT_RELATIVE_SECONDS: rdtunit = UDAT_REL_UNIT_SECOND; break;
159        default: // a unit that the above method does not handle
160             return nullptr;
161    }
162 
163    return getRelativeDateTimeUnitFormatter(fStyle, rdtunit, pastFutureIndex, pluralUnit);
164  }
165 
166  // Use fallback cache for SimpleFormatter relativeUnits.
getRelativeDateTimeUnitFormatter(int32_t fStyle,URelativeDateTimeUnit unit,int32_t pastFutureIndex,int32_t pluralUnit) const167  const SimpleFormatter* RelativeDateTimeCacheData::getRelativeDateTimeUnitFormatter(
168         int32_t fStyle,
169         URelativeDateTimeUnit unit,
170         int32_t pastFutureIndex,
171         int32_t pluralUnit) const {
172     while (true) {
173         int32_t style = fStyle;
174         do {
175             if (relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit] != nullptr) {
176                 return relativeUnitsFormatters[style][unit][pastFutureIndex][pluralUnit];
177             }
178             style = fallBackCache[style];
179         } while (style != -1);
180 
181         if (pluralUnit == StandardPlural::OTHER) {
182             break;
183         }
184         pluralUnit = StandardPlural::OTHER;
185     }
186     return nullptr;  // No formatter found.
187  }
188 
getStringByIndex(const UResourceBundle * resource,int32_t idx,UnicodeString & result,UErrorCode & status)189 static UBool getStringByIndex(
190         const UResourceBundle *resource,
191         int32_t idx,
192         UnicodeString &result,
193         UErrorCode &status) {
194     int32_t len = 0;
195     const char16_t *resStr = ures_getStringByIndex(
196             resource, idx, &len, &status);
197     if (U_FAILURE(status)) {
198         return false;
199     }
200     result.setTo(true, resStr, len);
201     return true;
202 }
203 
204 namespace {
205 
206 /**
207  * Sink for enumerating all of the measurement unit display names.
208  *
209  * More specific bundles (en_GB) are enumerated before their parents (en_001, en, root):
210  * Only store a value if it is still missing, that is, it has not been overridden.
211  */
212 struct RelDateTimeFmtDataSink : public ResourceSink {
213 
214     /**
215      * Sink for patterns for relative dates and times. For example,
216      * fields/relative/...
217      */
218 
219     // Generic unit enum for storing Unit info.
220     typedef enum RelAbsUnit {
221         INVALID_UNIT = -1,
222         SECOND,
223         MINUTE,
224         HOUR,
225         DAY,
226         WEEK,
227         MONTH,
228         QUARTER,
229         YEAR,
230         SUNDAY,
231         MONDAY,
232         TUESDAY,
233         WEDNESDAY,
234         THURSDAY,
235         FRIDAY,
236         SATURDAY
237     } RelAbsUnit;
238 
relUnitFromGeneric__anonefb583900111::RelDateTimeFmtDataSink239     static int32_t relUnitFromGeneric(RelAbsUnit genUnit) {
240         // Converts the generic units to UDAT_RELATIVE version.
241         switch (genUnit) {
242             case SECOND:
243                 return UDAT_REL_UNIT_SECOND;
244             case MINUTE:
245                 return UDAT_REL_UNIT_MINUTE;
246             case HOUR:
247                 return UDAT_REL_UNIT_HOUR;
248             case DAY:
249                 return UDAT_REL_UNIT_DAY;
250             case WEEK:
251                 return UDAT_REL_UNIT_WEEK;
252             case MONTH:
253                 return UDAT_REL_UNIT_MONTH;
254             case QUARTER:
255                 return UDAT_REL_UNIT_QUARTER;
256             case YEAR:
257                 return UDAT_REL_UNIT_YEAR;
258             case SUNDAY:
259                 return UDAT_REL_UNIT_SUNDAY;
260             case MONDAY:
261                 return UDAT_REL_UNIT_MONDAY;
262             case TUESDAY:
263                 return UDAT_REL_UNIT_TUESDAY;
264             case WEDNESDAY:
265                 return UDAT_REL_UNIT_WEDNESDAY;
266             case THURSDAY:
267                 return UDAT_REL_UNIT_THURSDAY;
268             case FRIDAY:
269                 return UDAT_REL_UNIT_FRIDAY;
270             case SATURDAY:
271                 return UDAT_REL_UNIT_SATURDAY;
272             default:
273                 return -1;
274         }
275     }
276 
absUnitFromGeneric__anonefb583900111::RelDateTimeFmtDataSink277     static int32_t absUnitFromGeneric(RelAbsUnit genUnit) {
278         // Converts the generic units to UDAT_RELATIVE version.
279         switch (genUnit) {
280             case DAY:
281                 return UDAT_ABSOLUTE_DAY;
282             case WEEK:
283                 return UDAT_ABSOLUTE_WEEK;
284             case MONTH:
285                 return UDAT_ABSOLUTE_MONTH;
286             case QUARTER:
287                 return UDAT_ABSOLUTE_QUARTER;
288             case YEAR:
289                 return UDAT_ABSOLUTE_YEAR;
290             case SUNDAY:
291                 return UDAT_ABSOLUTE_SUNDAY;
292             case MONDAY:
293                 return UDAT_ABSOLUTE_MONDAY;
294             case TUESDAY:
295                 return UDAT_ABSOLUTE_TUESDAY;
296             case WEDNESDAY:
297                 return UDAT_ABSOLUTE_WEDNESDAY;
298             case THURSDAY:
299                 return UDAT_ABSOLUTE_THURSDAY;
300             case FRIDAY:
301                 return UDAT_ABSOLUTE_FRIDAY;
302             case SATURDAY:
303                 return UDAT_ABSOLUTE_SATURDAY;
304             case HOUR:
305                 return UDAT_ABSOLUTE_HOUR;
306             case MINUTE:
307                 return UDAT_ABSOLUTE_MINUTE;
308             default:
309                 return -1;
310         }
311     }
312 
keyToDirection__anonefb583900111::RelDateTimeFmtDataSink313     static int32_t keyToDirection(const char* key) {
314         if (uprv_strcmp(key, "-2") == 0) {
315             return UDAT_DIRECTION_LAST_2;
316         }
317         if (uprv_strcmp(key, "-1") == 0) {
318             return UDAT_DIRECTION_LAST;
319         }
320         if (uprv_strcmp(key, "0") == 0) {
321             return UDAT_DIRECTION_THIS;
322         }
323         if (uprv_strcmp(key, "1") == 0) {
324             return UDAT_DIRECTION_NEXT;
325         }
326         if (uprv_strcmp(key, "2") == 0) {
327             return UDAT_DIRECTION_NEXT_2;
328         }
329         return -1;
330     }
331 
332     // Values kept between levels of parsing the CLDR data.
333     int32_t pastFutureIndex;  // 0 == past or 1 ==  future
334     UDateRelativeDateTimeFormatterStyle style;  // {LONG, SHORT, NARROW}
335     RelAbsUnit genericUnit;
336 
337     RelativeDateTimeCacheData &outputData;
338 
339     // Constructor
RelDateTimeFmtDataSink__anonefb583900111::RelDateTimeFmtDataSink340     RelDateTimeFmtDataSink(RelativeDateTimeCacheData& cacheData)
341         : outputData(cacheData) {
342         // Clear cacheData.fallBackCache
343         cacheData.fallBackCache[UDAT_STYLE_LONG] = -1;
344         cacheData.fallBackCache[UDAT_STYLE_SHORT] = -1;
345         cacheData.fallBackCache[UDAT_STYLE_NARROW] = -1;
346     }
347 
348     ~RelDateTimeFmtDataSink();
349 
350     // Utility functions
styleFromString__anonefb583900111::RelDateTimeFmtDataSink351     static UDateRelativeDateTimeFormatterStyle styleFromString(const char *s) {
352         int32_t len = static_cast<int32_t>(uprv_strlen(s));
353         if (len >= 7 && uprv_strcmp(s + len - 7, "-narrow") == 0) {
354             return UDAT_STYLE_NARROW;
355         }
356         if (len >= 6 && uprv_strcmp(s + len - 6, "-short") == 0) {
357             return UDAT_STYLE_SHORT;
358         }
359         return UDAT_STYLE_LONG;
360     }
361 
styleSuffixLength__anonefb583900111::RelDateTimeFmtDataSink362     static int32_t styleSuffixLength(UDateRelativeDateTimeFormatterStyle style) {
363         switch (style) {
364             case UDAT_STYLE_NARROW:
365                 return 7;
366             case UDAT_STYLE_SHORT:
367                 return 6;
368             default:
369                 return 0;
370         }
371     }
372 
373     // Utility functions
styleFromAliasUnicodeString__anonefb583900111::RelDateTimeFmtDataSink374     static UDateRelativeDateTimeFormatterStyle styleFromAliasUnicodeString(UnicodeString s) {
375         static const char16_t narrow[7] = {0x002D, 0x006E, 0x0061, 0x0072, 0x0072, 0x006F, 0x0077};
376         static const char16_t sshort[6] = {0x002D, 0x0073, 0x0068, 0x006F, 0x0072, 0x0074,};
377         if (s.endsWith(narrow, 7)) {
378             return UDAT_STYLE_NARROW;
379         }
380         if (s.endsWith(sshort, 6)) {
381             return UDAT_STYLE_SHORT;
382         }
383         return UDAT_STYLE_LONG;
384     }
385 
unitOrNegativeFromString__anonefb583900111::RelDateTimeFmtDataSink386     static RelAbsUnit unitOrNegativeFromString(const char* keyword, int32_t length) {
387         // Quick check from string to enum.
388         switch (length) {
389             case 3:
390                 if (uprv_strncmp(keyword, "day", length) == 0) {
391                     return DAY;
392                 } else if (uprv_strncmp(keyword, "sun", length) == 0) {
393                     return SUNDAY;
394                 } else if (uprv_strncmp(keyword, "mon", length) == 0) {
395                     return MONDAY;
396                 } else if (uprv_strncmp(keyword, "tue", length) == 0) {
397                     return TUESDAY;
398                 } else if (uprv_strncmp(keyword, "wed", length) == 0) {
399                     return WEDNESDAY;
400                 } else if (uprv_strncmp(keyword, "thu", length) == 0) {
401                     return THURSDAY;
402                 } else if (uprv_strncmp(keyword, "fri", length) == 0) {
403                     return FRIDAY;
404                 } else if (uprv_strncmp(keyword, "sat", length) == 0) {
405                     return SATURDAY;
406                 }
407                 break;
408             case 4:
409                 if (uprv_strncmp(keyword, "hour", length) == 0) {
410                     return HOUR;
411                 } else if (uprv_strncmp(keyword, "week", length) == 0) {
412                     return WEEK;
413                 } else if (uprv_strncmp(keyword, "year", length) == 0) {
414                     return YEAR;
415                 }
416                 break;
417             case 5:
418                 if (uprv_strncmp(keyword, "month", length) == 0) {
419                     return MONTH;
420                 }
421                 break;
422             case 6:
423                 if (uprv_strncmp(keyword, "minute", length) == 0) {
424                     return MINUTE;
425                 } else if (uprv_strncmp(keyword, "second", length) == 0) {
426                     return SECOND;
427                 }
428                 break;
429             case 7:
430                 if (uprv_strncmp(keyword, "quarter", length) == 0) {
431                     return QUARTER;  // TODO: Check @provisional
432                   }
433                 break;
434             default:
435                 break;
436         }
437         return INVALID_UNIT;
438     }
439 
handlePlainDirection__anonefb583900111::RelDateTimeFmtDataSink440     void handlePlainDirection(ResourceValue &value, UErrorCode &errorCode) {
441         // Handle Display Name for PLAIN direction for some units.
442         if (U_FAILURE(errorCode)) { return; }
443 
444         int32_t absUnit = absUnitFromGeneric(genericUnit);
445         if (absUnit < 0) {
446           return;  // Not interesting.
447         }
448 
449         // Store displayname if not set.
450         if (outputData.absoluteUnits[style]
451             [absUnit][UDAT_DIRECTION_PLAIN].isEmpty()) {
452             outputData.absoluteUnits[style]
453                 [absUnit][UDAT_DIRECTION_PLAIN].fastCopyFrom(value.getUnicodeString(errorCode));
454             return;
455         }
456     }
457 
consumeTableRelative__anonefb583900111::RelDateTimeFmtDataSink458     void consumeTableRelative(const char *key, ResourceValue &value, UErrorCode &errorCode) {
459         ResourceTable unitTypesTable = value.getTable(errorCode);
460         if (U_FAILURE(errorCode)) { return; }
461 
462         for (int32_t i = 0; unitTypesTable.getKeyAndValue(i, key, value); ++i) {
463             if (value.getType() == URES_STRING) {
464                 int32_t direction = keyToDirection(key);
465                 if (direction < 0) {
466                   continue;
467                 }
468 
469                 int32_t relUnitIndex = relUnitFromGeneric(genericUnit);
470                 if (relUnitIndex == UDAT_REL_UNIT_SECOND && uprv_strcmp(key, "0") == 0 &&
471                     outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW][UDAT_DIRECTION_PLAIN].isEmpty()) {
472                     // Handle "NOW"
473                     outputData.absoluteUnits[style][UDAT_ABSOLUTE_NOW]
474                         [UDAT_DIRECTION_PLAIN].fastCopyFrom(value.getUnicodeString(errorCode));
475                 }
476 
477                 int32_t absUnitIndex = absUnitFromGeneric(genericUnit);
478                 if (absUnitIndex < 0) {
479                     continue;
480                 }
481                 // Only reset if slot is empty.
482                 if (outputData.absoluteUnits[style][absUnitIndex][direction].isEmpty()) {
483                     outputData.absoluteUnits[style][absUnitIndex]
484                         [direction].fastCopyFrom(value.getUnicodeString(errorCode));
485                 }
486             }
487         }
488     }
489 
consumeTimeDetail__anonefb583900111::RelDateTimeFmtDataSink490     void consumeTimeDetail(int32_t relUnitIndex,
491                            const char *key, ResourceValue &value, UErrorCode &errorCode) {
492         ResourceTable unitTypesTable = value.getTable(errorCode);
493         if (U_FAILURE(errorCode)) { return; }
494 
495           for (int32_t i = 0; unitTypesTable.getKeyAndValue(i, key, value); ++i) {
496             if (value.getType() == URES_STRING) {
497                 int32_t pluralIndex = StandardPlural::indexOrNegativeFromString(key);
498                 if (pluralIndex >= 0) {
499                     SimpleFormatter **patterns =
500                         outputData.relativeUnitsFormatters[style][relUnitIndex]
501                         [pastFutureIndex];
502                     // Only set if not already established.
503                     if (patterns[pluralIndex] == nullptr) {
504                         patterns[pluralIndex] = new SimpleFormatter(
505                             value.getUnicodeString(errorCode), 0, 1, errorCode);
506                         if (patterns[pluralIndex] == nullptr) {
507                             errorCode = U_MEMORY_ALLOCATION_ERROR;
508                         }
509                     }
510                 }
511             }
512         }
513     }
514 
consumeTableRelativeTime__anonefb583900111::RelDateTimeFmtDataSink515     void consumeTableRelativeTime(const char *key, ResourceValue &value, UErrorCode &errorCode) {
516         ResourceTable relativeTimeTable = value.getTable(errorCode);
517         if (U_FAILURE(errorCode)) { return; }
518 
519         int32_t relUnitIndex = relUnitFromGeneric(genericUnit);
520         if (relUnitIndex < 0) {
521             return;
522         }
523         for (int32_t i = 0; relativeTimeTable.getKeyAndValue(i, key, value); ++i) {
524             if (uprv_strcmp(key, "past") == 0) {
525                 pastFutureIndex = 0;
526             } else if (uprv_strcmp(key, "future") == 0) {
527                 pastFutureIndex = 1;
528             } else {
529                 // Unknown key.
530                 continue;
531             }
532             consumeTimeDetail(relUnitIndex, key, value, errorCode);
533         }
534     }
535 
consumeAlias__anonefb583900111::RelDateTimeFmtDataSink536     void consumeAlias(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
537 
538         UDateRelativeDateTimeFormatterStyle sourceStyle = styleFromString(key);
539         const UnicodeString valueStr = value.getAliasUnicodeString(errorCode);
540         if (U_FAILURE(errorCode)) { return; }
541 
542         UDateRelativeDateTimeFormatterStyle targetStyle =
543             styleFromAliasUnicodeString(valueStr);
544 
545         if (sourceStyle == targetStyle) {
546             errorCode = U_INVALID_FORMAT_ERROR;
547             return;
548         }
549         if (outputData.fallBackCache[sourceStyle] != -1 &&
550             outputData.fallBackCache[sourceStyle] != targetStyle) {
551             errorCode = U_INVALID_FORMAT_ERROR;
552             return;
553         }
554         outputData.fallBackCache[sourceStyle] = targetStyle;
555     }
556 
consumeTimeUnit__anonefb583900111::RelDateTimeFmtDataSink557     void consumeTimeUnit(const char *key, ResourceValue &value, UErrorCode &errorCode) {
558         ResourceTable unitTypesTable = value.getTable(errorCode);
559         if (U_FAILURE(errorCode)) { return; }
560 
561         for (int32_t i = 0; unitTypesTable.getKeyAndValue(i, key, value); ++i) {
562             // Handle display name.
563             if (uprv_strcmp(key, "dn") == 0 && value.getType() == URES_STRING) {
564                 handlePlainDirection(value, errorCode);
565             }
566             if (value.getType() == URES_TABLE) {
567                 if (uprv_strcmp(key, "relative") == 0) {
568                     consumeTableRelative(key, value, errorCode);
569                 } else if (uprv_strcmp(key, "relativeTime") == 0) {
570                     consumeTableRelativeTime(key, value, errorCode);
571                 }
572             }
573         }
574     }
575 
put__anonefb583900111::RelDateTimeFmtDataSink576     virtual void put(const char *key, ResourceValue &value,
577                      UBool /*noFallback*/, UErrorCode &errorCode) override {
578         // Main entry point to sink
579         ResourceTable table = value.getTable(errorCode);
580         if (U_FAILURE(errorCode)) { return; }
581         for (int32_t i = 0; table.getKeyAndValue(i, key, value); ++i) {
582             if (value.getType() == URES_ALIAS) {
583                 consumeAlias(key, value, errorCode);
584             } else {
585                 style = styleFromString(key);
586                 int32_t unitSize = static_cast<int32_t>(uprv_strlen(key)) - styleSuffixLength(style);
587                 genericUnit = unitOrNegativeFromString(key, unitSize);
588                 if (style >= 0 && genericUnit != INVALID_UNIT) {
589                     consumeTimeUnit(key, value, errorCode);
590                 }
591             }
592         }
593     }
594 
595 };
596 
597 // Virtual destructors must be defined out of line.
~RelDateTimeFmtDataSink()598 RelDateTimeFmtDataSink::~RelDateTimeFmtDataSink() {}
599 } // namespace
600 
601 static const DateFormatSymbols::DtWidthType styleToDateFormatSymbolWidth[UDAT_STYLE_COUNT] = {
602   DateFormatSymbols::WIDE, DateFormatSymbols::SHORT, DateFormatSymbols::NARROW
603 };
604 
605 // Get days of weeks from the DateFormatSymbols class.
loadWeekdayNames(UnicodeString absoluteUnits[UDAT_STYLE_COUNT][UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT],const char * localeId,UErrorCode & status)606 static void loadWeekdayNames(UnicodeString absoluteUnits[UDAT_STYLE_COUNT]
607                                  [UDAT_ABSOLUTE_UNIT_COUNT][UDAT_DIRECTION_COUNT],
608                              const char* localeId,
609                              UErrorCode& status) {
610     if (U_FAILURE(status)) {
611         return;
612     }
613     Locale locale(localeId);
614     DateFormatSymbols dfSym(locale, status);
615     if (U_FAILURE(status)) {
616         return;
617     }
618     for (int32_t style = 0; style < UDAT_STYLE_COUNT; ++style) {
619         DateFormatSymbols::DtWidthType dtfmtWidth = styleToDateFormatSymbolWidth[style];
620         int32_t count;
621         const UnicodeString* weekdayNames =
622             dfSym.getWeekdays(count, DateFormatSymbols::STANDALONE, dtfmtWidth);
623         for (int32_t dayIndex = UDAT_ABSOLUTE_SUNDAY;
624                 dayIndex <= UDAT_ABSOLUTE_SATURDAY; ++ dayIndex) {
625             int32_t dateSymbolIndex = (dayIndex - UDAT_ABSOLUTE_SUNDAY) + UCAL_SUNDAY;
626             absoluteUnits[style][dayIndex][UDAT_DIRECTION_PLAIN].fastCopyFrom(
627                 weekdayNames[dateSymbolIndex]);
628         }
629     }
630 }
631 
loadUnitData(const UResourceBundle * resource,RelativeDateTimeCacheData & cacheData,const char * localeId,UErrorCode & status)632 static UBool loadUnitData(
633         const UResourceBundle *resource,
634         RelativeDateTimeCacheData &cacheData,
635         const char* localeId,
636         UErrorCode &status) {
637 
638     RelDateTimeFmtDataSink sink(cacheData);
639 
640     ures_getAllItemsWithFallback(resource, "fields", sink, status);
641     if (U_FAILURE(status)) {
642         return false;
643     }
644 
645     // Get the weekday names from DateFormatSymbols.
646     loadWeekdayNames(cacheData.absoluteUnits, localeId, status);
647     return U_SUCCESS(status);
648 }
649 
650 static const int32_t cTypeBufMax = 32;
651 
getDateTimePattern(Locale locale,const UResourceBundle * resource,UnicodeString & result,UErrorCode & status)652 static UBool getDateTimePattern(
653         Locale locale,
654         const UResourceBundle *resource,
655         UnicodeString &result,
656         UErrorCode &status) {
657     if (U_FAILURE(status)) {
658         return false;
659     }
660     char cType[cTypeBufMax + 1];
661     Calendar::getCalendarTypeFromLocale(locale, cType, cTypeBufMax, status);
662     cType[cTypeBufMax] = 0;
663     if (U_FAILURE(status) || cType[0] == 0) {
664         status = U_ZERO_ERROR;
665         uprv_strcpy(cType, "gregorian");
666     }
667 
668     LocalUResourceBundlePointer topLevel;
669     int32_t dateTimeFormatOffset = DateFormat::kMedium;
670     CharString pathBuffer;
671     // Currently, for compatibility with pre-CLDR-42 data, we default to the "atTime"
672     // combining patterns. Depending on guidance in CLDR 42 spec and on DisplayOptions,
673     // we may change this.
674     pathBuffer.append("calendar/", status)
675             .append(cType, status)
676             .append("/DateTimePatterns%atTime", status);
677     topLevel.adoptInstead(
678             ures_getByKeyWithFallback(
679                     resource, pathBuffer.data(), nullptr, &status));
680     if (U_FAILURE(status) ||  ures_getSize(topLevel.getAlias()) < 4) {
681         // Fall back to standard combining patterns
682         status = U_ZERO_ERROR;
683         dateTimeFormatOffset = DateFormat::kDateTime;
684         pathBuffer.clear();
685         pathBuffer.append("calendar/", status)
686                 .append(cType, status)
687                 .append("/DateTimePatterns", status);
688         topLevel.adoptInstead(
689                 ures_getByKeyWithFallback(
690                         resource, pathBuffer.data(), nullptr, &status));
691     }
692     if (U_FAILURE(status)) {
693         return false;
694     }
695     if (dateTimeFormatOffset == DateFormat::kDateTime && ures_getSize(topLevel.getAlias()) <= DateFormat::kDateTime) {
696         // Oops, size is too small to access the index that we want, fallback
697         // to a hard-coded value.
698         result = UNICODE_STRING_SIMPLE("{1} {0}");
699         return true;
700     }
701     return getStringByIndex(topLevel.getAlias(), dateTimeFormatOffset, result, status);
702 }
703 
704 template<>
createObject(const void *,UErrorCode & status) const705 const RelativeDateTimeCacheData *LocaleCacheKey<RelativeDateTimeCacheData>::createObject(const void * /*unused*/, UErrorCode &status) const {
706     const char *localeId = fLoc.getName();
707     LocalUResourceBundlePointer topLevel(ures_open(nullptr, localeId, &status));
708     if (U_FAILURE(status)) {
709         return nullptr;
710     }
711     LocalPointer<RelativeDateTimeCacheData> result(
712             new RelativeDateTimeCacheData());
713     if (result.isNull()) {
714         status = U_MEMORY_ALLOCATION_ERROR;
715         return nullptr;
716     }
717     if (!loadUnitData(
718             topLevel.getAlias(),
719             *result,
720             localeId,
721             status)) {
722         return nullptr;
723     }
724     UnicodeString dateTimePattern;
725     if (!getDateTimePattern(fLoc, topLevel.getAlias(), dateTimePattern, status)) {
726         return nullptr;
727     }
728     result->adoptCombinedDateAndTime(
729             new SimpleFormatter(dateTimePattern, 2, 2, status));
730     if (U_FAILURE(status)) {
731         return nullptr;
732     }
733     result->addRef();
734     return result.orphan();
735 }
736 
737 
738 
739 static constexpr FormattedStringBuilder::Field kRDTNumericField
740     = {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_NUMERIC_FIELD};
741 
742 static constexpr FormattedStringBuilder::Field kRDTLiteralField
743     = {UFIELD_CATEGORY_RELATIVE_DATETIME, UDAT_REL_LITERAL_FIELD};
744 
745 class FormattedRelativeDateTimeData : public FormattedValueStringBuilderImpl {
746 public:
FormattedRelativeDateTimeData()747     FormattedRelativeDateTimeData() : FormattedValueStringBuilderImpl(kRDTNumericField) {}
748     virtual ~FormattedRelativeDateTimeData();
749 };
750 
751 FormattedRelativeDateTimeData::~FormattedRelativeDateTimeData() = default;
752 
753 
UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedRelativeDateTime)754 UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedRelativeDateTime)
755 
756 
757 RelativeDateTimeFormatter::RelativeDateTimeFormatter(UErrorCode& status) :
758         fCache(nullptr),
759         fNumberFormat(nullptr),
760         fPluralRules(nullptr),
761         fStyle(UDAT_STYLE_LONG),
762         fContext(UDISPCTX_CAPITALIZATION_NONE),
763         fOptBreakIterator(nullptr) {
764     init(nullptr, nullptr, status);
765 }
766 
RelativeDateTimeFormatter(const Locale & locale,UErrorCode & status)767 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
768         const Locale& locale, UErrorCode& status) :
769         fCache(nullptr),
770         fNumberFormat(nullptr),
771         fPluralRules(nullptr),
772         fStyle(UDAT_STYLE_LONG),
773         fContext(UDISPCTX_CAPITALIZATION_NONE),
774         fOptBreakIterator(nullptr),
775         fLocale(locale) {
776     init(nullptr, nullptr, status);
777 }
778 
RelativeDateTimeFormatter(const Locale & locale,NumberFormat * nfToAdopt,UErrorCode & status)779 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
780         const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) :
781         fCache(nullptr),
782         fNumberFormat(nullptr),
783         fPluralRules(nullptr),
784         fStyle(UDAT_STYLE_LONG),
785         fContext(UDISPCTX_CAPITALIZATION_NONE),
786         fOptBreakIterator(nullptr),
787         fLocale(locale) {
788     init(nfToAdopt, nullptr, status);
789 }
790 
RelativeDateTimeFormatter(const Locale & locale,NumberFormat * nfToAdopt,UDateRelativeDateTimeFormatterStyle styl,UDisplayContext capitalizationContext,UErrorCode & status)791 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
792         const Locale& locale,
793         NumberFormat *nfToAdopt,
794         UDateRelativeDateTimeFormatterStyle styl,
795         UDisplayContext capitalizationContext,
796         UErrorCode& status) :
797         fCache(nullptr),
798         fNumberFormat(nullptr),
799         fPluralRules(nullptr),
800         fStyle(styl),
801         fContext(capitalizationContext),
802         fOptBreakIterator(nullptr),
803         fLocale(locale) {
804     if (U_FAILURE(status)) {
805         return;
806     }
807     if ((capitalizationContext >> 8) != UDISPCTX_TYPE_CAPITALIZATION) {
808         status = U_ILLEGAL_ARGUMENT_ERROR;
809         return;
810     }
811     if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) {
812         BreakIterator *bi = BreakIterator::createSentenceInstance(locale, status);
813         if (U_FAILURE(status)) {
814             return;
815         }
816         init(nfToAdopt, bi, status);
817     } else {
818         init(nfToAdopt, nullptr, status);
819     }
820 }
821 
RelativeDateTimeFormatter(const RelativeDateTimeFormatter & other)822 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
823         const RelativeDateTimeFormatter& other)
824         : UObject(other),
825           fCache(other.fCache),
826           fNumberFormat(other.fNumberFormat),
827           fPluralRules(other.fPluralRules),
828           fStyle(other.fStyle),
829           fContext(other.fContext),
830           fOptBreakIterator(other.fOptBreakIterator),
831           fLocale(other.fLocale) {
832     fCache->addRef();
833     fNumberFormat->addRef();
834     fPluralRules->addRef();
835     if (fOptBreakIterator != nullptr) {
836       fOptBreakIterator->addRef();
837     }
838 }
839 
operator =(const RelativeDateTimeFormatter & other)840 RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(
841         const RelativeDateTimeFormatter& other) {
842     if (this != &other) {
843         SharedObject::copyPtr(other.fCache, fCache);
844         SharedObject::copyPtr(other.fNumberFormat, fNumberFormat);
845         SharedObject::copyPtr(other.fPluralRules, fPluralRules);
846         SharedObject::copyPtr(other.fOptBreakIterator, fOptBreakIterator);
847         fStyle = other.fStyle;
848         fContext = other.fContext;
849         fLocale = other.fLocale;
850     }
851     return *this;
852 }
853 
~RelativeDateTimeFormatter()854 RelativeDateTimeFormatter::~RelativeDateTimeFormatter() {
855     if (fCache != nullptr) {
856         fCache->removeRef();
857     }
858     if (fNumberFormat != nullptr) {
859         fNumberFormat->removeRef();
860     }
861     if (fPluralRules != nullptr) {
862         fPluralRules->removeRef();
863     }
864     if (fOptBreakIterator != nullptr) {
865         fOptBreakIterator->removeRef();
866     }
867 }
868 
getNumberFormat() const869 const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const {
870     return **fNumberFormat;
871 }
872 
getCapitalizationContext() const873 UDisplayContext RelativeDateTimeFormatter::getCapitalizationContext() const {
874     return fContext;
875 }
876 
getFormatStyle() const877 UDateRelativeDateTimeFormatterStyle RelativeDateTimeFormatter::getFormatStyle() const {
878     return fStyle;
879 }
880 
881 
882 // To reduce boilerplate code, we use a helper function that forwards variadic
883 // arguments to the formatImpl function.
884 
885 template<typename F, typename... Args>
doFormat(F callback,UnicodeString & appendTo,UErrorCode & status,Args...args) const886 UnicodeString& RelativeDateTimeFormatter::doFormat(
887         F callback,
888         UnicodeString& appendTo,
889         UErrorCode& status,
890         Args... args) const {
891     FormattedRelativeDateTimeData output;
892     (this->*callback)(std::forward<Args>(args)..., output, status);
893     if (U_FAILURE(status)) {
894         return appendTo;
895     }
896     UnicodeString result = output.getStringRef().toUnicodeString();
897     return appendTo.append(adjustForContext(result));
898 }
899 
900 template<typename F, typename... Args>
doFormatToValue(F callback,UErrorCode & status,Args...args) const901 FormattedRelativeDateTime RelativeDateTimeFormatter::doFormatToValue(
902         F callback,
903         UErrorCode& status,
904         Args... args) const {
905     if (!checkNoAdjustForContext(status)) {
906         return FormattedRelativeDateTime(status);
907     }
908     LocalPointer<FormattedRelativeDateTimeData> output(
909         new FormattedRelativeDateTimeData(), status);
910     if (U_FAILURE(status)) {
911         return FormattedRelativeDateTime(status);
912     }
913     (this->*callback)(std::forward<Args>(args)..., *output, status);
914     output->getStringRef().writeTerminator(status);
915     return FormattedRelativeDateTime(output.orphan());
916 }
917 
format(double quantity,UDateDirection direction,UDateRelativeUnit unit,UnicodeString & appendTo,UErrorCode & status) const918 UnicodeString& RelativeDateTimeFormatter::format(
919         double quantity,
920         UDateDirection direction,
921         UDateRelativeUnit unit,
922         UnicodeString& appendTo,
923         UErrorCode& status) const {
924     return doFormat(
925         &RelativeDateTimeFormatter::formatImpl,
926         appendTo,
927         status,
928         quantity,
929         direction,
930         unit);
931 }
932 
formatToValue(double quantity,UDateDirection direction,UDateRelativeUnit unit,UErrorCode & status) const933 FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
934         double quantity,
935         UDateDirection direction,
936         UDateRelativeUnit unit,
937         UErrorCode& status) const {
938     return doFormatToValue(
939         &RelativeDateTimeFormatter::formatImpl,
940         status,
941         quantity,
942         direction,
943         unit);
944 }
945 
formatImpl(double quantity,UDateDirection direction,UDateRelativeUnit unit,FormattedRelativeDateTimeData & output,UErrorCode & status) const946 void RelativeDateTimeFormatter::formatImpl(
947         double quantity,
948         UDateDirection direction,
949         UDateRelativeUnit unit,
950         FormattedRelativeDateTimeData& output,
951         UErrorCode& status) const {
952     if (U_FAILURE(status)) {
953         return;
954     }
955     if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
956         status = U_ILLEGAL_ARGUMENT_ERROR;
957         return;
958     }
959     int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
960 
961     StandardPlural::Form pluralForm;
962     QuantityFormatter::formatAndSelect(
963         quantity,
964         **fNumberFormat,
965         **fPluralRules,
966         output.getStringRef(),
967         pluralForm,
968         status);
969     if (U_FAILURE(status)) {
970         return;
971     }
972 
973     const SimpleFormatter* formatter =
974         fCache->getRelativeUnitFormatter(fStyle, unit, bFuture, pluralForm);
975     if (formatter == nullptr) {
976         // TODO: WARN - look at quantity formatter's action with an error.
977         status = U_INVALID_FORMAT_ERROR;
978         return;
979     }
980 
981     number::impl::SimpleModifier modifier(*formatter, kRDTLiteralField, false);
982     modifier.formatAsPrefixSuffix(
983         output.getStringRef(), 0, output.getStringRef().length(), status);
984 }
985 
formatNumeric(double offset,URelativeDateTimeUnit unit,UnicodeString & appendTo,UErrorCode & status) const986 UnicodeString& RelativeDateTimeFormatter::formatNumeric(
987         double offset,
988         URelativeDateTimeUnit unit,
989         UnicodeString& appendTo,
990         UErrorCode& status) const {
991     return doFormat(
992         &RelativeDateTimeFormatter::formatNumericImpl,
993         appendTo,
994         status,
995         offset,
996         unit);
997 }
998 
formatNumericToValue(double offset,URelativeDateTimeUnit unit,UErrorCode & status) const999 FormattedRelativeDateTime RelativeDateTimeFormatter::formatNumericToValue(
1000         double offset,
1001         URelativeDateTimeUnit unit,
1002         UErrorCode& status) const {
1003     return doFormatToValue(
1004         &RelativeDateTimeFormatter::formatNumericImpl,
1005         status,
1006         offset,
1007         unit);
1008 }
1009 
formatNumericImpl(double offset,URelativeDateTimeUnit unit,FormattedRelativeDateTimeData & output,UErrorCode & status) const1010 void RelativeDateTimeFormatter::formatNumericImpl(
1011         double offset,
1012         URelativeDateTimeUnit unit,
1013         FormattedRelativeDateTimeData& output,
1014         UErrorCode& status) const {
1015     if (U_FAILURE(status)) {
1016         return;
1017     }
1018     UDateDirection direction = UDAT_DIRECTION_NEXT;
1019     if (std::signbit(offset)) { // needed to handle -0.0
1020         direction = UDAT_DIRECTION_LAST;
1021         offset = -offset;
1022     }
1023     if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
1024         status = U_ILLEGAL_ARGUMENT_ERROR;
1025         return;
1026     }
1027     int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
1028 
1029     StandardPlural::Form pluralForm;
1030     QuantityFormatter::formatAndSelect(
1031         offset,
1032         **fNumberFormat,
1033         **fPluralRules,
1034         output.getStringRef(),
1035         pluralForm,
1036         status);
1037     if (U_FAILURE(status)) {
1038         return;
1039     }
1040 
1041     const SimpleFormatter* formatter =
1042         fCache->getRelativeDateTimeUnitFormatter(fStyle, unit, bFuture, pluralForm);
1043     if (formatter == nullptr) {
1044         // TODO: WARN - look at quantity formatter's action with an error.
1045         status = U_INVALID_FORMAT_ERROR;
1046         return;
1047     }
1048 
1049     number::impl::SimpleModifier modifier(*formatter, kRDTLiteralField, false);
1050     modifier.formatAsPrefixSuffix(
1051         output.getStringRef(), 0, output.getStringRef().length(), status);
1052 }
1053 
format(UDateDirection direction,UDateAbsoluteUnit unit,UnicodeString & appendTo,UErrorCode & status) const1054 UnicodeString& RelativeDateTimeFormatter::format(
1055         UDateDirection direction,
1056         UDateAbsoluteUnit unit,
1057         UnicodeString& appendTo,
1058         UErrorCode& status) const {
1059     return doFormat(
1060         &RelativeDateTimeFormatter::formatAbsoluteImpl,
1061         appendTo,
1062         status,
1063         direction,
1064         unit);
1065 }
1066 
formatToValue(UDateDirection direction,UDateAbsoluteUnit unit,UErrorCode & status) const1067 FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
1068         UDateDirection direction,
1069         UDateAbsoluteUnit unit,
1070         UErrorCode& status) const {
1071     return doFormatToValue(
1072         &RelativeDateTimeFormatter::formatAbsoluteImpl,
1073         status,
1074         direction,
1075         unit);
1076 }
1077 
formatAbsoluteImpl(UDateDirection direction,UDateAbsoluteUnit unit,FormattedRelativeDateTimeData & output,UErrorCode & status) const1078 void RelativeDateTimeFormatter::formatAbsoluteImpl(
1079         UDateDirection direction,
1080         UDateAbsoluteUnit unit,
1081         FormattedRelativeDateTimeData& output,
1082         UErrorCode& status) const {
1083     if (U_FAILURE(status)) {
1084         return;
1085     }
1086     if (unit == UDAT_ABSOLUTE_NOW && direction != UDAT_DIRECTION_PLAIN) {
1087         status = U_ILLEGAL_ARGUMENT_ERROR;
1088         return;
1089     }
1090 
1091     // Get string using fallback.
1092     output.getStringRef().append(
1093         fCache->getAbsoluteUnitString(fStyle, unit, direction),
1094         kRDTLiteralField,
1095         status);
1096 }
1097 
format(double offset,URelativeDateTimeUnit unit,UnicodeString & appendTo,UErrorCode & status) const1098 UnicodeString& RelativeDateTimeFormatter::format(
1099         double offset,
1100         URelativeDateTimeUnit unit,
1101         UnicodeString& appendTo,
1102         UErrorCode& status) const {
1103     return doFormat(
1104         &RelativeDateTimeFormatter::formatRelativeImpl,
1105         appendTo,
1106         status,
1107         offset,
1108         unit);
1109 }
1110 
formatToValue(double offset,URelativeDateTimeUnit unit,UErrorCode & status) const1111 FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
1112         double offset,
1113         URelativeDateTimeUnit unit,
1114         UErrorCode& status) const {
1115     return doFormatToValue(
1116         &RelativeDateTimeFormatter::formatRelativeImpl,
1117         status,
1118         offset,
1119         unit);
1120 }
1121 
formatRelativeImpl(double offset,URelativeDateTimeUnit unit,FormattedRelativeDateTimeData & output,UErrorCode & status) const1122 void RelativeDateTimeFormatter::formatRelativeImpl(
1123         double offset,
1124         URelativeDateTimeUnit unit,
1125         FormattedRelativeDateTimeData& output,
1126         UErrorCode& status) const {
1127     if (U_FAILURE(status)) {
1128         return;
1129     }
1130     // TODO:
1131     // The full implementation of this depends on CLDR data that is not yet available,
1132     // see: http://unicode.org/cldr/trac/ticket/9165 Add more relative field data.
1133     // In the meantime do a quick bring-up by calling the old format method; this
1134     // leaves some holes (even for data that is currently available, such as quarter).
1135     // When the new CLDR data is available, update the data storage accordingly,
1136     // rewrite this to use it directly, and rewrite the old format method to call this
1137     // new one; that is covered by https://unicode-org.atlassian.net/browse/ICU-12171.
1138     UDateDirection direction = UDAT_DIRECTION_COUNT;
1139     if (offset > -2.1 && offset < 2.1) {
1140         // Allow a 1% epsilon, so offsets in -1.01..-0.99 map to LAST
1141         double offsetx100 = offset * 100.0;
1142         int32_t intoffset = (offsetx100 < 0)? (int32_t)(offsetx100-0.5) : (int32_t)(offsetx100+0.5);
1143         switch (intoffset) {
1144             case -200/*-2*/: direction = UDAT_DIRECTION_LAST_2; break;
1145             case -100/*-1*/: direction = UDAT_DIRECTION_LAST; break;
1146             case    0/* 0*/: direction = UDAT_DIRECTION_THIS; break;
1147             case  100/* 1*/: direction = UDAT_DIRECTION_NEXT; break;
1148             case  200/* 2*/: direction = UDAT_DIRECTION_NEXT_2; break;
1149             default: break;
1150     	}
1151     }
1152     UDateAbsoluteUnit absunit = UDAT_ABSOLUTE_UNIT_COUNT;
1153     switch (unit) {
1154         case UDAT_REL_UNIT_YEAR:    absunit = UDAT_ABSOLUTE_YEAR; break;
1155         case UDAT_REL_UNIT_QUARTER: absunit = UDAT_ABSOLUTE_QUARTER; break;
1156         case UDAT_REL_UNIT_MONTH:   absunit = UDAT_ABSOLUTE_MONTH; break;
1157         case UDAT_REL_UNIT_WEEK:    absunit = UDAT_ABSOLUTE_WEEK; break;
1158         case UDAT_REL_UNIT_DAY:     absunit = UDAT_ABSOLUTE_DAY; break;
1159         case UDAT_REL_UNIT_SECOND:
1160             if (direction == UDAT_DIRECTION_THIS) {
1161                 absunit = UDAT_ABSOLUTE_NOW;
1162                 direction = UDAT_DIRECTION_PLAIN;
1163             }
1164             break;
1165         case UDAT_REL_UNIT_SUNDAY:  absunit = UDAT_ABSOLUTE_SUNDAY; break;
1166         case UDAT_REL_UNIT_MONDAY:  absunit = UDAT_ABSOLUTE_MONDAY; break;
1167         case UDAT_REL_UNIT_TUESDAY:  absunit = UDAT_ABSOLUTE_TUESDAY; break;
1168         case UDAT_REL_UNIT_WEDNESDAY:  absunit = UDAT_ABSOLUTE_WEDNESDAY; break;
1169         case UDAT_REL_UNIT_THURSDAY:  absunit = UDAT_ABSOLUTE_THURSDAY; break;
1170         case UDAT_REL_UNIT_FRIDAY:  absunit = UDAT_ABSOLUTE_FRIDAY; break;
1171         case UDAT_REL_UNIT_SATURDAY:  absunit = UDAT_ABSOLUTE_SATURDAY; break;
1172         case UDAT_REL_UNIT_HOUR:  absunit = UDAT_ABSOLUTE_HOUR; break;
1173         case UDAT_REL_UNIT_MINUTE:  absunit = UDAT_ABSOLUTE_MINUTE; break;
1174         default: break;
1175     }
1176     if (direction != UDAT_DIRECTION_COUNT && absunit != UDAT_ABSOLUTE_UNIT_COUNT) {
1177         formatAbsoluteImpl(direction, absunit, output, status);
1178         if (output.getStringRef().length() != 0) {
1179             return;
1180         }
1181     }
1182     // otherwise fallback to formatNumeric
1183     formatNumericImpl(offset, unit, output, status);
1184 }
1185 
combineDateAndTime(const UnicodeString & relativeDateString,const UnicodeString & timeString,UnicodeString & appendTo,UErrorCode & status) const1186 UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
1187         const UnicodeString& relativeDateString, const UnicodeString& timeString,
1188         UnicodeString& appendTo, UErrorCode& status) const {
1189     return fCache->getCombinedDateAndTime()->format(
1190             timeString, relativeDateString, appendTo, status);
1191 }
1192 
adjustForContext(UnicodeString & str) const1193 UnicodeString& RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const {
1194     if (fOptBreakIterator == nullptr
1195         || str.length() == 0 || !u_islower(str.char32At(0))) {
1196         return str;
1197     }
1198 
1199     // Must guarantee that one thread at a time accesses the shared break
1200     // iterator.
1201     static UMutex gBrkIterMutex;
1202     Mutex lock(&gBrkIterMutex);
1203     str.toTitle(
1204             fOptBreakIterator->get(),
1205             fLocale,
1206             U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
1207     return str;
1208 }
1209 
checkNoAdjustForContext(UErrorCode & status) const1210 UBool RelativeDateTimeFormatter::checkNoAdjustForContext(UErrorCode& status) const {
1211     // This is unsupported because it's hard to keep fields in sync with title
1212     // casing. The code could be written and tested if there is demand.
1213     if (fOptBreakIterator != nullptr) {
1214         status = U_UNSUPPORTED_ERROR;
1215         return false;
1216     }
1217     return true;
1218 }
1219 
init(NumberFormat * nfToAdopt,BreakIterator * biToAdopt,UErrorCode & status)1220 void RelativeDateTimeFormatter::init(
1221         NumberFormat *nfToAdopt,
1222         BreakIterator *biToAdopt,
1223         UErrorCode &status) {
1224     LocalPointer<NumberFormat> nf(nfToAdopt);
1225     LocalPointer<BreakIterator> bi(biToAdopt);
1226     UnifiedCache::getByLocale(fLocale, fCache, status);
1227     if (U_FAILURE(status)) {
1228         return;
1229     }
1230     const SharedPluralRules *pr = PluralRules::createSharedInstance(
1231             fLocale, UPLURAL_TYPE_CARDINAL, status);
1232     if (U_FAILURE(status)) {
1233         return;
1234     }
1235     SharedObject::copyPtr(pr, fPluralRules);
1236     pr->removeRef();
1237     if (nf.isNull()) {
1238        const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
1239                fLocale, UNUM_DECIMAL, status);
1240         if (U_FAILURE(status)) {
1241             return;
1242         }
1243         SharedObject::copyPtr(shared, fNumberFormat);
1244         shared->removeRef();
1245     } else {
1246         SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
1247         if (shared == nullptr) {
1248             status = U_MEMORY_ALLOCATION_ERROR;
1249             return;
1250         }
1251         nf.orphan();
1252         SharedObject::copyPtr(shared, fNumberFormat);
1253     }
1254     if (bi.isNull()) {
1255         SharedObject::clearPtr(fOptBreakIterator);
1256     } else {
1257         SharedBreakIterator *shared = new SharedBreakIterator(bi.getAlias());
1258         if (shared == nullptr) {
1259             status = U_MEMORY_ALLOCATION_ERROR;
1260             return;
1261         }
1262         bi.orphan();
1263         SharedObject::copyPtr(shared, fOptBreakIterator);
1264     }
1265 }
1266 
1267 U_NAMESPACE_END
1268 
1269 // Plain C API
1270 
1271 U_NAMESPACE_USE
1272 
1273 
1274 // Magic number: "FRDT" (FormattedRelativeDateTime) in ASCII
1275 UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
1276     FormattedRelativeDateTime,
1277     UFormattedRelativeDateTime,
1278     UFormattedRelativeDateTimeImpl,
1279     UFormattedRelativeDateTimeApiHelper,
1280     ureldatefmt,
1281     0x46524454)
1282 
1283 
1284 U_CAPI URelativeDateTimeFormatter* U_EXPORT2
ureldatefmt_open(const char * locale,UNumberFormat * nfToAdopt,UDateRelativeDateTimeFormatterStyle width,UDisplayContext capitalizationContext,UErrorCode * status)1285 ureldatefmt_open( const char*          locale,
1286                   UNumberFormat*       nfToAdopt,
1287                   UDateRelativeDateTimeFormatterStyle width,
1288                   UDisplayContext      capitalizationContext,
1289                   UErrorCode*          status )
1290 {
1291     if (U_FAILURE(*status)) {
1292         return nullptr;
1293     }
1294     LocalPointer<RelativeDateTimeFormatter> formatter(new RelativeDateTimeFormatter(Locale(locale),
1295                                                               (NumberFormat*)nfToAdopt, width,
1296                                                               capitalizationContext, *status), *status);
1297     if (U_FAILURE(*status)) {
1298         return nullptr;
1299     }
1300     return (URelativeDateTimeFormatter*)formatter.orphan();
1301 }
1302 
1303 U_CAPI void U_EXPORT2
ureldatefmt_close(URelativeDateTimeFormatter * reldatefmt)1304 ureldatefmt_close(URelativeDateTimeFormatter *reldatefmt)
1305 {
1306     delete (RelativeDateTimeFormatter*)reldatefmt;
1307 }
1308 
1309 U_CAPI int32_t U_EXPORT2
ureldatefmt_formatNumeric(const URelativeDateTimeFormatter * reldatefmt,double offset,URelativeDateTimeUnit unit,char16_t * result,int32_t resultCapacity,UErrorCode * status)1310 ureldatefmt_formatNumeric( const URelativeDateTimeFormatter* reldatefmt,
1311                     double                offset,
1312                     URelativeDateTimeUnit unit,
1313                     char16_t*                result,
1314                     int32_t               resultCapacity,
1315                     UErrorCode*           status)
1316 {
1317     if (U_FAILURE(*status)) {
1318         return 0;
1319     }
1320     if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
1321         *status = U_ILLEGAL_ARGUMENT_ERROR;
1322         return 0;
1323     }
1324     UnicodeString res;
1325     if (result != nullptr) {
1326         // nullptr destination for pure preflighting: empty dummy string
1327         // otherwise, alias the destination buffer (copied from udat_format)
1328         res.setTo(result, 0, resultCapacity);
1329     }
1330     ((RelativeDateTimeFormatter*)reldatefmt)->formatNumeric(offset, unit, res, *status);
1331     if (U_FAILURE(*status)) {
1332         return 0;
1333     }
1334     return res.extract(result, resultCapacity, *status);
1335 }
1336 
1337 U_CAPI void U_EXPORT2
ureldatefmt_formatNumericToResult(const URelativeDateTimeFormatter * reldatefmt,double offset,URelativeDateTimeUnit unit,UFormattedRelativeDateTime * result,UErrorCode * status)1338 ureldatefmt_formatNumericToResult(
1339         const URelativeDateTimeFormatter* reldatefmt,
1340         double                            offset,
1341         URelativeDateTimeUnit             unit,
1342         UFormattedRelativeDateTime*       result,
1343         UErrorCode*                       status) {
1344     if (U_FAILURE(*status)) {
1345         return;
1346     }
1347     auto* fmt = reinterpret_cast<const RelativeDateTimeFormatter*>(reldatefmt);
1348     auto* resultImpl = UFormattedRelativeDateTimeApiHelper::validate(result, *status);
1349     resultImpl->fImpl = fmt->formatNumericToValue(offset, unit, *status);
1350 }
1351 
1352 U_CAPI int32_t U_EXPORT2
ureldatefmt_format(const URelativeDateTimeFormatter * reldatefmt,double offset,URelativeDateTimeUnit unit,char16_t * result,int32_t resultCapacity,UErrorCode * status)1353 ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt,
1354                     double                offset,
1355                     URelativeDateTimeUnit unit,
1356                     char16_t*                result,
1357                     int32_t               resultCapacity,
1358                     UErrorCode*           status)
1359 {
1360     if (U_FAILURE(*status)) {
1361         return 0;
1362     }
1363     if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
1364         *status = U_ILLEGAL_ARGUMENT_ERROR;
1365         return 0;
1366     }
1367     UnicodeString res;
1368     if (result != nullptr) {
1369         // nullptr destination for pure preflighting: empty dummy string
1370         // otherwise, alias the destination buffer (copied from udat_format)
1371         res.setTo(result, 0, resultCapacity);
1372     }
1373     ((RelativeDateTimeFormatter*)reldatefmt)->format(offset, unit, res, *status);
1374     if (U_FAILURE(*status)) {
1375         return 0;
1376     }
1377     return res.extract(result, resultCapacity, *status);
1378 }
1379 
1380 U_CAPI void U_EXPORT2
ureldatefmt_formatToResult(const URelativeDateTimeFormatter * reldatefmt,double offset,URelativeDateTimeUnit unit,UFormattedRelativeDateTime * result,UErrorCode * status)1381 ureldatefmt_formatToResult(
1382         const URelativeDateTimeFormatter* reldatefmt,
1383         double                            offset,
1384         URelativeDateTimeUnit             unit,
1385         UFormattedRelativeDateTime*       result,
1386         UErrorCode*                       status) {
1387     if (U_FAILURE(*status)) {
1388         return;
1389     }
1390     auto* fmt = reinterpret_cast<const RelativeDateTimeFormatter*>(reldatefmt);
1391     auto* resultImpl = UFormattedRelativeDateTimeApiHelper::validate(result, *status);
1392     resultImpl->fImpl = fmt->formatToValue(offset, unit, *status);
1393 }
1394 
1395 U_CAPI int32_t U_EXPORT2
ureldatefmt_combineDateAndTime(const URelativeDateTimeFormatter * reldatefmt,const char16_t * relativeDateString,int32_t relativeDateStringLen,const char16_t * timeString,int32_t timeStringLen,char16_t * result,int32_t resultCapacity,UErrorCode * status)1396 ureldatefmt_combineDateAndTime( const URelativeDateTimeFormatter* reldatefmt,
1397                     const char16_t *     relativeDateString,
1398                     int32_t           relativeDateStringLen,
1399                     const char16_t *     timeString,
1400                     int32_t           timeStringLen,
1401                     char16_t*            result,
1402                     int32_t           resultCapacity,
1403                     UErrorCode*       status )
1404 {
1405     if (U_FAILURE(*status)) {
1406         return 0;
1407     }
1408     if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0 ||
1409             (relativeDateString == nullptr ? relativeDateStringLen != 0 : relativeDateStringLen < -1) ||
1410             (timeString == nullptr ? timeStringLen != 0 : timeStringLen < -1)) {
1411         *status = U_ILLEGAL_ARGUMENT_ERROR;
1412         return 0;
1413     }
1414     UnicodeString relDateStr((UBool)(relativeDateStringLen == -1), relativeDateString, relativeDateStringLen);
1415     UnicodeString timeStr((UBool)(timeStringLen == -1), timeString, timeStringLen);
1416     UnicodeString res(result, 0, resultCapacity);
1417     ((RelativeDateTimeFormatter*)reldatefmt)->combineDateAndTime(relDateStr, timeStr, res, *status);
1418     if (U_FAILURE(*status)) {
1419         return 0;
1420     }
1421     return res.extract(result, resultCapacity, *status);
1422 }
1423 
1424 #endif /* !UCONFIG_NO_FORMATTING */
1425