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