LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - reldtfmt.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 260 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RelativeDateFormat)
      41             : 
      42           0 : RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) :
      43             :  DateFormat(other), fDateTimeFormatter(NULL), fDatePattern(other.fDatePattern),
      44             :  fTimePattern(other.fTimePattern), fCombinedFormat(NULL),
      45           0 :  fDateStyle(other.fDateStyle), fLocale(other.fLocale),
      46           0 :  fDatesLen(other.fDatesLen), fDates(NULL),
      47           0 :  fCombinedHasDateAtStart(other.fCombinedHasDateAtStart),
      48           0 :  fCapitalizationInfoSet(other.fCapitalizationInfoSet),
      49           0 :  fCapitalizationOfRelativeUnitsForUIListMenu(other.fCapitalizationOfRelativeUnitsForUIListMenu),
      50           0 :  fCapitalizationOfRelativeUnitsForStandAlone(other.fCapitalizationOfRelativeUnitsForStandAlone),
      51           0 :  fCapitalizationBrkIter(NULL)
      52             : {
      53           0 :     if(other.fDateTimeFormatter != NULL) {
      54           0 :         fDateTimeFormatter = (SimpleDateFormat*)other.fDateTimeFormatter->clone();
      55             :     }
      56           0 :     if(other.fCombinedFormat != NULL) {
      57           0 :         fCombinedFormat = new SimpleFormatter(*other.fCombinedFormat);
      58             :     }
      59           0 :     if (fDatesLen > 0) {
      60           0 :         fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*(size_t)fDatesLen);
      61           0 :         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           0 : }
      69             : 
      70           0 : RelativeDateFormat::RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle,
      71           0 :                                         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           0 :  fCapitalizationBrkIter(NULL)
      77             : {
      78           0 :     if(U_FAILURE(status) ) {
      79           0 :         return;
      80             :     }
      81             : 
      82           0 :     if (timeStyle < UDAT_NONE || timeStyle > UDAT_SHORT) {
      83             :         // don't support other time styles (e.g. relative styles), for now
      84           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
      85           0 :         return;
      86             :     }
      87           0 :     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           0 :     if (baseDateStyle != UDAT_NONE) {
      92           0 :         df = createDateInstance((EStyle)baseDateStyle, locale);
      93           0 :         fDateTimeFormatter=dynamic_cast<SimpleDateFormat *>(df);
      94           0 :         if (fDateTimeFormatter == NULL) {
      95           0 :             status = U_UNSUPPORTED_ERROR;
      96           0 :              return;
      97             :         }
      98           0 :         fDateTimeFormatter->toPattern(fDatePattern);
      99           0 :         if (timeStyle != UDAT_NONE) {
     100           0 :             df = createTimeInstance((EStyle)timeStyle, locale);
     101           0 :             SimpleDateFormat *sdf = dynamic_cast<SimpleDateFormat *>(df);
     102           0 :             if (sdf != NULL) {
     103           0 :                 sdf->toPattern(fTimePattern);
     104           0 :                 delete sdf;
     105             :             }
     106             :         }
     107             :     } else {
     108             :         // does not matter whether timeStyle is UDAT_NONE, we need something for fDateTimeFormatter
     109           0 :         df = createTimeInstance((EStyle)timeStyle, locale);
     110           0 :         fDateTimeFormatter=dynamic_cast<SimpleDateFormat *>(df);
     111           0 :         if (fDateTimeFormatter == NULL) {
     112           0 :             status = U_UNSUPPORTED_ERROR;
     113           0 :             delete df;
     114           0 :             return;
     115             :         }
     116           0 :         fDateTimeFormatter->toPattern(fTimePattern);
     117             :     }
     118             : 
     119             :     // Initialize the parent fCalendar, so that parse() works correctly.
     120           0 :     initializeCalendar(NULL, locale, status);
     121           0 :     loadDates(status);
     122             : }
     123             : 
     124           0 : RelativeDateFormat::~RelativeDateFormat() {
     125           0 :     delete fDateTimeFormatter;
     126           0 :     delete fCombinedFormat;
     127           0 :     uprv_free(fDates);
     128             : #if !UCONFIG_NO_BREAK_ITERATION
     129             :     delete fCapitalizationBrkIter;
     130             : #endif
     131           0 : }
     132             : 
     133             : 
     134           0 : Format* RelativeDateFormat::clone(void) const {
     135           0 :     return new RelativeDateFormat(*this);
     136             : }
     137             : 
     138           0 : UBool RelativeDateFormat::operator==(const Format& other) const {
     139           0 :     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           0 :         RelativeDateFormat* that = (RelativeDateFormat*)&other;
     144           0 :         return (fDateStyle==that->fDateStyle   &&
     145           0 :                 fDatePattern==that->fDatePattern   &&
     146           0 :                 fTimePattern==that->fTimePattern   &&
     147           0 :                 fLocale==that->fLocale );
     148             :     }
     149           0 :     return FALSE;
     150             : }
     151             : 
     152             : static const UChar APOSTROPHE = (UChar)0x0027;
     153             : 
     154           0 : UnicodeString& RelativeDateFormat::format(  Calendar& cal,
     155             :                                 UnicodeString& appendTo,
     156             :                                 FieldPosition& pos) const {
     157             :                                 
     158           0 :     UErrorCode status = U_ZERO_ERROR;
     159           0 :     UnicodeString relativeDayString;
     160           0 :     UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
     161             :     
     162             :     // calculate the difference, in days, between 'cal' and now.
     163           0 :     int dayDiff = dayDifference(cal, status);
     164             : 
     165             :     // look up string
     166           0 :     int32_t len = 0;
     167           0 :     const UChar *theString = getStringForDay(dayDiff, len, status);
     168           0 :     if(U_SUCCESS(status) && (theString!=NULL)) {
     169             :         // found a relative string
     170           0 :         relativeDayString.setTo(theString, len);
     171             :     }
     172             : 
     173           0 :     if ( relativeDayString.length() > 0 && !fDatePattern.isEmpty() && 
     174           0 :          (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           0 :         fDateTimeFormatter->setContext(UDISPCTX_CAPITALIZATION_NONE, status);
     186             :     } else {
     187             :         // set our context for the formatter
     188           0 :         fDateTimeFormatter->setContext(capitalizationContext, status);
     189             :     }
     190             : 
     191           0 :     if (fDatePattern.isEmpty()) {
     192           0 :         fDateTimeFormatter->applyPattern(fTimePattern);
     193           0 :         fDateTimeFormatter->format(cal,appendTo,pos);
     194           0 :     } else if (fTimePattern.isEmpty() || fCombinedFormat == NULL) {
     195           0 :         if (relativeDayString.length() > 0) {
     196           0 :             appendTo.append(relativeDayString);
     197             :         } else {
     198           0 :             fDateTimeFormatter->applyPattern(fDatePattern);
     199           0 :             fDateTimeFormatter->format(cal,appendTo,pos);
     200             :         }
     201             :     } else {
     202           0 :         UnicodeString datePattern;
     203           0 :         if (relativeDayString.length() > 0) {
     204             :             // Need to quote the relativeDayString to make it a legal date pattern
     205           0 :             relativeDayString.findAndReplace(UNICODE_STRING("'", 1), UNICODE_STRING("''", 2)); // double any existing APOSTROPHE
     206           0 :             relativeDayString.insert(0, APOSTROPHE); // add APOSTROPHE at beginning...
     207           0 :             relativeDayString.append(APOSTROPHE); // and at end
     208           0 :             datePattern.setTo(relativeDayString);
     209             :         } else {
     210           0 :             datePattern.setTo(fDatePattern);
     211             :         }
     212           0 :         UnicodeString combinedPattern;
     213           0 :         fCombinedFormat->format(fTimePattern, datePattern, combinedPattern, status);
     214           0 :         fDateTimeFormatter->applyPattern(combinedPattern);
     215           0 :         fDateTimeFormatter->format(cal,appendTo,pos);
     216             :     }
     217             : 
     218           0 :     return appendTo;
     219             : }
     220             : 
     221             : 
     222             : 
     223             : UnicodeString&
     224           0 : 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           0 :     return DateFormat::format(obj, appendTo, pos, status);
     234             : }
     235             : 
     236             : 
     237           0 : void RelativeDateFormat::parse( const UnicodeString& text,
     238             :                     Calendar& cal,
     239             :                     ParsePosition& pos) const {
     240             : 
     241           0 :     int32_t startIndex = pos.getIndex();
     242           0 :     if (fDatePattern.isEmpty()) {
     243             :         // no date pattern, try parsing as time
     244           0 :         fDateTimeFormatter->applyPattern(fTimePattern);
     245           0 :         fDateTimeFormatter->parse(text,cal,pos);
     246           0 :     } 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           0 :         UBool matchedRelative = FALSE;
     250           0 :         for (int n=0; n < fDatesLen && !matchedRelative; n++) {
     251           0 :             if (fDates[n].string != NULL &&
     252           0 :                     text.compare(startIndex, fDates[n].len, fDates[n].string) == 0) {
     253             :                 // it matched, handle the relative day string
     254           0 :                 UErrorCode status = U_ZERO_ERROR;
     255           0 :                 matchedRelative = TRUE;
     256             : 
     257             :                 // Set the calendar to now+offset
     258           0 :                 cal.setTime(Calendar::getNow(),status);
     259           0 :                 cal.add(UCAL_DATE,fDates[n].offset, status);
     260             : 
     261           0 :                 if(U_FAILURE(status)) { 
     262             :                     // failure in setting calendar field, set offset to beginning of rel day string
     263           0 :                     pos.setErrorIndex(startIndex);
     264             :                 } else {
     265           0 :                     pos.setIndex(startIndex + fDates[n].len);
     266             :                 }
     267             :             }
     268             :         }
     269           0 :         if (!matchedRelative) {
     270             :             // just parse as normal date
     271           0 :             fDateTimeFormatter->applyPattern(fDatePattern);
     272           0 :             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           0 :         UnicodeString modifiedText(text);
     278           0 :         FieldPosition fPos;
     279           0 :         int32_t dateStart = 0, origDateLen = 0, modDateLen = 0;
     280           0 :         UErrorCode status = U_ZERO_ERROR;
     281           0 :         for (int n=0; n < fDatesLen; n++) {
     282             :             int32_t relativeStringOffset;
     283           0 :             if (fDates[n].string != NULL &&
     284           0 :                     (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           0 :                 UnicodeString dateString;
     287           0 :                 Calendar * tempCal = cal.clone();
     288             : 
     289             :                 // Set the calendar to now+offset
     290           0 :                 tempCal->setTime(Calendar::getNow(),status);
     291           0 :                 tempCal->add(UCAL_DATE,fDates[n].offset, status);
     292           0 :                 if(U_FAILURE(status)) { 
     293           0 :                     pos.setErrorIndex(startIndex);
     294           0 :                     delete tempCal;
     295           0 :                     return;
     296             :                 }
     297             : 
     298           0 :                 fDateTimeFormatter->applyPattern(fDatePattern);
     299           0 :                 fDateTimeFormatter->format(*tempCal, dateString, fPos);
     300           0 :                 dateStart = relativeStringOffset;
     301           0 :                 origDateLen = fDates[n].len;
     302           0 :                 modDateLen = dateString.length();
     303           0 :                 modifiedText.replace(dateStart, origDateLen, dateString);
     304           0 :                 delete tempCal;
     305           0 :                 break;
     306             :             }
     307             :         }
     308           0 :         UnicodeString combinedPattern;
     309           0 :         fCombinedFormat->format(fTimePattern, fDatePattern, combinedPattern, status);
     310           0 :         fDateTimeFormatter->applyPattern(combinedPattern);
     311           0 :         fDateTimeFormatter->parse(modifiedText,cal,pos);
     312             : 
     313             :         // Adjust offsets
     314           0 :         UBool noError = (pos.getErrorIndex() < 0);
     315           0 :         int32_t offset = (noError)? pos.getIndex(): pos.getErrorIndex();
     316           0 :         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           0 :             offset -= (modDateLen - origDateLen);
     320           0 :         } 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           0 :             offset = dateStart;
     324             :         }
     325           0 :         if (noError) {
     326           0 :             pos.setIndex(offset);
     327             :         } else {
     328           0 :             pos.setErrorIndex(offset);
     329             :         }
     330             :     }
     331             : }
     332             : 
     333             : UDate
     334           0 : 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           0 :     return DateFormat::parse(text, pos);
     339             : }
     340             : 
     341             : UDate
     342           0 : 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           0 :     return DateFormat::parse(text, status);
     347             : }
     348             : 
     349             : 
     350           0 : const UChar *RelativeDateFormat::getStringForDay(int32_t day, int32_t &len, UErrorCode &status) const {
     351           0 :     if(U_FAILURE(status)) {
     352           0 :         return NULL;
     353             :     }
     354             : 
     355             :     // Is it inside the resource bundle's range?
     356           0 :     int n = day + UDAT_DIRECTION_THIS;
     357           0 :     if (n >= 0 && n < fDatesLen) {
     358           0 :         if (fDates[n].offset == day && fDates[n].string != NULL) {
     359           0 :             len = fDates[n].len;
     360           0 :             return fDates[n].string;
     361             :         }
     362             :     }
     363           0 :     return NULL;  // not found.
     364             : }
     365             : 
     366             : UnicodeString&
     367           0 : RelativeDateFormat::toPattern(UnicodeString& result, UErrorCode& status) const
     368             : {
     369           0 :     if (!U_FAILURE(status)) {
     370           0 :         result.remove();
     371           0 :         if (fDatePattern.isEmpty()) {
     372           0 :             result.setTo(fTimePattern);
     373           0 :         } else if (fTimePattern.isEmpty() || fCombinedFormat == NULL) {
     374           0 :             result.setTo(fDatePattern);
     375             :         } else {
     376           0 :             fCombinedFormat->format(fTimePattern, fDatePattern, result, status);
     377             :         }
     378             :     }
     379           0 :     return result;
     380             : }
     381             : 
     382             : UnicodeString&
     383           0 : RelativeDateFormat::toPatternDate(UnicodeString& result, UErrorCode& status) const
     384             : {
     385           0 :     if (!U_FAILURE(status)) {
     386           0 :         result.remove();
     387           0 :         result.setTo(fDatePattern);
     388             :     }
     389           0 :     return result;
     390             : }
     391             : 
     392             : UnicodeString&
     393           0 : RelativeDateFormat::toPatternTime(UnicodeString& result, UErrorCode& status) const
     394             : {
     395           0 :     if (!U_FAILURE(status)) {
     396           0 :         result.remove();
     397           0 :         result.setTo(fTimePattern);
     398             :     }
     399           0 :     return result;
     400             : }
     401             : 
     402             : void
     403           0 : RelativeDateFormat::applyPatterns(const UnicodeString& datePattern, const UnicodeString& timePattern, UErrorCode &status)
     404             : {
     405           0 :     if (!U_FAILURE(status)) {
     406           0 :         fDatePattern.setTo(datePattern);
     407           0 :         fTimePattern.setTo(timePattern);
     408             :     }
     409           0 : }
     410             : 
     411             : const DateFormatSymbols*
     412           0 : RelativeDateFormat::getDateFormatSymbols() const
     413             : {
     414           0 :     return fDateTimeFormatter->getDateFormatSymbols();
     415             : }
     416             : 
     417             : // override the DateFormat implementation in order to
     418             : // lazily initialize relevant items
     419             : void
     420           0 : RelativeDateFormat::setContext(UDisplayContext value, UErrorCode& status)
     421             : {
     422           0 :     DateFormat::setContext(value, status);
     423           0 :     if (U_SUCCESS(status)) {
     424           0 :         if (!fCapitalizationInfoSet &&
     425           0 :                 (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE)) {
     426           0 :             initCapitalizationContextInfo(fLocale);
     427           0 :             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             :             UErrorCode 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           0 : }
     443             : 
     444             : void
     445           0 : 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 = intVector[0];
     460             :             fCapitalizationOfRelativeUnitsForStandAlone = intVector[1];
     461             :         }
     462             :     }
     463             : #endif
     464           0 : }
     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           0 :   RelDateFmtDataSink(URelativeString* fDates, int32_t len) : fDatesPtr(fDates), fDatesLen(len) {
     478           0 :     for (int32_t i = 0; i < fDatesLen; ++i) {
     479           0 :       fDatesPtr[i].offset = 0;
     480           0 :       fDatesPtr[i].string = NULL;
     481           0 :       fDatesPtr[i].len = -1;
     482             :     }
     483           0 :   }
     484             : 
     485             :   virtual ~RelDateFmtDataSink();
     486             : 
     487           0 :   virtual void put(const char *key, ResourceValue &value,
     488             :                    UBool /*noFallback*/, UErrorCode &errorCode) {
     489           0 :       ResourceTable relDayTable = value.getTable(errorCode);
     490           0 :       int32_t n = 0;
     491           0 :       int32_t len = 0;
     492           0 :       for (int32_t i = 0; relDayTable.getKeyAndValue(i, key, value); ++i) {
     493             :         // Find the relative offset.
     494           0 :         int32_t offset = atoi(key);
     495             : 
     496             :         // Put in the proper spot, but don't override existing data.
     497           0 :         n = offset + UDAT_DIRECTION_THIS; // Converts to index in UDAT_R
     498           0 :         if (n < fDatesLen && fDatesPtr[n].string == NULL) {
     499             :           // Not found and n is an empty slot.
     500           0 :           fDatesPtr[n].offset = offset;
     501           0 :           fDatesPtr[n].string = value.getString(len, errorCode);
     502           0 :           fDatesPtr[n].len = len;
     503             :         }
     504             :       }
     505           0 :   }
     506             : };
     507             : 
     508             : 
     509             : // Virtual destructors must be defined out of line.
     510           0 : 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           0 : void RelativeDateFormat::loadDates(UErrorCode &status) {
     519           0 :     UResourceBundle *rb = ures_open(NULL, fLocale.getBaseName(), &status);
     520             :     LocalUResourceBundlePointer dateTimePatterns(
     521             :         ures_getByKeyWithFallback(rb,
     522             :                                   "calendar/gregorian/DateTimePatterns",
     523           0 :                                   (UResourceBundle*)NULL, &status));
     524           0 :     if(U_SUCCESS(status)) {
     525           0 :         int32_t patternsSize = ures_getSize(dateTimePatterns.getAlias());
     526           0 :         if (patternsSize > kDateTime) {
     527           0 :             int32_t resStrLen = 0;
     528           0 :             int32_t glueIndex = kDateTime;
     529           0 :             if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
     530           0 :                 int32_t offsetIncrement = (fDateStyle & ~kRelative); // Remove relative bit.
     531           0 :                 if (offsetIncrement >= (int32_t)kFull &&
     532             :                     offsetIncrement <= (int32_t)kShortRelative) {
     533           0 :                     glueIndex = kDateTimeOffset + offsetIncrement;
     534             :                 }
     535             :             }
     536             : 
     537           0 :             const UChar *resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), glueIndex, &resStrLen, &status);
     538           0 :             if (U_SUCCESS(status) && resStrLen >= patItem1Len && u_strncmp(resStr,patItem1,patItem1Len)==0) {
     539           0 :                 fCombinedHasDateAtStart = TRUE;
     540             :             }
     541           0 :             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           0 :     fDatesLen = UDAT_DIRECTION_COUNT; // Maximum defined by data.
     547           0 :     fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen);
     548             : 
     549           0 :     RelDateFmtDataSink sink(fDates, fDatesLen);
     550           0 :     ures_getAllItemsWithFallback(rb, "fields/day/relative", sink, status);
     551             : 
     552           0 :     ures_close(rb);
     553             : 
     554           0 :     if(U_FAILURE(status)) {
     555           0 :         fDatesLen=0;
     556           0 :         return;
     557             :     }
     558             : }
     559             : 
     560             : //----------------------------------------------------------------------
     561             : 
     562             : // this should to be in DateFormat, instead it was copied from SimpleDateFormat.
     563             : 
     564             : Calendar*
     565           0 : RelativeDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)
     566             : {
     567           0 :     if(!U_FAILURE(status)) {
     568           0 :         fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
     569             :     }
     570           0 :     if (U_SUCCESS(status) && fCalendar == NULL) {
     571           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     572             :     }
     573           0 :     return fCalendar;
     574             : }
     575             : 
     576           0 : int32_t RelativeDateFormat::dayDifference(Calendar &cal, UErrorCode &status) {
     577           0 :     if(U_FAILURE(status)) {
     578           0 :         return 0;
     579             :     }
     580             :     // TODO: Cache the nowCal to avoid heap allocs? Would be difficult, don't know the calendar type
     581           0 :     Calendar *nowCal = cal.clone();
     582           0 :     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           0 :     int32_t dayDiff = cal.get(UCAL_JULIAN_DAY, status) - nowCal->get(UCAL_JULIAN_DAY, status);
     588             : 
     589           0 :     delete nowCal;
     590           0 :     return dayDiff;
     591             : }
     592             : 
     593             : U_NAMESPACE_END
     594             : 
     595             : #endif  /* !UCONFIG_NO_FORMATTING */

Generated by: LCOV version 1.13