tor-browser

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

reldtfmt.cpp (23339B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 * Copyright (C) 2007-2016, International Business Machines Corporation and
      6 * others. All Rights Reserved.
      7 *******************************************************************************
      8 */
      9 
     10 #include "unicode/utypes.h"
     11 
     12 #if !UCONFIG_NO_FORMATTING
     13 
     14 #include <stdlib.h>
     15 
     16 #include "unicode/datefmt.h"
     17 #include "unicode/reldatefmt.h"
     18 #include "unicode/simpleformatter.h"
     19 #include "unicode/smpdtfmt.h"
     20 #include "unicode/udisplaycontext.h"
     21 #include "unicode/uchar.h"
     22 #include "unicode/brkiter.h"
     23 #include "unicode/ucasemap.h"
     24 #include "reldtfmt.h"
     25 #include "cmemory.h"
     26 #include "uresimp.h"
     27 
     28 U_NAMESPACE_BEGIN
     29 
     30 
     31 /**
     32 * An array of URelativeString structs is used to store the resource data loaded out of the bundle.
     33 */
     34 struct URelativeString {
     35    int32_t offset;         /** offset of this item, such as, the relative date **/
     36    int32_t len;            /** length of the string **/
     37    const char16_t* string;    /** string, or nullptr if not set **/
     38 };
     39 
     40 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RelativeDateFormat)
     41 
     42 RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) :
     43 DateFormat(other), fDateTimeFormatter(nullptr), fDatePattern(other.fDatePattern),
     44 fTimePattern(other.fTimePattern), fCombinedFormat(nullptr),
     45 fDateStyle(other.fDateStyle), fLocale(other.fLocale),
     46 fDatesLen(other.fDatesLen), fDates(nullptr),
     47 fCombinedHasDateAtStart(other.fCombinedHasDateAtStart),
     48 fCapitalizationInfoSet(other.fCapitalizationInfoSet),
     49 fCapitalizationOfRelativeUnitsForUIListMenu(other.fCapitalizationOfRelativeUnitsForUIListMenu),
     50 fCapitalizationOfRelativeUnitsForStandAlone(other.fCapitalizationOfRelativeUnitsForStandAlone),
     51 fCapitalizationBrkIter(nullptr)
     52 {
     53    if(other.fDateTimeFormatter != nullptr) {
     54        fDateTimeFormatter = other.fDateTimeFormatter->clone();
     55    }
     56    if(other.fCombinedFormat != nullptr) {
     57        fCombinedFormat = new SimpleFormatter(*other.fCombinedFormat);
     58    }
     59    if (fDatesLen > 0) {
     60        fDates = static_cast<URelativeString*>(uprv_malloc(sizeof(fDates[0]) * static_cast<size_t>(fDatesLen)));
     61        uprv_memcpy(fDates, other.fDates, sizeof(fDates[0])*(size_t)fDatesLen);
     62    }
     63 #if !UCONFIG_NO_BREAK_ITERATION
     64    if (other.fCapitalizationBrkIter != nullptr) {
     65        fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();
     66    }
     67 #endif
     68 }
     69 
     70 RelativeDateFormat::RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle,
     71                                        const Locale& locale, UErrorCode& status) :
     72 DateFormat(), fDateTimeFormatter(nullptr), fDatePattern(), fTimePattern(), fCombinedFormat(nullptr),
     73 fDateStyle(dateStyle), fLocale(locale), fDatesLen(0), fDates(nullptr),
     74 fCombinedHasDateAtStart(false), fCapitalizationInfoSet(false),
     75 fCapitalizationOfRelativeUnitsForUIListMenu(false), fCapitalizationOfRelativeUnitsForStandAlone(false),
     76 fCapitalizationBrkIter(nullptr)
     77 {
     78    if(U_FAILURE(status) ) {
     79        return;
     80    }
     81    if (dateStyle != UDAT_FULL_RELATIVE &&
     82        dateStyle != UDAT_LONG_RELATIVE &&
     83        dateStyle != UDAT_MEDIUM_RELATIVE &&
     84        dateStyle != UDAT_SHORT_RELATIVE &&
     85        dateStyle != UDAT_RELATIVE) {
     86        status = U_ILLEGAL_ARGUMENT_ERROR;
     87        return;
     88    }
     89 
     90    if (timeStyle < UDAT_NONE || timeStyle > UDAT_SHORT) {
     91        // don't support other time styles (e.g. relative styles), for now
     92        status = U_ILLEGAL_ARGUMENT_ERROR;
     93        return;
     94    }
     95    UDateFormatStyle baseDateStyle = (dateStyle > UDAT_SHORT) ? static_cast<UDateFormatStyle>(dateStyle & ~UDAT_RELATIVE) : dateStyle;
     96    DateFormat * df;
     97    // Get fDateTimeFormatter from either date or time style (does not matter, we will override the pattern).
     98    // We do need to get separate patterns for the date & time styles.
     99    if (baseDateStyle != UDAT_NONE) {
    100        df = createDateInstance(static_cast<EStyle>(baseDateStyle), locale);
    101        fDateTimeFormatter=dynamic_cast<SimpleDateFormat *>(df);
    102        if (fDateTimeFormatter == nullptr) {
    103            status = U_UNSUPPORTED_ERROR;
    104             return;
    105        }
    106        fDateTimeFormatter->toPattern(fDatePattern);
    107        if (timeStyle != UDAT_NONE) {
    108            df = createTimeInstance(static_cast<EStyle>(timeStyle), locale);
    109            SimpleDateFormat *sdf = dynamic_cast<SimpleDateFormat *>(df);
    110            if (sdf != nullptr) {
    111                sdf->toPattern(fTimePattern);
    112                delete sdf;
    113            }
    114        }
    115    } else {
    116        // does not matter whether timeStyle is UDAT_NONE, we need something for fDateTimeFormatter
    117        df = createTimeInstance(static_cast<EStyle>(timeStyle), locale);
    118        fDateTimeFormatter=dynamic_cast<SimpleDateFormat *>(df);
    119        if (fDateTimeFormatter == nullptr) {
    120            status = U_UNSUPPORTED_ERROR;
    121            delete df;
    122            return;
    123        }
    124        fDateTimeFormatter->toPattern(fTimePattern);
    125    }
    126 
    127    // Initialize the parent fCalendar, so that parse() works correctly.
    128    initializeCalendar(nullptr, locale, status);
    129    loadDates(status);
    130 }
    131 
    132 RelativeDateFormat::~RelativeDateFormat() {
    133    delete fDateTimeFormatter;
    134    delete fCombinedFormat;
    135    uprv_free(fDates);
    136 #if !UCONFIG_NO_BREAK_ITERATION
    137    delete fCapitalizationBrkIter;
    138 #endif
    139 }
    140 
    141 
    142 RelativeDateFormat* RelativeDateFormat::clone() const {
    143    return new RelativeDateFormat(*this);
    144 }
    145 
    146 bool RelativeDateFormat::operator==(const Format& other) const {
    147    if(DateFormat::operator==(other)) {
    148        // The DateFormat::operator== check for fCapitalizationContext equality above
    149        //   is sufficient to check equality of all derived context-related data.
    150        // DateFormat::operator== guarantees following cast is safe
    151        RelativeDateFormat* that = (RelativeDateFormat*)&other;
    152        return (fDateStyle==that->fDateStyle   &&
    153                fDatePattern==that->fDatePattern   &&
    154                fTimePattern==that->fTimePattern   &&
    155                fLocale==that->fLocale );
    156    }
    157    return false;
    158 }
    159 
    160 static const char16_t APOSTROPHE = static_cast<char16_t>(0x0027);
    161 
    162 UnicodeString& RelativeDateFormat::format(  Calendar& cal,
    163                                UnicodeString& appendTo,
    164                                FieldPosition& pos) const {
    165                                
    166    UErrorCode status = U_ZERO_ERROR;
    167    UnicodeString relativeDayString;
    168    UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
    169    
    170    // calculate the difference, in days, between 'cal' and now.
    171    int dayDiff = dayDifference(cal, status);
    172 
    173    // look up string
    174    int32_t len = 0;
    175    const char16_t *theString = getStringForDay(dayDiff, len, status);
    176    if(U_SUCCESS(status) && (theString!=nullptr)) {
    177        // found a relative string
    178        relativeDayString.setTo(theString, len);
    179    }
    180 
    181    if ( relativeDayString.length() > 0 && !fDatePattern.isEmpty() && 
    182         (fTimePattern.isEmpty() || fCombinedFormat == nullptr || fCombinedHasDateAtStart)) {
    183 #if !UCONFIG_NO_BREAK_ITERATION
    184        // capitalize relativeDayString according to context for relative, set formatter no context
    185        if ( u_islower(relativeDayString.char32At(0)) && fCapitalizationBrkIter!= nullptr &&
    186             ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
    187               (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) ||
    188               (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone) ) ) {
    189            // titlecase first word of relativeDayString
    190            relativeDayString.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
    191        }
    192 #endif
    193        fDateTimeFormatter->setContext(UDISPCTX_CAPITALIZATION_NONE, status);
    194    } else {
    195        // set our context for the formatter
    196        fDateTimeFormatter->setContext(capitalizationContext, status);
    197    }
    198 
    199    if (fDatePattern.isEmpty()) {
    200        fDateTimeFormatter->applyPattern(fTimePattern);
    201        fDateTimeFormatter->format(cal,appendTo,pos);
    202    } else if (fTimePattern.isEmpty() || fCombinedFormat == nullptr) {
    203        if (relativeDayString.length() > 0) {
    204            appendTo.append(relativeDayString);
    205        } else {
    206            fDateTimeFormatter->applyPattern(fDatePattern);
    207            fDateTimeFormatter->format(cal,appendTo,pos);
    208        }
    209    } else {
    210        UnicodeString datePattern;
    211        if (relativeDayString.length() > 0) {
    212            // Need to quote the relativeDayString to make it a legal date pattern
    213            relativeDayString.findAndReplace(UNICODE_STRING("'", 1), UNICODE_STRING("''", 2)); // double any existing APOSTROPHE
    214            relativeDayString.insert(0, APOSTROPHE); // add APOSTROPHE at beginning...
    215            relativeDayString.append(APOSTROPHE); // and at end
    216            datePattern.setTo(relativeDayString);
    217        } else {
    218            datePattern.setTo(fDatePattern);
    219        }
    220        UnicodeString combinedPattern;
    221        fCombinedFormat->format(fTimePattern, datePattern, combinedPattern, status);
    222        fDateTimeFormatter->applyPattern(combinedPattern);
    223        fDateTimeFormatter->format(cal,appendTo,pos);
    224    }
    225 
    226    return appendTo;
    227 }
    228 
    229 
    230 
    231 UnicodeString&
    232 RelativeDateFormat::format(const Formattable& obj, 
    233                         UnicodeString& appendTo, 
    234                         FieldPosition& pos,
    235                         UErrorCode& status) const
    236 {
    237    // this is just here to get around the hiding problem
    238    // (the previous format() override would hide the version of
    239    // format() on DateFormat that this function correspond to, so we
    240    // have to redefine it here)
    241    return DateFormat::format(obj, appendTo, pos, status);
    242 }
    243 
    244 
    245 void RelativeDateFormat::parse( const UnicodeString& text,
    246                    Calendar& cal,
    247                    ParsePosition& pos) const {
    248 
    249    int32_t startIndex = pos.getIndex();
    250    if (fDatePattern.isEmpty()) {
    251        // no date pattern, try parsing as time
    252        fDateTimeFormatter->applyPattern(fTimePattern);
    253        fDateTimeFormatter->parse(text,cal,pos);
    254    } else if (fTimePattern.isEmpty() || fCombinedFormat == nullptr) {
    255        // no time pattern or way to combine, try parsing as date
    256        // first check whether text matches a relativeDayString
    257        UBool matchedRelative = false;
    258        for (int n=0; n < fDatesLen && !matchedRelative; n++) {
    259            if (fDates[n].string != nullptr &&
    260                    text.compare(startIndex, fDates[n].len, fDates[n].string) == 0) {
    261                // it matched, handle the relative day string
    262                UErrorCode status = U_ZERO_ERROR;
    263                matchedRelative = true;
    264 
    265                // Set the calendar to now+offset
    266                cal.setTime(Calendar::getNow(),status);
    267                cal.add(UCAL_DATE,fDates[n].offset, status);
    268 
    269                if(U_FAILURE(status)) { 
    270                    // failure in setting calendar field, set offset to beginning of rel day string
    271                    pos.setErrorIndex(startIndex);
    272                } else {
    273                    pos.setIndex(startIndex + fDates[n].len);
    274                }
    275            }
    276        }
    277        if (!matchedRelative) {
    278            // just parse as normal date
    279            fDateTimeFormatter->applyPattern(fDatePattern);
    280            fDateTimeFormatter->parse(text,cal,pos);
    281        }
    282    } else {
    283        // Here we replace any relativeDayString in text with the equivalent date
    284        // formatted per fDatePattern, then parse text normally using the combined pattern.
    285        UnicodeString modifiedText(text);
    286        FieldPosition fPos;
    287        int32_t dateStart = 0, origDateLen = 0, modDateLen = 0;
    288        UErrorCode status = U_ZERO_ERROR;
    289        for (int n=0; n < fDatesLen; n++) {
    290            int32_t relativeStringOffset;
    291            if (fDates[n].string != nullptr &&
    292                    (relativeStringOffset = modifiedText.indexOf(fDates[n].string, fDates[n].len, startIndex)) >= startIndex) {
    293                // it matched, replace the relative date with a real one for parsing
    294                UnicodeString dateString;
    295                Calendar * tempCal = cal.clone();
    296 
    297                // Set the calendar to now+offset
    298                tempCal->setTime(Calendar::getNow(),status);
    299                tempCal->add(UCAL_DATE,fDates[n].offset, status);
    300                if(U_FAILURE(status)) { 
    301                    pos.setErrorIndex(startIndex);
    302                    delete tempCal;
    303                    return;
    304                }
    305 
    306                fDateTimeFormatter->applyPattern(fDatePattern);
    307                fDateTimeFormatter->format(*tempCal, dateString, fPos);
    308                dateStart = relativeStringOffset;
    309                origDateLen = fDates[n].len;
    310                modDateLen = dateString.length();
    311                modifiedText.replace(dateStart, origDateLen, dateString);
    312                delete tempCal;
    313                break;
    314            }
    315        }
    316        UnicodeString combinedPattern;
    317        fCombinedFormat->format(fTimePattern, fDatePattern, combinedPattern, status);
    318        fDateTimeFormatter->applyPattern(combinedPattern);
    319        fDateTimeFormatter->parse(modifiedText,cal,pos);
    320 
    321        // Adjust offsets
    322        UBool noError = (pos.getErrorIndex() < 0);
    323        int32_t offset = (noError)? pos.getIndex(): pos.getErrorIndex();
    324        if (offset >= dateStart + modDateLen) {
    325            // offset at or after the end of the replaced text,
    326            // correct by the difference between original and replacement
    327            offset -= (modDateLen - origDateLen);
    328        } else if (offset >= dateStart) {
    329            // offset in the replaced text, set it to the beginning of that text
    330            // (i.e. the beginning of the relative day string)
    331            offset = dateStart;
    332        }
    333        if (noError) {
    334            pos.setIndex(offset);
    335        } else {
    336            pos.setErrorIndex(offset);
    337        }
    338    }
    339 }
    340 
    341 UDate
    342 RelativeDateFormat::parse( const UnicodeString& text,
    343                         ParsePosition& pos) const {
    344    // redefined here because the other parse() function hides this function's
    345    // counterpart on DateFormat
    346    return DateFormat::parse(text, pos);
    347 }
    348 
    349 UDate
    350 RelativeDateFormat::parse(const UnicodeString& text, UErrorCode& status) const
    351 {
    352    // redefined here because the other parse() function hides this function's
    353    // counterpart on DateFormat
    354    return DateFormat::parse(text, status);
    355 }
    356 
    357 
    358 const char16_t *RelativeDateFormat::getStringForDay(int32_t day, int32_t &len, UErrorCode &status) const {
    359    if(U_FAILURE(status)) {
    360        return nullptr;
    361    }
    362 
    363    // Is it inside the resource bundle's range?
    364    int n = day + UDAT_DIRECTION_THIS;
    365    if (n >= 0 && n < fDatesLen) {
    366        if (fDates[n].offset == day && fDates[n].string != nullptr) {
    367            len = fDates[n].len;
    368            return fDates[n].string;
    369        }
    370    }
    371    return nullptr;  // not found.
    372 }
    373 
    374 UnicodeString&
    375 RelativeDateFormat::toPattern(UnicodeString& result, UErrorCode& status) const
    376 {
    377    if (!U_FAILURE(status)) {
    378        result.remove();
    379        if (fDatePattern.isEmpty()) {
    380            result.setTo(fTimePattern);
    381        } else if (fTimePattern.isEmpty() || fCombinedFormat == nullptr) {
    382            result.setTo(fDatePattern);
    383        } else {
    384            fCombinedFormat->format(fTimePattern, fDatePattern, result, status);
    385        }
    386    }
    387    return result;
    388 }
    389 
    390 UnicodeString&
    391 RelativeDateFormat::toPatternDate(UnicodeString& result, UErrorCode& status) const
    392 {
    393    if (!U_FAILURE(status)) {
    394        result.remove();
    395        result.setTo(fDatePattern);
    396    }
    397    return result;
    398 }
    399 
    400 UnicodeString&
    401 RelativeDateFormat::toPatternTime(UnicodeString& result, UErrorCode& status) const
    402 {
    403    if (!U_FAILURE(status)) {
    404        result.remove();
    405        result.setTo(fTimePattern);
    406    }
    407    return result;
    408 }
    409 
    410 void
    411 RelativeDateFormat::applyPatterns(const UnicodeString& datePattern, const UnicodeString& timePattern, UErrorCode &status)
    412 {
    413    if (!U_FAILURE(status)) {
    414        fDatePattern.setTo(datePattern);
    415        fTimePattern.setTo(timePattern);
    416    }
    417 }
    418 
    419 const DateFormatSymbols*
    420 RelativeDateFormat::getDateFormatSymbols() const
    421 {
    422    return fDateTimeFormatter->getDateFormatSymbols();
    423 }
    424 
    425 // override the DateFormat implementation in order to
    426 // lazily initialize relevant items
    427 void
    428 RelativeDateFormat::setContext(UDisplayContext value, UErrorCode& status)
    429 {
    430    DateFormat::setContext(value, status);
    431    if (U_SUCCESS(status)) {
    432        if (!fCapitalizationInfoSet &&
    433                (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE)) {
    434            initCapitalizationContextInfo(fLocale);
    435            fCapitalizationInfoSet = true;
    436        }
    437 #if !UCONFIG_NO_BREAK_ITERATION
    438        if ( fCapitalizationBrkIter == nullptr && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
    439                (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) ||
    440                (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone)) ) {
    441            status = U_ZERO_ERROR;
    442            fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
    443            if (U_FAILURE(status)) {
    444                delete fCapitalizationBrkIter;
    445                fCapitalizationBrkIter = nullptr;
    446            }
    447        }
    448 #endif
    449    }
    450 }
    451 
    452 void
    453 RelativeDateFormat::initCapitalizationContextInfo(const Locale& thelocale)
    454 {
    455 #if !UCONFIG_NO_BREAK_ITERATION
    456    const char * localeID = (thelocale != nullptr)? thelocale.getBaseName(): nullptr;
    457    UErrorCode status = U_ZERO_ERROR;
    458    LocalUResourceBundlePointer rb(ures_open(nullptr, localeID, &status));
    459    ures_getByKeyWithFallback(rb.getAlias(),
    460                              "contextTransforms/relative",
    461                               rb.getAlias(), &status);
    462    if (U_SUCCESS(status) && rb != nullptr) {
    463        int32_t len = 0;
    464        const int32_t * intVector = ures_getIntVector(rb.getAlias(),
    465                                                      &len, &status);
    466        if (U_SUCCESS(status) && intVector != nullptr && len >= 2) {
    467            fCapitalizationOfRelativeUnitsForUIListMenu = static_cast<UBool>(intVector[0]);
    468            fCapitalizationOfRelativeUnitsForStandAlone = static_cast<UBool>(intVector[1]);
    469        }
    470    }
    471 #endif
    472 }
    473 
    474 namespace {
    475 
    476 /**
    477 * Sink for getting data from fields/day/relative data.
    478 * For loading relative day names, e.g., "yesterday", "today".
    479 */
    480 
    481 struct RelDateFmtDataSink : public ResourceSink {
    482  URelativeString *fDatesPtr;
    483  int32_t fDatesLen;
    484 
    485  RelDateFmtDataSink(URelativeString* fDates, int32_t len) : fDatesPtr(fDates), fDatesLen(len) {
    486    for (int32_t i = 0; i < fDatesLen; ++i) {
    487      fDatesPtr[i].offset = 0;
    488      fDatesPtr[i].string = nullptr;
    489      fDatesPtr[i].len = -1;
    490    }
    491  }
    492 
    493  virtual ~RelDateFmtDataSink();
    494 
    495  virtual void put(const char *key, ResourceValue &value,
    496                   UBool /*noFallback*/, UErrorCode &errorCode) override {
    497      ResourceTable relDayTable = value.getTable(errorCode);
    498      int32_t n = 0;
    499      int32_t len = 0;
    500      for (int32_t i = 0; relDayTable.getKeyAndValue(i, key, value); ++i) {
    501        // Find the relative offset.
    502        int32_t offset = atoi(key);
    503 
    504        // Put in the proper spot, but don't override existing data.
    505        n = offset + UDAT_DIRECTION_THIS; // Converts to index in UDAT_R
    506        if (0 <= n && n < fDatesLen && fDatesPtr[n].string == nullptr) {
    507          // Not found and n is an empty slot.
    508          fDatesPtr[n].offset = offset;
    509          fDatesPtr[n].string = value.getString(len, errorCode);
    510          fDatesPtr[n].len = len;
    511        }
    512      }
    513  }
    514 };
    515 
    516 
    517 // Virtual destructors must be defined out of line.
    518 RelDateFmtDataSink::~RelDateFmtDataSink() {}
    519 
    520 }  // Namespace
    521 
    522 
    523 static const char16_t patItem1[] = {0x7B,0x31,0x7D}; // "{1}"
    524 static const int32_t patItem1Len = 3;
    525 
    526 void RelativeDateFormat::loadDates(UErrorCode &status) {
    527    UResourceBundle *rb = ures_open(nullptr, fLocale.getBaseName(), &status);
    528    LocalUResourceBundlePointer dateTimePatterns(
    529        ures_getByKeyWithFallback(rb,
    530                                  "calendar/gregorian/DateTimePatterns",
    531                                  (UResourceBundle*)nullptr, &status));
    532    if(U_SUCCESS(status)) {
    533        int32_t patternsSize = ures_getSize(dateTimePatterns.getAlias());
    534        if (patternsSize > kDateTime) {
    535            int32_t resStrLen = 0;
    536            int32_t glueIndex = kDateTime;
    537            if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
    538                int32_t offsetIncrement = (fDateStyle & ~kRelative); // Remove relative bit.
    539                if (offsetIncrement >= static_cast<int32_t>(kFull) &&
    540                    offsetIncrement <= static_cast<int32_t>(kShortRelative)) {
    541                    glueIndex = kDateTimeOffset + offsetIncrement;
    542                }
    543            }
    544 
    545            const char16_t *resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), glueIndex, &resStrLen, &status);
    546            if (U_SUCCESS(status) && resStrLen >= patItem1Len && u_strncmp(resStr,patItem1,patItem1Len)==0) {
    547                fCombinedHasDateAtStart = true;
    548            }
    549            fCombinedFormat = new SimpleFormatter(UnicodeString(true, resStr, resStrLen), 2, 2, status);
    550        }
    551    }
    552 
    553    // Data loading for relative names, e.g., "yesterday", "today", "tomorrow".
    554    fDatesLen = UDAT_DIRECTION_COUNT; // Maximum defined by data.
    555    fDates = static_cast<URelativeString*>(uprv_malloc(sizeof(fDates[0]) * fDatesLen));
    556 
    557    RelDateFmtDataSink sink(fDates, fDatesLen);
    558    ures_getAllItemsWithFallback(rb, "fields/day/relative", sink, status);
    559 
    560    ures_close(rb);
    561 
    562    if(U_FAILURE(status)) {
    563        fDatesLen=0;
    564        return;
    565    }
    566 }
    567 
    568 //----------------------------------------------------------------------
    569 
    570 // this should to be in DateFormat, instead it was copied from SimpleDateFormat.
    571 
    572 Calendar*
    573 RelativeDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)
    574 {
    575    if(!U_FAILURE(status)) {
    576        fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
    577    }
    578    if (U_SUCCESS(status) && fCalendar == nullptr) {
    579        status = U_MEMORY_ALLOCATION_ERROR;
    580    }
    581    return fCalendar;
    582 }
    583 
    584 int32_t RelativeDateFormat::dayDifference(Calendar &cal, UErrorCode &status) {
    585    if(U_FAILURE(status)) {
    586        return 0;
    587    }
    588    // TODO: Cache the nowCal to avoid heap allocs? Would be difficult, don't know the calendar type
    589    Calendar *nowCal = cal.clone();
    590    nowCal->setTime(Calendar::getNow(), status);
    591 
    592    // For the day difference, we are interested in the difference in the (modified) julian day number
    593    // which is midnight to midnight.  Using fieldDifference() is NOT correct here, because 
    594    // 6pm Jan 4th  to 10am Jan 5th should be considered "tomorrow".
    595    int32_t dayDiff = cal.get(UCAL_JULIAN_DAY, status) - nowCal->get(UCAL_JULIAN_DAY, status);
    596 
    597    delete nowCal;
    598    return dayDiff;
    599 }
    600 
    601 U_NAMESPACE_END
    602 
    603 #endif  /* !UCONFIG_NO_FORMATTING */