tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

reldatefmt.cpp (51608B)


      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
     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:
     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 
    103    void adoptCombinedDateAndTime(SimpleFormatter *fmtToAdopt) {
    104        delete combinedDateAndTime;
    105        combinedDateAndTime = fmtToAdopt;
    106    }
    107    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 
    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.
    133 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 
    145 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.
    167 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 
    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 
    239    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 
    277    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 
    313    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
    340    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
    351    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 
    362    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
    374    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 
    386    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 
    440    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 
    458    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 
    490    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 
    515    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 
    536    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 
    557    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 
    576    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.
    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.
    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 
    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 
    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<>
    705 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:
    747    FormattedRelativeDateTimeData() : FormattedValueStringBuilderImpl(kRDTNumericField) {}
    748    virtual ~FormattedRelativeDateTimeData();
    749 };
    750 
    751 FormattedRelativeDateTimeData::~FormattedRelativeDateTimeData() = default;
    752 
    753 
    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    (void)fOptBreakIterator; // suppress unused field warning
    765    init(nullptr, nullptr, status);
    766 }
    767 
    768 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
    769        const Locale& locale, UErrorCode& status) :
    770        fCache(nullptr),
    771        fNumberFormat(nullptr),
    772        fPluralRules(nullptr),
    773        fStyle(UDAT_STYLE_LONG),
    774        fContext(UDISPCTX_CAPITALIZATION_NONE),
    775        fOptBreakIterator(nullptr),
    776        fLocale(locale) {
    777    init(nullptr, nullptr, status);
    778 }
    779 
    780 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
    781        const Locale& locale, NumberFormat *nfToAdopt, UErrorCode& status) :
    782        fCache(nullptr),
    783        fNumberFormat(nullptr),
    784        fPluralRules(nullptr),
    785        fStyle(UDAT_STYLE_LONG),
    786        fContext(UDISPCTX_CAPITALIZATION_NONE),
    787        fOptBreakIterator(nullptr),
    788        fLocale(locale) {
    789    init(nfToAdopt, nullptr, status);
    790 }
    791 
    792 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
    793        const Locale& locale,
    794        NumberFormat *nfToAdopt,
    795        UDateRelativeDateTimeFormatterStyle styl,
    796        UDisplayContext capitalizationContext,
    797        UErrorCode& status) :
    798        fCache(nullptr),
    799        fNumberFormat(nullptr),
    800        fPluralRules(nullptr),
    801        fStyle(styl),
    802        fContext(capitalizationContext),
    803        fOptBreakIterator(nullptr),
    804        fLocale(locale) {
    805    if (U_FAILURE(status)) {
    806        return;
    807    }
    808    if (styl < 0 || UDAT_STYLE_COUNT <= styl) {
    809        status = U_ILLEGAL_ARGUMENT_ERROR;
    810        return;
    811    }
    812    if ((capitalizationContext >> 8) != UDISPCTX_TYPE_CAPITALIZATION) {
    813        status = U_ILLEGAL_ARGUMENT_ERROR;
    814        return;
    815    }
    816    if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) {
    817 #if !UCONFIG_NO_BREAK_ITERATION
    818        BreakIterator *bi = BreakIterator::createSentenceInstance(locale, status);
    819        if (U_FAILURE(status)) {
    820            return;
    821        }
    822        init(nfToAdopt, bi, status);
    823 #else
    824        status = U_UNSUPPORTED_ERROR;
    825        return;
    826 #endif // !UCONFIG_NO_BREAK_ITERATION
    827    } else {
    828        init(nfToAdopt, nullptr, status);
    829    }
    830 }
    831 
    832 RelativeDateTimeFormatter::RelativeDateTimeFormatter(
    833        const RelativeDateTimeFormatter& other)
    834        : UObject(other),
    835          fCache(other.fCache),
    836          fNumberFormat(other.fNumberFormat),
    837          fPluralRules(other.fPluralRules),
    838          fStyle(other.fStyle),
    839          fContext(other.fContext),
    840          fOptBreakIterator(other.fOptBreakIterator),
    841          fLocale(other.fLocale) {
    842    fCache->addRef();
    843    fNumberFormat->addRef();
    844    fPluralRules->addRef();
    845 #if !UCONFIG_NO_BREAK_ITERATION
    846    if (fOptBreakIterator != nullptr) {
    847      fOptBreakIterator->addRef();
    848    }
    849 #endif // !UCONFIG_NO_BREAK_ITERATION
    850 }
    851 
    852 RelativeDateTimeFormatter& RelativeDateTimeFormatter::operator=(
    853        const RelativeDateTimeFormatter& other) {
    854    if (this != &other) {
    855        SharedObject::copyPtr(other.fCache, fCache);
    856        SharedObject::copyPtr(other.fNumberFormat, fNumberFormat);
    857        SharedObject::copyPtr(other.fPluralRules, fPluralRules);
    858 #if !UCONFIG_NO_BREAK_ITERATION
    859        SharedObject::copyPtr(other.fOptBreakIterator, fOptBreakIterator);
    860 #endif // !UCONFIG_NO_BREAK_ITERATION
    861        fStyle = other.fStyle;
    862        fContext = other.fContext;
    863        fLocale = other.fLocale;
    864    }
    865    return *this;
    866 }
    867 
    868 RelativeDateTimeFormatter::~RelativeDateTimeFormatter() {
    869    if (fCache != nullptr) {
    870        fCache->removeRef();
    871    }
    872    if (fNumberFormat != nullptr) {
    873        fNumberFormat->removeRef();
    874    }
    875    if (fPluralRules != nullptr) {
    876        fPluralRules->removeRef();
    877    }
    878 #if !UCONFIG_NO_BREAK_ITERATION
    879    if (fOptBreakIterator != nullptr) {
    880        fOptBreakIterator->removeRef();
    881    }
    882 #endif // !UCONFIG_NO_BREAK_ITERATION
    883 }
    884 
    885 const NumberFormat& RelativeDateTimeFormatter::getNumberFormat() const {
    886    return **fNumberFormat;
    887 }
    888 
    889 UDisplayContext RelativeDateTimeFormatter::getCapitalizationContext() const {
    890    return fContext;
    891 }
    892 
    893 UDateRelativeDateTimeFormatterStyle RelativeDateTimeFormatter::getFormatStyle() const {
    894    return fStyle;
    895 }
    896 
    897 
    898 // To reduce boilerplate code, we use a helper function that forwards variadic
    899 // arguments to the formatImpl function.
    900 
    901 template<typename F, typename... Args>
    902 UnicodeString& RelativeDateTimeFormatter::doFormat(
    903        F callback,
    904        UnicodeString& appendTo,
    905        UErrorCode& status,
    906        Args... args) const {
    907    FormattedRelativeDateTimeData output;
    908    (this->*callback)(std::forward<Args>(args)..., output, status);
    909    if (U_FAILURE(status)) {
    910        return appendTo;
    911    }
    912    UnicodeString result = output.getStringRef().toUnicodeString();
    913    return appendTo.append(adjustForContext(result));
    914 }
    915 
    916 template<typename F, typename... Args>
    917 FormattedRelativeDateTime RelativeDateTimeFormatter::doFormatToValue(
    918        F callback,
    919        UErrorCode& status,
    920        Args... args) const {
    921    if (!checkNoAdjustForContext(status)) {
    922        return FormattedRelativeDateTime(status);
    923    }
    924    LocalPointer<FormattedRelativeDateTimeData> output(
    925        new FormattedRelativeDateTimeData(), status);
    926    if (U_FAILURE(status)) {
    927        return FormattedRelativeDateTime(status);
    928    }
    929    (this->*callback)(std::forward<Args>(args)..., *output, status);
    930    output->getStringRef().writeTerminator(status);
    931    return FormattedRelativeDateTime(output.orphan());
    932 }
    933 
    934 UnicodeString& RelativeDateTimeFormatter::format(
    935        double quantity,
    936        UDateDirection direction,
    937        UDateRelativeUnit unit,
    938        UnicodeString& appendTo,
    939        UErrorCode& status) const {
    940    return doFormat(
    941        &RelativeDateTimeFormatter::formatImpl,
    942        appendTo,
    943        status,
    944        quantity,
    945        direction,
    946        unit);
    947 }
    948 
    949 FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
    950        double quantity,
    951        UDateDirection direction,
    952        UDateRelativeUnit unit,
    953        UErrorCode& status) const {
    954    return doFormatToValue(
    955        &RelativeDateTimeFormatter::formatImpl,
    956        status,
    957        quantity,
    958        direction,
    959        unit);
    960 }
    961 
    962 void RelativeDateTimeFormatter::formatImpl(
    963        double quantity,
    964        UDateDirection direction,
    965        UDateRelativeUnit unit,
    966        FormattedRelativeDateTimeData& output,
    967        UErrorCode& status) const {
    968    if (U_FAILURE(status)) {
    969        return;
    970    }
    971    if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
    972        status = U_ILLEGAL_ARGUMENT_ERROR;
    973        return;
    974    }
    975    int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
    976 
    977    StandardPlural::Form pluralForm;
    978    QuantityFormatter::formatAndSelect(
    979        quantity,
    980        **fNumberFormat,
    981        **fPluralRules,
    982        output.getStringRef(),
    983        pluralForm,
    984        status);
    985    if (U_FAILURE(status)) {
    986        return;
    987    }
    988 
    989    const SimpleFormatter* formatter =
    990        fCache->getRelativeUnitFormatter(fStyle, unit, bFuture, pluralForm);
    991    if (formatter == nullptr) {
    992        // TODO: WARN - look at quantity formatter's action with an error.
    993        status = U_INVALID_FORMAT_ERROR;
    994        return;
    995    }
    996 
    997    number::impl::SimpleModifier modifier(*formatter, kRDTLiteralField, false);
    998    modifier.formatAsPrefixSuffix(
    999        output.getStringRef(), 0, output.getStringRef().length(), status);
   1000 }
   1001 
   1002 UnicodeString& RelativeDateTimeFormatter::formatNumeric(
   1003        double offset,
   1004        URelativeDateTimeUnit unit,
   1005        UnicodeString& appendTo,
   1006        UErrorCode& status) const {
   1007    return doFormat(
   1008        &RelativeDateTimeFormatter::formatNumericImpl,
   1009        appendTo,
   1010        status,
   1011        offset,
   1012        unit);
   1013 }
   1014 
   1015 FormattedRelativeDateTime RelativeDateTimeFormatter::formatNumericToValue(
   1016        double offset,
   1017        URelativeDateTimeUnit unit,
   1018        UErrorCode& status) const {
   1019    return doFormatToValue(
   1020        &RelativeDateTimeFormatter::formatNumericImpl,
   1021        status,
   1022        offset,
   1023        unit);
   1024 }
   1025 
   1026 void RelativeDateTimeFormatter::formatNumericImpl(
   1027        double offset,
   1028        URelativeDateTimeUnit unit,
   1029        FormattedRelativeDateTimeData& output,
   1030        UErrorCode& status) const {
   1031    if (U_FAILURE(status)) {
   1032        return;
   1033    }
   1034    if (unit < 0 || UDAT_REL_UNIT_COUNT <= unit) {
   1035        status = U_ILLEGAL_ARGUMENT_ERROR;
   1036        return;
   1037    }
   1038    UDateDirection direction = UDAT_DIRECTION_NEXT;
   1039    if (std::signbit(offset)) { // needed to handle -0.0
   1040        direction = UDAT_DIRECTION_LAST;
   1041        offset = -offset;
   1042    }
   1043    if (direction != UDAT_DIRECTION_LAST && direction != UDAT_DIRECTION_NEXT) {
   1044        status = U_ILLEGAL_ARGUMENT_ERROR;
   1045        return;
   1046    }
   1047    int32_t bFuture = direction == UDAT_DIRECTION_NEXT ? 1 : 0;
   1048 
   1049    StandardPlural::Form pluralForm;
   1050    QuantityFormatter::formatAndSelect(
   1051        offset,
   1052        **fNumberFormat,
   1053        **fPluralRules,
   1054        output.getStringRef(),
   1055        pluralForm,
   1056        status);
   1057    if (U_FAILURE(status)) {
   1058        return;
   1059    }
   1060 
   1061    const SimpleFormatter* formatter =
   1062        fCache->getRelativeDateTimeUnitFormatter(fStyle, unit, bFuture, pluralForm);
   1063    if (formatter == nullptr) {
   1064        // TODO: WARN - look at quantity formatter's action with an error.
   1065        status = U_INVALID_FORMAT_ERROR;
   1066        return;
   1067    }
   1068 
   1069    number::impl::SimpleModifier modifier(*formatter, kRDTLiteralField, false);
   1070    modifier.formatAsPrefixSuffix(
   1071        output.getStringRef(), 0, output.getStringRef().length(), status);
   1072 }
   1073 
   1074 UnicodeString& RelativeDateTimeFormatter::format(
   1075        UDateDirection direction,
   1076        UDateAbsoluteUnit unit,
   1077        UnicodeString& appendTo,
   1078        UErrorCode& status) const {
   1079    return doFormat(
   1080        &RelativeDateTimeFormatter::formatAbsoluteImpl,
   1081        appendTo,
   1082        status,
   1083        direction,
   1084        unit);
   1085 }
   1086 
   1087 FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
   1088        UDateDirection direction,
   1089        UDateAbsoluteUnit unit,
   1090        UErrorCode& status) const {
   1091    return doFormatToValue(
   1092        &RelativeDateTimeFormatter::formatAbsoluteImpl,
   1093        status,
   1094        direction,
   1095        unit);
   1096 }
   1097 
   1098 void RelativeDateTimeFormatter::formatAbsoluteImpl(
   1099        UDateDirection direction,
   1100        UDateAbsoluteUnit unit,
   1101        FormattedRelativeDateTimeData& output,
   1102        UErrorCode& status) const {
   1103    if (U_FAILURE(status)) {
   1104        return;
   1105    }
   1106    if ((unit < 0 || UDAT_ABSOLUTE_UNIT_COUNT <= unit) ||
   1107        (direction < 0 || UDAT_DIRECTION_COUNT <= direction) ||
   1108        (unit == UDAT_ABSOLUTE_NOW && direction != UDAT_DIRECTION_PLAIN)) {
   1109        status = U_ILLEGAL_ARGUMENT_ERROR;
   1110        return;
   1111    }
   1112 
   1113    // Get string using fallback.
   1114    output.getStringRef().append(
   1115        fCache->getAbsoluteUnitString(fStyle, unit, direction),
   1116        kRDTLiteralField,
   1117        status);
   1118 }
   1119 
   1120 UnicodeString& RelativeDateTimeFormatter::format(
   1121        double offset,
   1122        URelativeDateTimeUnit unit,
   1123        UnicodeString& appendTo,
   1124        UErrorCode& status) const {
   1125    return doFormat(
   1126        &RelativeDateTimeFormatter::formatRelativeImpl,
   1127        appendTo,
   1128        status,
   1129        offset,
   1130        unit);
   1131 }
   1132 
   1133 FormattedRelativeDateTime RelativeDateTimeFormatter::formatToValue(
   1134        double offset,
   1135        URelativeDateTimeUnit unit,
   1136        UErrorCode& status) const {
   1137    return doFormatToValue(
   1138        &RelativeDateTimeFormatter::formatRelativeImpl,
   1139        status,
   1140        offset,
   1141        unit);
   1142 }
   1143 
   1144 void RelativeDateTimeFormatter::formatRelativeImpl(
   1145        double offset,
   1146        URelativeDateTimeUnit unit,
   1147        FormattedRelativeDateTimeData& output,
   1148        UErrorCode& status) const {
   1149    if (U_FAILURE(status)) {
   1150        return;
   1151    }
   1152    // TODO:
   1153    // The full implementation of this depends on CLDR data that is not yet available,
   1154    // see: http://unicode.org/cldr/trac/ticket/9165 Add more relative field data.
   1155    // In the meantime do a quick bring-up by calling the old format method; this
   1156    // leaves some holes (even for data that is currently available, such as quarter).
   1157    // When the new CLDR data is available, update the data storage accordingly,
   1158    // rewrite this to use it directly, and rewrite the old format method to call this
   1159    // new one; that is covered by https://unicode-org.atlassian.net/browse/ICU-12171.
   1160    UDateDirection direction = UDAT_DIRECTION_COUNT;
   1161    if (offset > -2.1 && offset < 2.1) {
   1162        // Allow a 1% epsilon, so offsets in -1.01..-0.99 map to LAST
   1163        double offsetx100 = offset * 100.0;
   1164        int32_t intoffset = offsetx100 < 0 ? static_cast<int32_t>(offsetx100 - 0.5)
   1165                                           : static_cast<int32_t>(offsetx100 + 0.5);
   1166        switch (intoffset) {
   1167            case -200/*-2*/: direction = UDAT_DIRECTION_LAST_2; break;
   1168            case -100/*-1*/: direction = UDAT_DIRECTION_LAST; break;
   1169            case    0/* 0*/: direction = UDAT_DIRECTION_THIS; break;
   1170            case  100/* 1*/: direction = UDAT_DIRECTION_NEXT; break;
   1171            case  200/* 2*/: direction = UDAT_DIRECTION_NEXT_2; break;
   1172            default: break;
   1173    	}
   1174    }
   1175    UDateAbsoluteUnit absunit = UDAT_ABSOLUTE_UNIT_COUNT;
   1176    switch (unit) {
   1177        case UDAT_REL_UNIT_YEAR:    absunit = UDAT_ABSOLUTE_YEAR; break;
   1178        case UDAT_REL_UNIT_QUARTER: absunit = UDAT_ABSOLUTE_QUARTER; break;
   1179        case UDAT_REL_UNIT_MONTH:   absunit = UDAT_ABSOLUTE_MONTH; break;
   1180        case UDAT_REL_UNIT_WEEK:    absunit = UDAT_ABSOLUTE_WEEK; break;
   1181        case UDAT_REL_UNIT_DAY:     absunit = UDAT_ABSOLUTE_DAY; break;
   1182        case UDAT_REL_UNIT_SECOND:
   1183            if (direction == UDAT_DIRECTION_THIS) {
   1184                absunit = UDAT_ABSOLUTE_NOW;
   1185                direction = UDAT_DIRECTION_PLAIN;
   1186            }
   1187            break;
   1188        case UDAT_REL_UNIT_SUNDAY:  absunit = UDAT_ABSOLUTE_SUNDAY; break;
   1189        case UDAT_REL_UNIT_MONDAY:  absunit = UDAT_ABSOLUTE_MONDAY; break;
   1190        case UDAT_REL_UNIT_TUESDAY:  absunit = UDAT_ABSOLUTE_TUESDAY; break;
   1191        case UDAT_REL_UNIT_WEDNESDAY:  absunit = UDAT_ABSOLUTE_WEDNESDAY; break;
   1192        case UDAT_REL_UNIT_THURSDAY:  absunit = UDAT_ABSOLUTE_THURSDAY; break;
   1193        case UDAT_REL_UNIT_FRIDAY:  absunit = UDAT_ABSOLUTE_FRIDAY; break;
   1194        case UDAT_REL_UNIT_SATURDAY:  absunit = UDAT_ABSOLUTE_SATURDAY; break;
   1195        case UDAT_REL_UNIT_HOUR:  absunit = UDAT_ABSOLUTE_HOUR; break;
   1196        case UDAT_REL_UNIT_MINUTE:  absunit = UDAT_ABSOLUTE_MINUTE; break;
   1197        default: break;
   1198    }
   1199    if (direction != UDAT_DIRECTION_COUNT && absunit != UDAT_ABSOLUTE_UNIT_COUNT) {
   1200        formatAbsoluteImpl(direction, absunit, output, status);
   1201        if (output.getStringRef().length() != 0) {
   1202            return;
   1203        }
   1204    }
   1205    // otherwise fallback to formatNumeric
   1206    formatNumericImpl(offset, unit, output, status);
   1207 }
   1208 
   1209 UnicodeString& RelativeDateTimeFormatter::combineDateAndTime(
   1210        const UnicodeString& relativeDateString, const UnicodeString& timeString,
   1211        UnicodeString& appendTo, UErrorCode& status) const {
   1212    return fCache->getCombinedDateAndTime()->format(
   1213            timeString, relativeDateString, appendTo, status);
   1214 }
   1215 
   1216 UnicodeString& RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) const {
   1217 #if !UCONFIG_NO_BREAK_ITERATION
   1218    if (fOptBreakIterator == nullptr
   1219        || str.length() == 0 || !u_islower(str.char32At(0))) {
   1220        return str;
   1221    }
   1222 
   1223    // Must guarantee that one thread at a time accesses the shared break
   1224    // iterator.
   1225    static UMutex gBrkIterMutex;
   1226    Mutex lock(&gBrkIterMutex);
   1227    str.toTitle(
   1228            fOptBreakIterator->get(),
   1229            fLocale,
   1230            U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
   1231 #endif // !UCONFIG_NO_BREAK_ITERATION
   1232    return str;
   1233 }
   1234 
   1235 UBool RelativeDateTimeFormatter::checkNoAdjustForContext(UErrorCode& status) const {
   1236 #if !UCONFIG_NO_BREAK_ITERATION
   1237    // This is unsupported because it's hard to keep fields in sync with title
   1238    // casing. The code could be written and tested if there is demand.
   1239    if (fOptBreakIterator != nullptr) {
   1240        status = U_UNSUPPORTED_ERROR;
   1241        return false;
   1242    }
   1243 #else
   1244    (void)status; // suppress unused argument warning
   1245 #endif // !UCONFIG_NO_BREAK_ITERATION
   1246    return true;
   1247 }
   1248 
   1249 void RelativeDateTimeFormatter::init(
   1250        NumberFormat *nfToAdopt,
   1251 #if !UCONFIG_NO_BREAK_ITERATION
   1252        BreakIterator *biToAdopt,
   1253 #else
   1254        std::nullptr_t,
   1255 #endif // !UCONFIG_NO_BREAK_ITERATION
   1256        UErrorCode &status) {
   1257    LocalPointer<NumberFormat> nf(nfToAdopt);
   1258 #if !UCONFIG_NO_BREAK_ITERATION
   1259    LocalPointer<BreakIterator> bi(biToAdopt);
   1260 #endif // !UCONFIG_NO_BREAK_ITERATION
   1261    UnifiedCache::getByLocale(fLocale, fCache, status);
   1262    if (U_FAILURE(status)) {
   1263        return;
   1264    }
   1265    const SharedPluralRules *pr = PluralRules::createSharedInstance(
   1266            fLocale, UPLURAL_TYPE_CARDINAL, status);
   1267    if (U_FAILURE(status)) {
   1268        return;
   1269    }
   1270    SharedObject::copyPtr(pr, fPluralRules);
   1271    pr->removeRef();
   1272    if (nf.isNull()) {
   1273       const SharedNumberFormat *shared = NumberFormat::createSharedInstance(
   1274               fLocale, UNUM_DECIMAL, status);
   1275        if (U_FAILURE(status)) {
   1276            return;
   1277        }
   1278        SharedObject::copyPtr(shared, fNumberFormat);
   1279        shared->removeRef();
   1280    } else {
   1281        SharedNumberFormat *shared = new SharedNumberFormat(nf.getAlias());
   1282        if (shared == nullptr) {
   1283            status = U_MEMORY_ALLOCATION_ERROR;
   1284            return;
   1285        }
   1286        nf.orphan();
   1287        SharedObject::copyPtr(shared, fNumberFormat);
   1288    }
   1289 #if !UCONFIG_NO_BREAK_ITERATION
   1290    if (bi.isNull()) {
   1291        SharedObject::clearPtr(fOptBreakIterator);
   1292    } else {
   1293        SharedBreakIterator *shared = new SharedBreakIterator(bi.getAlias());
   1294        if (shared == nullptr) {
   1295            status = U_MEMORY_ALLOCATION_ERROR;
   1296            return;
   1297        }
   1298        bi.orphan();
   1299        SharedObject::copyPtr(shared, fOptBreakIterator);
   1300    }
   1301 #endif // !UCONFIG_NO_BREAK_ITERATION
   1302 }
   1303 
   1304 U_NAMESPACE_END
   1305 
   1306 // Plain C API
   1307 
   1308 U_NAMESPACE_USE
   1309 
   1310 
   1311 // Magic number: "FRDT" (FormattedRelativeDateTime) in ASCII
   1312 UPRV_FORMATTED_VALUE_CAPI_AUTO_IMPL(
   1313    FormattedRelativeDateTime,
   1314    UFormattedRelativeDateTime,
   1315    UFormattedRelativeDateTimeImpl,
   1316    UFormattedRelativeDateTimeApiHelper,
   1317    ureldatefmt,
   1318    0x46524454)
   1319 
   1320 
   1321 U_CAPI URelativeDateTimeFormatter* U_EXPORT2
   1322 ureldatefmt_open( const char*          locale,
   1323                  UNumberFormat*       nfToAdopt,
   1324                  UDateRelativeDateTimeFormatterStyle width,
   1325                  UDisplayContext      capitalizationContext,
   1326                  UErrorCode*          status )
   1327 {
   1328    if (U_FAILURE(*status)) {
   1329        return nullptr;
   1330    }
   1331    LocalPointer<RelativeDateTimeFormatter> formatter(new RelativeDateTimeFormatter(Locale(locale),
   1332                                                              (NumberFormat*)nfToAdopt, width,
   1333                                                              capitalizationContext, *status), *status);
   1334    if (U_FAILURE(*status)) {
   1335        return nullptr;
   1336    }
   1337    return (URelativeDateTimeFormatter*)formatter.orphan();
   1338 }
   1339 
   1340 U_CAPI void U_EXPORT2
   1341 ureldatefmt_close(URelativeDateTimeFormatter *reldatefmt)
   1342 {
   1343    delete (RelativeDateTimeFormatter*)reldatefmt;
   1344 }
   1345 
   1346 U_CAPI int32_t U_EXPORT2
   1347 ureldatefmt_formatNumeric( const URelativeDateTimeFormatter* reldatefmt,
   1348                    double                offset,
   1349                    URelativeDateTimeUnit unit,
   1350                    char16_t*                result,
   1351                    int32_t               resultCapacity,
   1352                    UErrorCode*           status)
   1353 {
   1354    if (U_FAILURE(*status)) {
   1355        return 0;
   1356    }
   1357    if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
   1358        *status = U_ILLEGAL_ARGUMENT_ERROR;
   1359        return 0;
   1360    }
   1361    UnicodeString res;
   1362    if (result != nullptr) {
   1363        // nullptr destination for pure preflighting: empty dummy string
   1364        // otherwise, alias the destination buffer (copied from udat_format)
   1365        res.setTo(result, 0, resultCapacity);
   1366    }
   1367    ((RelativeDateTimeFormatter*)reldatefmt)->formatNumeric(offset, unit, res, *status);
   1368    if (U_FAILURE(*status)) {
   1369        return 0;
   1370    }
   1371    return res.extract(result, resultCapacity, *status);
   1372 }
   1373 
   1374 U_CAPI void U_EXPORT2
   1375 ureldatefmt_formatNumericToResult(
   1376        const URelativeDateTimeFormatter* reldatefmt,
   1377        double                            offset,
   1378        URelativeDateTimeUnit             unit,
   1379        UFormattedRelativeDateTime*       result,
   1380        UErrorCode*                       status) {
   1381    if (U_FAILURE(*status)) {
   1382        return;
   1383    }
   1384    const auto* fmt = reinterpret_cast<const RelativeDateTimeFormatter*>(reldatefmt);
   1385    auto* resultImpl = UFormattedRelativeDateTimeApiHelper::validate(result, *status);
   1386    resultImpl->fImpl = fmt->formatNumericToValue(offset, unit, *status);
   1387 }
   1388 
   1389 U_CAPI int32_t U_EXPORT2
   1390 ureldatefmt_format( const URelativeDateTimeFormatter* reldatefmt,
   1391                    double                offset,
   1392                    URelativeDateTimeUnit unit,
   1393                    char16_t*                result,
   1394                    int32_t               resultCapacity,
   1395                    UErrorCode*           status)
   1396 {
   1397    if (U_FAILURE(*status)) {
   1398        return 0;
   1399    }
   1400    if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0) {
   1401        *status = U_ILLEGAL_ARGUMENT_ERROR;
   1402        return 0;
   1403    }
   1404    UnicodeString res;
   1405    if (result != nullptr) {
   1406        // nullptr destination for pure preflighting: empty dummy string
   1407        // otherwise, alias the destination buffer (copied from udat_format)
   1408        res.setTo(result, 0, resultCapacity);
   1409    }
   1410    ((RelativeDateTimeFormatter*)reldatefmt)->format(offset, unit, res, *status);
   1411    if (U_FAILURE(*status)) {
   1412        return 0;
   1413    }
   1414    return res.extract(result, resultCapacity, *status);
   1415 }
   1416 
   1417 U_CAPI void U_EXPORT2
   1418 ureldatefmt_formatToResult(
   1419        const URelativeDateTimeFormatter* reldatefmt,
   1420        double                            offset,
   1421        URelativeDateTimeUnit             unit,
   1422        UFormattedRelativeDateTime*       result,
   1423        UErrorCode*                       status) {
   1424    if (U_FAILURE(*status)) {
   1425        return;
   1426    }
   1427    const auto* fmt = reinterpret_cast<const RelativeDateTimeFormatter*>(reldatefmt);
   1428    auto* resultImpl = UFormattedRelativeDateTimeApiHelper::validate(result, *status);
   1429    resultImpl->fImpl = fmt->formatToValue(offset, unit, *status);
   1430 }
   1431 
   1432 U_CAPI int32_t U_EXPORT2
   1433 ureldatefmt_combineDateAndTime( const URelativeDateTimeFormatter* reldatefmt,
   1434                    const char16_t *     relativeDateString,
   1435                    int32_t           relativeDateStringLen,
   1436                    const char16_t *     timeString,
   1437                    int32_t           timeStringLen,
   1438                    char16_t*            result,
   1439                    int32_t           resultCapacity,
   1440                    UErrorCode*       status )
   1441 {
   1442    if (U_FAILURE(*status)) {
   1443        return 0;
   1444    }
   1445    if (result == nullptr ? resultCapacity != 0 : resultCapacity < 0 ||
   1446            (relativeDateString == nullptr ? relativeDateStringLen != 0 : relativeDateStringLen < -1) ||
   1447            (timeString == nullptr ? timeStringLen != 0 : timeStringLen < -1)) {
   1448        *status = U_ILLEGAL_ARGUMENT_ERROR;
   1449        return 0;
   1450    }
   1451    UnicodeString relDateStr(relativeDateStringLen == -1, relativeDateString, relativeDateStringLen);
   1452    UnicodeString timeStr(timeStringLen == -1, timeString, timeStringLen);
   1453    UnicodeString res(result, 0, resultCapacity);
   1454    ((RelativeDateTimeFormatter*)reldatefmt)->combineDateAndTime(relDateStr, timeStr, res, *status);
   1455    if (U_FAILURE(*status)) {
   1456        return 0;
   1457    }
   1458    return res.extract(result, resultCapacity, *status);
   1459 }
   1460 
   1461 #endif /* !UCONFIG_NO_FORMATTING */