LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - dtitvfmt.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 648 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 40 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             : * Copyright (C) 2008-2016, International Business Machines Corporation and
       5             : * others. All Rights Reserved.
       6             : *******************************************************************************
       7             : *
       8             : * File DTITVFMT.CPP
       9             : *
      10             : *******************************************************************************
      11             : */
      12             : 
      13             : #include "utypeinfo.h"  // for 'typeid' to work
      14             : 
      15             : #include "unicode/dtitvfmt.h"
      16             : 
      17             : #if !UCONFIG_NO_FORMATTING
      18             : 
      19             : //TODO: put in compilation
      20             : //#define DTITVFMT_DEBUG 1
      21             : 
      22             : #include "unicode/calendar.h"
      23             : #include "unicode/dtptngen.h"
      24             : #include "unicode/dtitvinf.h"
      25             : #include "unicode/simpleformatter.h"
      26             : #include "cmemory.h"
      27             : #include "cstring.h"
      28             : #include "dtitv_impl.h"
      29             : #include "mutex.h"
      30             : #include "uresimp.h"
      31             : 
      32             : #ifdef DTITVFMT_DEBUG
      33             : #include <iostream>
      34             : #endif
      35             : 
      36             : U_NAMESPACE_BEGIN
      37             : 
      38             : 
      39             : 
      40             : #ifdef DTITVFMT_DEBUG
      41             : #define PRINTMESG(msg) { std::cout << "(" << __FILE__ << ":" << __LINE__ << ") " << msg << "\n"; }
      42             : #endif
      43             : 
      44             : 
      45             : static const UChar gDateFormatSkeleton[][11] = {
      46             : //yMMMMEEEEd
      47             : {LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, CAP_E, CAP_E, CAP_E, CAP_E, LOW_D, 0},
      48             : //yMMMMd
      49             : {LOW_Y, CAP_M, CAP_M, CAP_M, CAP_M, LOW_D, 0},
      50             : //yMMMd
      51             : {LOW_Y, CAP_M, CAP_M, CAP_M, LOW_D, 0},
      52             : //yMd
      53             : {LOW_Y, CAP_M, LOW_D, 0} };
      54             : 
      55             : 
      56             : static const char gCalendarTag[] = "calendar";
      57             : static const char gGregorianTag[] = "gregorian";
      58             : static const char gDateTimePatternsTag[] = "DateTimePatterns";
      59             : 
      60             : 
      61             : // latestFirst:
      62             : static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
      63             : 
      64             : // earliestFirst:
      65             : static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON};
      66             : 
      67             : 
      68           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat)
      69             : 
      70             : // Mutex, protects access to fDateFormat, fFromCalendar and fToCalendar.
      71             : //        Needed because these data members are modified by const methods of DateIntervalFormat.
      72             : 
      73             : static UMutex gFormatterMutex = U_MUTEX_INITIALIZER;
      74             : 
      75             : DateIntervalFormat* U_EXPORT2
      76           0 : DateIntervalFormat::createInstance(const UnicodeString& skeleton,
      77             :                                    UErrorCode& status) {
      78           0 :     return createInstance(skeleton, Locale::getDefault(), status);
      79             : }
      80             : 
      81             : 
      82             : DateIntervalFormat* U_EXPORT2
      83           0 : DateIntervalFormat::createInstance(const UnicodeString& skeleton,
      84             :                                    const Locale& locale,
      85             :                                    UErrorCode& status) {
      86             : #ifdef DTITVFMT_DEBUG
      87             :     char result[1000];
      88             :     char result_1[1000];
      89             :     char mesg[2000];
      90             :     skeleton.extract(0,  skeleton.length(), result, "UTF-8");
      91             :     UnicodeString pat;
      92             :     ((SimpleDateFormat*)dtfmt)->toPattern(pat);
      93             :     pat.extract(0,  pat.length(), result_1, "UTF-8");
      94             :     sprintf(mesg, "skeleton: %s; pattern: %s\n", result, result_1);
      95             :     PRINTMESG(mesg)
      96             : #endif
      97             : 
      98           0 :     DateIntervalInfo* dtitvinf = new DateIntervalInfo(locale, status);
      99           0 :     return create(locale, dtitvinf, &skeleton, status);
     100             : }
     101             : 
     102             : 
     103             : 
     104             : DateIntervalFormat* U_EXPORT2
     105           0 : DateIntervalFormat::createInstance(const UnicodeString& skeleton,
     106             :                                    const DateIntervalInfo& dtitvinf,
     107             :                                    UErrorCode& status) {
     108           0 :     return createInstance(skeleton, Locale::getDefault(), dtitvinf, status);
     109             : }
     110             : 
     111             : 
     112             : DateIntervalFormat* U_EXPORT2
     113           0 : DateIntervalFormat::createInstance(const UnicodeString& skeleton,
     114             :                                    const Locale& locale,
     115             :                                    const DateIntervalInfo& dtitvinf,
     116             :                                    UErrorCode& status) {
     117           0 :     DateIntervalInfo* ptn = dtitvinf.clone();
     118           0 :     return create(locale, ptn, &skeleton, status);
     119             : }
     120             : 
     121             : 
     122           0 : DateIntervalFormat::DateIntervalFormat()
     123             : :   fInfo(NULL),
     124             :     fDateFormat(NULL),
     125             :     fFromCalendar(NULL),
     126             :     fToCalendar(NULL),
     127             :     fLocale(Locale::getRoot()),
     128             :     fDatePattern(NULL),
     129             :     fTimePattern(NULL),
     130           0 :     fDateTimeFormat(NULL)
     131           0 : {}
     132             : 
     133             : 
     134           0 : DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt)
     135             : :   Format(itvfmt),
     136             :     fInfo(NULL),
     137             :     fDateFormat(NULL),
     138             :     fFromCalendar(NULL),
     139             :     fToCalendar(NULL),
     140             :     fLocale(itvfmt.fLocale),
     141             :     fDatePattern(NULL),
     142             :     fTimePattern(NULL),
     143           0 :     fDateTimeFormat(NULL) {
     144           0 :     *this = itvfmt;
     145           0 : }
     146             : 
     147             : 
     148             : DateIntervalFormat&
     149           0 : DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) {
     150           0 :     if ( this != &itvfmt ) {
     151           0 :         delete fDateFormat;
     152           0 :         delete fInfo;
     153           0 :         delete fFromCalendar;
     154           0 :         delete fToCalendar;
     155           0 :         delete fDatePattern;
     156           0 :         delete fTimePattern;
     157           0 :         delete fDateTimeFormat;
     158             :         {
     159           0 :             Mutex lock(&gFormatterMutex);
     160           0 :             if ( itvfmt.fDateFormat ) {
     161           0 :                 fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
     162             :             } else {
     163           0 :                 fDateFormat = NULL;
     164             :             }
     165           0 :             if ( itvfmt.fFromCalendar ) {
     166           0 :                 fFromCalendar = itvfmt.fFromCalendar->clone();
     167             :             } else {
     168           0 :                 fFromCalendar = NULL;
     169             :             }
     170           0 :             if ( itvfmt.fToCalendar ) {
     171           0 :                 fToCalendar = itvfmt.fToCalendar->clone();
     172             :             } else {
     173           0 :                 fToCalendar = NULL;
     174             :             }
     175             :         }
     176           0 :         if ( itvfmt.fInfo ) {
     177           0 :             fInfo = itvfmt.fInfo->clone();
     178             :         } else {
     179           0 :             fInfo = NULL;
     180             :         }
     181           0 :         fSkeleton = itvfmt.fSkeleton;
     182             :         int8_t i;
     183           0 :         for ( i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
     184           0 :             fIntervalPatterns[i] = itvfmt.fIntervalPatterns[i];
     185             :         }
     186           0 :         fLocale = itvfmt.fLocale;
     187           0 :         fDatePattern    = (itvfmt.fDatePattern)?    (UnicodeString*)itvfmt.fDatePattern->clone(): NULL;
     188           0 :         fTimePattern    = (itvfmt.fTimePattern)?    (UnicodeString*)itvfmt.fTimePattern->clone(): NULL;
     189           0 :         fDateTimeFormat = (itvfmt.fDateTimeFormat)? (UnicodeString*)itvfmt.fDateTimeFormat->clone(): NULL;
     190             :     }
     191           0 :     return *this;
     192             : }
     193             : 
     194             : 
     195           0 : DateIntervalFormat::~DateIntervalFormat() {
     196           0 :     delete fInfo;
     197           0 :     delete fDateFormat;
     198           0 :     delete fFromCalendar;
     199           0 :     delete fToCalendar;
     200           0 :     delete fDatePattern;
     201           0 :     delete fTimePattern;
     202           0 :     delete fDateTimeFormat;
     203           0 : }
     204             : 
     205             : 
     206             : Format*
     207           0 : DateIntervalFormat::clone(void) const {
     208           0 :     return new DateIntervalFormat(*this);
     209             : }
     210             : 
     211             : 
     212             : UBool
     213           0 : DateIntervalFormat::operator==(const Format& other) const {
     214           0 :     if (typeid(*this) != typeid(other)) {return FALSE;}
     215           0 :     const DateIntervalFormat* fmt = (DateIntervalFormat*)&other;
     216           0 :     if (this == fmt) {return TRUE;}
     217           0 :     if (!Format::operator==(other)) {return FALSE;}
     218           0 :     if ((fInfo != fmt->fInfo) && (fInfo == NULL || fmt->fInfo == NULL)) {return FALSE;}
     219           0 :     if (fInfo && fmt->fInfo && (*fInfo != *fmt->fInfo )) {return FALSE;}
     220             :     {
     221           0 :         Mutex lock(&gFormatterMutex);
     222           0 :         if (fDateFormat != fmt->fDateFormat && (fDateFormat == NULL || fmt->fDateFormat == NULL)) {return FALSE;}
     223           0 :         if (fDateFormat && fmt->fDateFormat && (*fDateFormat != *fmt->fDateFormat)) {return FALSE;}
     224             :     }
     225             :     // note: fFromCalendar and fToCalendar hold no persistent state, and therefore do not participate in operator ==.
     226             :     //       fDateFormat has the master calendar for the DateIntervalFormat.
     227           0 :     if (fSkeleton != fmt->fSkeleton) {return FALSE;}
     228           0 :     if (fDatePattern != fmt->fDatePattern && (fDatePattern == NULL || fmt->fDatePattern == NULL)) {return FALSE;}
     229           0 :     if (fDatePattern && fmt->fDatePattern && (*fDatePattern != *fmt->fDatePattern)) {return FALSE;}
     230           0 :     if (fTimePattern != fmt->fTimePattern && (fTimePattern == NULL || fmt->fTimePattern == NULL)) {return FALSE;}
     231           0 :     if (fTimePattern && fmt->fTimePattern && (*fTimePattern != *fmt->fTimePattern)) {return FALSE;}
     232           0 :     if (fDateTimeFormat != fmt->fDateTimeFormat && (fDateTimeFormat == NULL || fmt->fDateTimeFormat == NULL)) {return FALSE;}
     233           0 :     if (fDateTimeFormat && fmt->fDateTimeFormat && (*fDateTimeFormat != *fmt->fDateTimeFormat)) {return FALSE;}
     234           0 :     if (fLocale != fmt->fLocale) {return FALSE;}
     235             : 
     236           0 :     for (int32_t i = 0; i< DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
     237           0 :         if (fIntervalPatterns[i].firstPart != fmt->fIntervalPatterns[i].firstPart) {return FALSE;}
     238           0 :         if (fIntervalPatterns[i].secondPart != fmt->fIntervalPatterns[i].secondPart ) {return FALSE;}
     239           0 :         if (fIntervalPatterns[i].laterDateFirst != fmt->fIntervalPatterns[i].laterDateFirst) {return FALSE;}
     240             :     }
     241           0 :     return TRUE;
     242             : }
     243             : 
     244             : 
     245             : UnicodeString&
     246           0 : DateIntervalFormat::format(const Formattable& obj,
     247             :                            UnicodeString& appendTo,
     248             :                            FieldPosition& fieldPosition,
     249             :                            UErrorCode& status) const {
     250           0 :     if ( U_FAILURE(status) ) {
     251           0 :         return appendTo;
     252             :     }
     253             : 
     254           0 :     if ( obj.getType() == Formattable::kObject ) {
     255           0 :         const UObject* formatObj = obj.getObject();
     256           0 :         const DateInterval* interval = dynamic_cast<const DateInterval*>(formatObj);
     257           0 :         if (interval != NULL) {
     258           0 :             return format(interval, appendTo, fieldPosition, status);
     259             :         }
     260             :     }
     261           0 :     status = U_ILLEGAL_ARGUMENT_ERROR;
     262           0 :     return appendTo;
     263             : }
     264             : 
     265             : 
     266             : UnicodeString&
     267           0 : DateIntervalFormat::format(const DateInterval* dtInterval,
     268             :                            UnicodeString& appendTo,
     269             :                            FieldPosition& fieldPosition,
     270             :                            UErrorCode& status) const {
     271           0 :     if ( U_FAILURE(status) ) {
     272           0 :         return appendTo;
     273             :     }
     274           0 :     if (fFromCalendar == NULL || fToCalendar == NULL || fDateFormat == NULL || fInfo == NULL) {
     275           0 :         status = U_INVALID_STATE_ERROR;
     276           0 :         return appendTo;
     277             :     }
     278             : 
     279           0 :     Mutex lock(&gFormatterMutex);
     280           0 :     fFromCalendar->setTime(dtInterval->getFromDate(), status);
     281           0 :     fToCalendar->setTime(dtInterval->getToDate(), status);
     282           0 :     return formatImpl(*fFromCalendar, *fToCalendar, appendTo,fieldPosition, status);
     283             : }
     284             : 
     285             : 
     286             : UnicodeString&
     287           0 : DateIntervalFormat::format(Calendar& fromCalendar,
     288             :                            Calendar& toCalendar,
     289             :                            UnicodeString& appendTo,
     290             :                            FieldPosition& pos,
     291             :                            UErrorCode& status) const {
     292           0 :     Mutex lock(&gFormatterMutex);
     293           0 :     return formatImpl(fromCalendar, toCalendar, appendTo, pos, status);
     294             : }
     295             : 
     296             : 
     297             : UnicodeString&
     298           0 : DateIntervalFormat::formatImpl(Calendar& fromCalendar,
     299             :                            Calendar& toCalendar,
     300             :                            UnicodeString& appendTo,
     301             :                            FieldPosition& pos,
     302             :                            UErrorCode& status) const {
     303           0 :     if ( U_FAILURE(status) ) {
     304           0 :         return appendTo;
     305             :     }
     306             : 
     307             :     // not support different calendar types and time zones
     308             :     //if ( fromCalendar.getType() != toCalendar.getType() ) {
     309           0 :     if ( !fromCalendar.isEquivalentTo(toCalendar) ) {
     310           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
     311           0 :         return appendTo;
     312             :     }
     313             : 
     314             :     // First, find the largest different calendar field.
     315           0 :     UCalendarDateFields field = UCAL_FIELD_COUNT;
     316             : 
     317           0 :     if ( fromCalendar.get(UCAL_ERA,status) != toCalendar.get(UCAL_ERA,status)) {
     318           0 :         field = UCAL_ERA;
     319           0 :     } else if ( fromCalendar.get(UCAL_YEAR, status) !=
     320           0 :                 toCalendar.get(UCAL_YEAR, status) ) {
     321           0 :         field = UCAL_YEAR;
     322           0 :     } else if ( fromCalendar.get(UCAL_MONTH, status) !=
     323           0 :                 toCalendar.get(UCAL_MONTH, status) ) {
     324           0 :         field = UCAL_MONTH;
     325           0 :     } else if ( fromCalendar.get(UCAL_DATE, status) !=
     326           0 :                 toCalendar.get(UCAL_DATE, status) ) {
     327           0 :         field = UCAL_DATE;
     328           0 :     } else if ( fromCalendar.get(UCAL_AM_PM, status) !=
     329           0 :                 toCalendar.get(UCAL_AM_PM, status) ) {
     330           0 :         field = UCAL_AM_PM;
     331           0 :     } else if ( fromCalendar.get(UCAL_HOUR, status) !=
     332           0 :                 toCalendar.get(UCAL_HOUR, status) ) {
     333           0 :         field = UCAL_HOUR;
     334           0 :     } else if ( fromCalendar.get(UCAL_MINUTE, status) !=
     335           0 :                 toCalendar.get(UCAL_MINUTE, status) ) {
     336           0 :         field = UCAL_MINUTE;
     337           0 :     } else if ( fromCalendar.get(UCAL_SECOND, status) !=
     338           0 :                 toCalendar.get(UCAL_SECOND, status) ) {
     339           0 :         field = UCAL_SECOND;
     340             :     }
     341             : 
     342           0 :     if ( U_FAILURE(status) ) {
     343           0 :         return appendTo;
     344             :     }
     345           0 :     if ( field == UCAL_FIELD_COUNT ) {
     346             :         /* ignore the millisecond etc. small fields' difference.
     347             :          * use single date when all the above are the same.
     348             :          */
     349           0 :         return fDateFormat->format(fromCalendar, appendTo, pos);
     350             :     }
     351           0 :     UBool fromToOnSameDay = (field==UCAL_AM_PM || field==UCAL_HOUR || field==UCAL_MINUTE || field==UCAL_SECOND);
     352             : 
     353             :     // following call should not set wrong status,
     354             :     // all the pass-in fields are valid till here
     355           0 :     int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
     356           0 :                                                                         status);
     357           0 :     const PatternInfo& intervalPattern = fIntervalPatterns[itvPtnIndex];
     358             : 
     359           0 :     if ( intervalPattern.firstPart.isEmpty() &&
     360           0 :          intervalPattern.secondPart.isEmpty() ) {
     361           0 :         if ( fDateFormat->isFieldUnitIgnored(field) ) {
     362             :             /* the largest different calendar field is small than
     363             :              * the smallest calendar field in pattern,
     364             :              * return single date format.
     365             :              */
     366           0 :             return fDateFormat->format(fromCalendar, appendTo, pos);
     367             :         }
     368           0 :         return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos, status);
     369             :     }
     370             :     // If the first part in interval pattern is empty,
     371             :     // the 2nd part of it saves the full-pattern used in fall-back.
     372             :     // For a 'real' interval pattern, the first part will never be empty.
     373           0 :     if ( intervalPattern.firstPart.isEmpty() ) {
     374             :         // fall back
     375           0 :         UnicodeString originalPattern;
     376           0 :         fDateFormat->toPattern(originalPattern);
     377           0 :         fDateFormat->applyPattern(intervalPattern.secondPart);
     378           0 :         appendTo = fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos, status);
     379           0 :         fDateFormat->applyPattern(originalPattern);
     380           0 :         return appendTo;
     381             :     }
     382             :     Calendar* firstCal;
     383             :     Calendar* secondCal;
     384           0 :     if ( intervalPattern.laterDateFirst ) {
     385           0 :         firstCal = &toCalendar;
     386           0 :         secondCal = &fromCalendar;
     387             :     } else {
     388           0 :         firstCal = &fromCalendar;
     389           0 :         secondCal = &toCalendar;
     390             :     }
     391             :     // break the interval pattern into 2 parts,
     392             :     // first part should not be empty,
     393           0 :     UnicodeString originalPattern;
     394           0 :     fDateFormat->toPattern(originalPattern);
     395           0 :     fDateFormat->applyPattern(intervalPattern.firstPart);
     396           0 :     fDateFormat->format(*firstCal, appendTo, pos);
     397           0 :     if ( !intervalPattern.secondPart.isEmpty() ) {
     398           0 :         fDateFormat->applyPattern(intervalPattern.secondPart);
     399           0 :         FieldPosition otherPos;
     400           0 :         otherPos.setField(pos.getField());
     401           0 :         fDateFormat->format(*secondCal, appendTo, otherPos);
     402           0 :         if (pos.getEndIndex() == 0 && otherPos.getEndIndex() > 0) {
     403           0 :             pos = otherPos;
     404             :         }
     405             :     }
     406           0 :     fDateFormat->applyPattern(originalPattern);
     407           0 :     return appendTo;
     408             : }
     409             : 
     410             : 
     411             : 
     412             : void
     413           0 : DateIntervalFormat::parseObject(const UnicodeString& /* source */,
     414             :                                 Formattable& /* result */,
     415             :                                 ParsePosition& /* parse_pos */) const {
     416             :     // parseObject(const UnicodeString&, Formattable&, UErrorCode&) const
     417             :     // will set status as U_INVALID_FORMAT_ERROR if
     418             :     // parse_pos is still 0
     419           0 : }
     420             : 
     421             : 
     422             : 
     423             : 
     424             : const DateIntervalInfo*
     425           0 : DateIntervalFormat::getDateIntervalInfo() const {
     426           0 :     return fInfo;
     427             : }
     428             : 
     429             : 
     430             : void
     431           0 : DateIntervalFormat::setDateIntervalInfo(const DateIntervalInfo& newItvPattern,
     432             :                                         UErrorCode& status) {
     433           0 :     delete fInfo;
     434           0 :     fInfo = new DateIntervalInfo(newItvPattern);
     435             : 
     436             :     // Delete patterns that get reset by initializePattern
     437           0 :     delete fDatePattern;
     438           0 :     fDatePattern = NULL;
     439           0 :     delete fTimePattern;
     440           0 :     fTimePattern = NULL;
     441           0 :     delete fDateTimeFormat;
     442           0 :     fDateTimeFormat = NULL;
     443             : 
     444           0 :     if (fDateFormat) {
     445           0 :         initializePattern(status);
     446             :     }
     447           0 : }
     448             : 
     449             : 
     450             : 
     451             : const DateFormat*
     452           0 : DateIntervalFormat::getDateFormat() const {
     453           0 :     return fDateFormat;
     454             : }
     455             : 
     456             : 
     457             : void
     458           0 : DateIntervalFormat::adoptTimeZone(TimeZone* zone)
     459             : {
     460           0 :     if (fDateFormat != NULL) {
     461           0 :         fDateFormat->adoptTimeZone(zone);
     462             :     }
     463             :     // The fDateFormat has the master calendar for the DateIntervalFormat and has
     464             :     // ownership of any adopted TimeZone; fFromCalendar and fToCalendar are internal
     465             :     // work clones of that calendar (and should not also be given ownership of the
     466             :     // adopted TimeZone).
     467           0 :     if (fFromCalendar) {
     468           0 :         fFromCalendar->setTimeZone(*zone);
     469             :     }
     470           0 :     if (fToCalendar) {
     471           0 :         fToCalendar->setTimeZone(*zone);
     472             :     }
     473           0 : }
     474             : 
     475             : void
     476           0 : DateIntervalFormat::setTimeZone(const TimeZone& zone)
     477             : {
     478           0 :     if (fDateFormat != NULL) {
     479           0 :         fDateFormat->setTimeZone(zone);
     480             :     }
     481             :     // The fDateFormat has the master calendar for the DateIntervalFormat;
     482             :     // fFromCalendar and fToCalendar are internal work clones of that calendar.
     483           0 :     if (fFromCalendar) {
     484           0 :         fFromCalendar->setTimeZone(zone);
     485             :     }
     486           0 :     if (fToCalendar) {
     487           0 :         fToCalendar->setTimeZone(zone);
     488             :     }
     489           0 : }
     490             : 
     491             : const TimeZone&
     492           0 : DateIntervalFormat::getTimeZone() const
     493             : {
     494           0 :     if (fDateFormat != NULL) {
     495           0 :         Mutex lock(&gFormatterMutex);
     496           0 :         return fDateFormat->getTimeZone();
     497             :     }
     498             :     // If fDateFormat is NULL (unexpected), create default timezone.
     499           0 :     return *(TimeZone::createDefault());
     500             : }
     501             : 
     502           0 : DateIntervalFormat::DateIntervalFormat(const Locale& locale,
     503             :                                        DateIntervalInfo* dtItvInfo,
     504             :                                        const UnicodeString* skeleton,
     505           0 :                                        UErrorCode& status)
     506             : :   fInfo(NULL),
     507             :     fDateFormat(NULL),
     508             :     fFromCalendar(NULL),
     509             :     fToCalendar(NULL),
     510             :     fLocale(locale),
     511             :     fDatePattern(NULL),
     512             :     fTimePattern(NULL),
     513           0 :     fDateTimeFormat(NULL)
     514             : {
     515           0 :     LocalPointer<DateIntervalInfo> info(dtItvInfo, status);
     516             :     LocalPointer<SimpleDateFormat> dtfmt(static_cast<SimpleDateFormat *>(
     517           0 :             DateFormat::createInstanceForSkeleton(*skeleton, locale, status)), status);
     518           0 :     if (U_FAILURE(status)) {
     519           0 :         return;
     520             :     }
     521             : 
     522           0 :     if ( skeleton ) {
     523           0 :         fSkeleton = *skeleton;
     524             :     }
     525           0 :     fInfo = info.orphan();
     526           0 :     fDateFormat = dtfmt.orphan();
     527           0 :     if ( fDateFormat->getCalendar() ) {
     528           0 :         fFromCalendar = fDateFormat->getCalendar()->clone();
     529           0 :         fToCalendar = fDateFormat->getCalendar()->clone();
     530             :     }
     531           0 :     initializePattern(status);
     532             : }
     533             : 
     534             : DateIntervalFormat* U_EXPORT2
     535           0 : DateIntervalFormat::create(const Locale& locale,
     536             :                            DateIntervalInfo* dtitvinf,
     537             :                            const UnicodeString* skeleton,
     538             :                            UErrorCode& status) {
     539             :     DateIntervalFormat* f = new DateIntervalFormat(locale, dtitvinf,
     540           0 :                                                    skeleton, status);
     541           0 :     if ( f == NULL ) {
     542           0 :         status = U_MEMORY_ALLOCATION_ERROR;
     543           0 :         delete dtitvinf;
     544           0 :     } else if ( U_FAILURE(status) ) {
     545             :         // safe to delete f, although nothing acutally is saved
     546           0 :         delete f;
     547           0 :         f = 0;
     548             :     }
     549           0 :     return f;
     550             : }
     551             : 
     552             : 
     553             : 
     554             : /**
     555             :  * Initialize interval patterns locale to this formatter
     556             :  *
     557             :  * This code is a bit complicated since
     558             :  * 1. the interval patterns saved in resource bundle files are interval
     559             :  *    patterns based on date or time only.
     560             :  *    It does not have interval patterns based on both date and time.
     561             :  *    Interval patterns on both date and time are algorithm generated.
     562             :  *
     563             :  *    For example, it has interval patterns on skeleton "dMy" and "hm",
     564             :  *    but it does not have interval patterns on skeleton "dMyhm".
     565             :  *
     566             :  *    The rule to genearte interval patterns for both date and time skeleton are
     567             :  *    1) when the year, month, or day differs, concatenate the two original
     568             :  *    expressions with a separator between,
     569             :  *    For example, interval pattern from "Jan 10, 2007 10:10 am"
     570             :  *    to "Jan 11, 2007 10:10am" is
     571             :  *    "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
     572             :  *
     573             :  *    2) otherwise, present the date followed by the range expression
     574             :  *    for the time.
     575             :  *    For example, interval pattern from "Jan 10, 2007 10:10 am"
     576             :  *    to "Jan 10, 2007 11:10am" is
     577             :  *    "Jan 10, 2007 10:10 am - 11:10am"
     578             :  *
     579             :  * 2. even a pattern does not request a certion calendar field,
     580             :  *    the interval pattern needs to include such field if such fields are
     581             :  *    different between 2 dates.
     582             :  *    For example, a pattern/skeleton is "hm", but the interval pattern
     583             :  *    includes year, month, and date when year, month, and date differs.
     584             :  *
     585             :  * @param status          output param set to success/failure code on exit
     586             :  * @stable ICU 4.0
     587             :  */
     588             : void
     589           0 : DateIntervalFormat::initializePattern(UErrorCode& status) {
     590           0 :     if ( U_FAILURE(status) ) {
     591           0 :         return;
     592             :     }
     593           0 :     const Locale& locale = fDateFormat->getSmpFmtLocale();
     594           0 :     if ( fSkeleton.isEmpty() ) {
     595           0 :         UnicodeString fullPattern;
     596           0 :         fDateFormat->toPattern(fullPattern);
     597             : #ifdef DTITVFMT_DEBUG
     598             :     char result[1000];
     599             :     char result_1[1000];
     600             :     char mesg[2000];
     601             :     fSkeleton.extract(0,  fSkeleton.length(), result, "UTF-8");
     602             :     sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
     603             :     PRINTMESG(mesg)
     604             : #endif
     605             :         // fSkeleton is already set by createDateIntervalInstance()
     606             :         // or by createInstance(UnicodeString skeleton, .... )
     607           0 :         fSkeleton = DateTimePatternGenerator::staticGetSkeleton(
     608           0 :                 fullPattern, status);
     609           0 :         if ( U_FAILURE(status) ) {
     610           0 :             return;
     611             :         }
     612             :     }
     613             : 
     614             :     // initialize the fIntervalPattern ordering
     615             :     int8_t i;
     616           0 :     for ( i = 0; i < DateIntervalInfo::kIPI_MAX_INDEX; ++i ) {
     617           0 :         fIntervalPatterns[i].laterDateFirst = fInfo->getDefaultOrder();
     618             :     }
     619             : 
     620             :     /* Check whether the skeleton is a combination of date and time.
     621             :      * For the complication reason 1 explained above.
     622             :      */
     623           0 :     UnicodeString dateSkeleton;
     624           0 :     UnicodeString timeSkeleton;
     625           0 :     UnicodeString normalizedTimeSkeleton;
     626           0 :     UnicodeString normalizedDateSkeleton;
     627             : 
     628             : 
     629             :     /* the difference between time skeleton and normalizedTimeSkeleton are:
     630             :      * 1. (Formerly, normalized time skeleton folded 'H' to 'h'; no longer true)
     631             :      * 2. 'a' is omitted in normalized time skeleton.
     632             :      * 3. there is only one appearance for 'h' or 'H', 'm','v', 'z' in normalized
     633             :      *    time skeleton
     634             :      *
     635             :      * The difference between date skeleton and normalizedDateSkeleton are:
     636             :      * 1. both 'y' and 'd' appear only once in normalizeDateSkeleton
     637             :      * 2. 'E' and 'EE' are normalized into 'EEE'
     638             :      * 3. 'MM' is normalized into 'M'
     639             :      */
     640           0 :     getDateTimeSkeleton(fSkeleton, dateSkeleton, normalizedDateSkeleton,
     641           0 :                         timeSkeleton, normalizedTimeSkeleton);
     642             : 
     643             : #ifdef DTITVFMT_DEBUG
     644             :     char result[1000];
     645             :     char result_1[1000];
     646             :     char mesg[2000];
     647             :     fSkeleton.extract(0,  fSkeleton.length(), result, "UTF-8");
     648             :     sprintf(mesg, "in getBestSkeleton: fSkeleton: %s; \n", result);
     649             :     PRINTMESG(mesg)
     650             : #endif
     651             : 
     652             :     // move this up here since we need it for fallbacks
     653           0 :     if ( timeSkeleton.length() > 0 && dateSkeleton.length() > 0 ) {
     654             :         // Need the Date/Time pattern for concatenation of the date
     655             :         // with the time interval.
     656             :         // The date/time pattern ( such as {0} {1} ) is saved in
     657             :         // calendar, that is why need to get the CalendarData here.
     658           0 :         LocalUResourceBundlePointer dateTimePatternsRes(ures_open(NULL, locale.getBaseName(), &status));
     659           0 :         ures_getByKey(dateTimePatternsRes.getAlias(), gCalendarTag,
     660           0 :                       dateTimePatternsRes.getAlias(), &status);
     661           0 :         ures_getByKeyWithFallback(dateTimePatternsRes.getAlias(), gGregorianTag,
     662           0 :                                   dateTimePatternsRes.getAlias(), &status);
     663           0 :         ures_getByKeyWithFallback(dateTimePatternsRes.getAlias(), gDateTimePatternsTag,
     664           0 :                                   dateTimePatternsRes.getAlias(), &status);
     665             : 
     666             :         int32_t dateTimeFormatLength;
     667             :         const UChar* dateTimeFormat = ures_getStringByIndex(
     668           0 :                                             dateTimePatternsRes.getAlias(),
     669             :                                             (int32_t)DateFormat::kDateTime,
     670           0 :                                             &dateTimeFormatLength, &status);
     671           0 :         if ( U_SUCCESS(status) && dateTimeFormatLength >= 3 ) {
     672           0 :             fDateTimeFormat = new UnicodeString(dateTimeFormat, dateTimeFormatLength);
     673             :         }
     674             :     }
     675             : 
     676             :     UBool found = setSeparateDateTimePtn(normalizedDateSkeleton,
     677           0 :                                          normalizedTimeSkeleton);
     678             : 
     679             :     // for skeletons with seconds, found is false and we enter this block
     680           0 :     if ( found == false ) {
     681             :         // use fallback
     682             :         // TODO: if user asks "m"(minute), but "d"(day) differ
     683           0 :         if ( timeSkeleton.length() != 0 ) {
     684           0 :             if ( dateSkeleton.length() == 0 ) {
     685             :                 // prefix with yMd
     686           0 :                 timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
     687             :                 UnicodeString pattern = DateFormat::getBestPattern(
     688           0 :                         locale, timeSkeleton, status);
     689           0 :                 if ( U_FAILURE(status) ) {
     690           0 :                     return;
     691             :                 }
     692             :                 // for fall back interval patterns,
     693             :                 // the first part of the pattern is empty,
     694             :                 // the second part of the pattern is the full-pattern
     695             :                 // should be used in fall-back.
     696           0 :                 setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
     697           0 :                 setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
     698           0 :                 setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
     699             :             } else {
     700             :                 // TODO: fall back
     701             :             }
     702             :         } else {
     703             :             // TODO: fall back
     704             :         }
     705           0 :         return;
     706             :     } // end of skeleton not found
     707             :     // interval patterns for skeleton are found in resource
     708           0 :     if ( timeSkeleton.length() == 0 ) {
     709             :         // done
     710           0 :     } else if ( dateSkeleton.length() == 0 ) {
     711             :         // prefix with yMd
     712           0 :         timeSkeleton.insert(0, gDateFormatSkeleton[DateFormat::kShort], -1);
     713             :         UnicodeString pattern = DateFormat::getBestPattern(
     714           0 :                 locale, timeSkeleton, status);
     715           0 :         if ( U_FAILURE(status) ) {
     716           0 :             return;
     717             :         }
     718             :         // for fall back interval patterns,
     719             :         // the first part of the pattern is empty,
     720             :         // the second part of the pattern is the full-pattern
     721             :         // should be used in fall-back.
     722           0 :         setPatternInfo(UCAL_DATE, NULL, &pattern, fInfo->getDefaultOrder());
     723           0 :         setPatternInfo(UCAL_MONTH, NULL, &pattern, fInfo->getDefaultOrder());
     724           0 :         setPatternInfo(UCAL_YEAR, NULL, &pattern, fInfo->getDefaultOrder());
     725             :     } else {
     726             :         /* if both present,
     727             :          * 1) when the year, month, or day differs,
     728             :          * concatenate the two original expressions with a separator between,
     729             :          * 2) otherwise, present the date followed by the
     730             :          * range expression for the time.
     731             :          */
     732             :         /*
     733             :          * 1) when the year, month, or day differs,
     734             :          * concatenate the two original expressions with a separator between,
     735             :          */
     736             :         // if field exists, use fall back
     737           0 :         UnicodeString skeleton = fSkeleton;
     738           0 :         if ( !fieldExistsInSkeleton(UCAL_DATE, dateSkeleton) ) {
     739             :             // prefix skeleton with 'd'
     740           0 :             skeleton.insert(0, LOW_D);
     741           0 :             setFallbackPattern(UCAL_DATE, skeleton, status);
     742             :         }
     743           0 :         if ( !fieldExistsInSkeleton(UCAL_MONTH, dateSkeleton) ) {
     744             :             // then prefix skeleton with 'M'
     745           0 :             skeleton.insert(0, CAP_M);
     746           0 :             setFallbackPattern(UCAL_MONTH, skeleton, status);
     747             :         }
     748           0 :         if ( !fieldExistsInSkeleton(UCAL_YEAR, dateSkeleton) ) {
     749             :             // then prefix skeleton with 'y'
     750           0 :             skeleton.insert(0, LOW_Y);
     751           0 :             setFallbackPattern(UCAL_YEAR, skeleton, status);
     752             :         }
     753             : 
     754             :         /*
     755             :          * 2) otherwise, present the date followed by the
     756             :          * range expression for the time.
     757             :          */
     758             : 
     759           0 :         if ( fDateTimeFormat == NULL ) {
     760             :             // earlier failure getting dateTimeFormat
     761           0 :             return;
     762             :         }
     763             : 
     764             :         UnicodeString datePattern = DateFormat::getBestPattern(
     765           0 :                 locale, dateSkeleton, status);
     766             : 
     767           0 :         concatSingleDate2TimeInterval(*fDateTimeFormat, datePattern, UCAL_AM_PM, status);
     768           0 :         concatSingleDate2TimeInterval(*fDateTimeFormat, datePattern, UCAL_HOUR, status);
     769           0 :         concatSingleDate2TimeInterval(*fDateTimeFormat, datePattern, UCAL_MINUTE, status);
     770             :     }
     771             : }
     772             : 
     773             : 
     774             : 
     775             : void  U_EXPORT2
     776           0 : DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton,
     777             :                                         UnicodeString& dateSkeleton,
     778             :                                         UnicodeString& normalizedDateSkeleton,
     779             :                                         UnicodeString& timeSkeleton,
     780             :                                         UnicodeString& normalizedTimeSkeleton) {
     781             :     // dateSkeleton follows the sequence of y*M*E*d*
     782             :     // timeSkeleton follows the sequence of hm*[v|z]?
     783           0 :     int32_t ECount = 0;
     784           0 :     int32_t dCount = 0;
     785           0 :     int32_t MCount = 0;
     786           0 :     int32_t yCount = 0;
     787           0 :     int32_t hCount = 0;
     788           0 :     int32_t HCount = 0;
     789           0 :     int32_t mCount = 0;
     790           0 :     int32_t vCount = 0;
     791           0 :     int32_t zCount = 0;
     792             :     int32_t i;
     793             : 
     794           0 :     for (i = 0; i < skeleton.length(); ++i) {
     795           0 :         UChar ch = skeleton[i];
     796           0 :         switch ( ch ) {
     797             :           case CAP_E:
     798           0 :             dateSkeleton.append(ch);
     799           0 :             ++ECount;
     800           0 :             break;
     801             :           case LOW_D:
     802           0 :             dateSkeleton.append(ch);
     803           0 :             ++dCount;
     804           0 :             break;
     805             :           case CAP_M:
     806           0 :             dateSkeleton.append(ch);
     807           0 :             ++MCount;
     808           0 :             break;
     809             :           case LOW_Y:
     810           0 :             dateSkeleton.append(ch);
     811           0 :             ++yCount;
     812           0 :             break;
     813             :           case CAP_G:
     814             :           case CAP_Y:
     815             :           case LOW_U:
     816             :           case CAP_Q:
     817             :           case LOW_Q:
     818             :           case CAP_L:
     819             :           case LOW_L:
     820             :           case CAP_W:
     821             :           case LOW_W:
     822             :           case CAP_D:
     823             :           case CAP_F:
     824             :           case LOW_G:
     825             :           case LOW_E:
     826             :           case LOW_C:
     827             :           case CAP_U:
     828             :           case LOW_R:
     829           0 :             normalizedDateSkeleton.append(ch);
     830           0 :             dateSkeleton.append(ch);
     831           0 :             break;
     832             :           case LOW_A:
     833             :             // 'a' is implicitly handled
     834           0 :             timeSkeleton.append(ch);
     835           0 :             break;
     836             :           case LOW_H:
     837           0 :             timeSkeleton.append(ch);
     838           0 :             ++hCount;
     839           0 :             break;
     840             :           case CAP_H:
     841           0 :             timeSkeleton.append(ch);
     842           0 :             ++HCount;
     843           0 :             break;
     844             :           case LOW_M:
     845           0 :             timeSkeleton.append(ch);
     846           0 :             ++mCount;
     847           0 :             break;
     848             :           case LOW_Z:
     849           0 :             ++zCount;
     850           0 :             timeSkeleton.append(ch);
     851           0 :             break;
     852             :           case LOW_V:
     853           0 :             ++vCount;
     854           0 :             timeSkeleton.append(ch);
     855           0 :             break;
     856             :           case CAP_V:
     857             :           case CAP_Z:
     858             :           case LOW_K:
     859             :           case CAP_K:
     860             :           case LOW_J:
     861             :           case LOW_S:
     862             :           case CAP_S:
     863             :           case CAP_A:
     864           0 :             timeSkeleton.append(ch);
     865           0 :             normalizedTimeSkeleton.append(ch);
     866           0 :             break;
     867             :         }
     868             :     }
     869             : 
     870             :     /* generate normalized form for date*/
     871           0 :     if ( yCount != 0 ) {
     872           0 :         for (i = 0; i < yCount; ++i) {
     873           0 :             normalizedDateSkeleton.append(LOW_Y);
     874             :         }
     875             :     }
     876           0 :     if ( MCount != 0 ) {
     877           0 :         if ( MCount < 3 ) {
     878           0 :             normalizedDateSkeleton.append(CAP_M);
     879             :         } else {
     880             :             int32_t i;
     881           0 :             for ( i = 0; i < MCount && i < MAX_M_COUNT; ++i ) {
     882           0 :                  normalizedDateSkeleton.append(CAP_M);
     883             :             }
     884             :         }
     885             :     }
     886           0 :     if ( ECount != 0 ) {
     887           0 :         if ( ECount <= 3 ) {
     888           0 :             normalizedDateSkeleton.append(CAP_E);
     889             :         } else {
     890             :             int32_t i;
     891           0 :             for ( i = 0; i < ECount && i < MAX_E_COUNT; ++i ) {
     892           0 :                  normalizedDateSkeleton.append(CAP_E);
     893             :             }
     894             :         }
     895             :     }
     896           0 :     if ( dCount != 0 ) {
     897           0 :         normalizedDateSkeleton.append(LOW_D);
     898             :     }
     899             : 
     900             :     /* generate normalized form for time */
     901           0 :     if ( HCount != 0 ) {
     902           0 :         normalizedTimeSkeleton.append(CAP_H);
     903             :     }
     904           0 :     else if ( hCount != 0 ) {
     905           0 :         normalizedTimeSkeleton.append(LOW_H);
     906             :     }
     907           0 :     if ( mCount != 0 ) {
     908           0 :         normalizedTimeSkeleton.append(LOW_M);
     909             :     }
     910           0 :     if ( zCount != 0 ) {
     911           0 :         normalizedTimeSkeleton.append(LOW_Z);
     912             :     }
     913           0 :     if ( vCount != 0 ) {
     914           0 :         normalizedTimeSkeleton.append(LOW_V);
     915             :     }
     916           0 : }
     917             : 
     918             : 
     919             : /**
     920             :  * Generate date or time interval pattern from resource,
     921             :  * and set them into the interval pattern locale to this formatter.
     922             :  *
     923             :  * It needs to handle the following:
     924             :  * 1. need to adjust field width.
     925             :  *    For example, the interval patterns saved in DateIntervalInfo
     926             :  *    includes "dMMMy", but not "dMMMMy".
     927             :  *    Need to get interval patterns for dMMMMy from dMMMy.
     928             :  *    Another example, the interval patterns saved in DateIntervalInfo
     929             :  *    includes "hmv", but not "hmz".
     930             :  *    Need to get interval patterns for "hmz' from 'hmv'
     931             :  *
     932             :  * 2. there might be no pattern for 'y' differ for skeleton "Md",
     933             :  *    in order to get interval patterns for 'y' differ,
     934             :  *    need to look for it from skeleton 'yMd'
     935             :  *
     936             :  * @param dateSkeleton   normalized date skeleton
     937             :  * @param timeSkeleton   normalized time skeleton
     938             :  * @return               whether the resource is found for the skeleton.
     939             :  *                       TRUE if interval pattern found for the skeleton,
     940             :  *                       FALSE otherwise.
     941             :  * @stable ICU 4.0
     942             :  */
     943             : UBool
     944           0 : DateIntervalFormat::setSeparateDateTimePtn(
     945             :                                  const UnicodeString& dateSkeleton,
     946             :                                  const UnicodeString& timeSkeleton) {
     947             :     const UnicodeString* skeleton;
     948             :     // if both date and time skeleton present,
     949             :     // the final interval pattern might include time interval patterns
     950             :     // ( when, am_pm, hour, minute differ ),
     951             :     // but not date interval patterns ( when year, month, day differ ).
     952             :     // For year/month/day differ, it falls back to fall-back pattern.
     953           0 :     if ( timeSkeleton.length() != 0  ) {
     954           0 :         skeleton = &timeSkeleton;
     955             :     } else {
     956           0 :         skeleton = &dateSkeleton;
     957             :     }
     958             : 
     959             :     /* interval patterns for skeleton "dMMMy" (but not "dMMMMy")
     960             :      * are defined in resource,
     961             :      * interval patterns for skeleton "dMMMMy" are calculated by
     962             :      * 1. get the best match skeleton for "dMMMMy", which is "dMMMy"
     963             :      * 2. get the interval patterns for "dMMMy",
     964             :      * 3. extend "MMM" to "MMMM" in above interval patterns for "dMMMMy"
     965             :      * getBestSkeleton() is step 1.
     966             :      */
     967             :     // best skeleton, and the difference information
     968           0 :     int8_t differenceInfo = 0;
     969           0 :     const UnicodeString* bestSkeleton = fInfo->getBestSkeleton(*skeleton,
     970           0 :                                                                differenceInfo);
     971             :     /* best skeleton could be NULL.
     972             :        For example: in "ca" resource file,
     973             :        interval format is defined as following
     974             :            intervalFormats{
     975             :                 fallback{"{0} - {1}"}
     976             :             }
     977             :        there is no skeletons/interval patterns defined,
     978             :        and the best skeleton match could be NULL
     979             :      */
     980           0 :     if ( bestSkeleton == NULL ) {
     981           0 :         return false;
     982             :     }
     983             : 
     984             :     // Set patterns for fallback use, need to do this
     985             :     // before returning if differenceInfo == -1
     986             :     UErrorCode status;
     987           0 :     if ( dateSkeleton.length() != 0) {
     988           0 :         status = U_ZERO_ERROR;
     989           0 :         fDatePattern = new UnicodeString(DateFormat::getBestPattern(
     990           0 :                 fLocale, dateSkeleton, status));
     991             :     }
     992           0 :     if ( timeSkeleton.length() != 0) {
     993           0 :         status = U_ZERO_ERROR;
     994           0 :         fTimePattern = new UnicodeString(DateFormat::getBestPattern(
     995           0 :                 fLocale, timeSkeleton, status));
     996             :     }
     997             : 
     998             :     // difference:
     999             :     // 0 means the best matched skeleton is the same as input skeleton
    1000             :     // 1 means the fields are the same, but field width are different
    1001             :     // 2 means the only difference between fields are v/z,
    1002             :     // -1 means there are other fields difference
    1003             :     // (this will happen, for instance, if the supplied skeleton has seconds,
    1004             :     //  but no skeletons in the intervalFormats data do)
    1005           0 :     if ( differenceInfo == -1 ) {
    1006             :         // skeleton has different fields, not only  v/z difference
    1007           0 :         return false;
    1008             :     }
    1009             : 
    1010           0 :     if ( timeSkeleton.length() == 0 ) {
    1011           0 :         UnicodeString extendedSkeleton;
    1012           0 :         UnicodeString extendedBestSkeleton;
    1013             :         // only has date skeleton
    1014           0 :         setIntervalPattern(UCAL_DATE, skeleton, bestSkeleton, differenceInfo,
    1015           0 :                            &extendedSkeleton, &extendedBestSkeleton);
    1016             : 
    1017           0 :         UBool extended = setIntervalPattern(UCAL_MONTH, skeleton, bestSkeleton,
    1018             :                                      differenceInfo,
    1019           0 :                                      &extendedSkeleton, &extendedBestSkeleton);
    1020             : 
    1021           0 :         if ( extended ) {
    1022           0 :             bestSkeleton = &extendedBestSkeleton;
    1023           0 :             skeleton = &extendedSkeleton;
    1024             :         }
    1025           0 :         setIntervalPattern(UCAL_YEAR, skeleton, bestSkeleton, differenceInfo,
    1026           0 :                            &extendedSkeleton, &extendedBestSkeleton);
    1027             :     } else {
    1028           0 :         setIntervalPattern(UCAL_MINUTE, skeleton, bestSkeleton, differenceInfo);
    1029           0 :         setIntervalPattern(UCAL_HOUR, skeleton, bestSkeleton, differenceInfo);
    1030           0 :         setIntervalPattern(UCAL_AM_PM, skeleton, bestSkeleton, differenceInfo);
    1031             :     }
    1032           0 :     return true;
    1033             : }
    1034             : 
    1035             : 
    1036             : 
    1037             : void
    1038           0 : DateIntervalFormat::setFallbackPattern(UCalendarDateFields field,
    1039             :                                        const UnicodeString& skeleton,
    1040             :                                        UErrorCode& status) {
    1041           0 :     if ( U_FAILURE(status) ) {
    1042           0 :         return;
    1043             :     }
    1044             :     UnicodeString pattern = DateFormat::getBestPattern(
    1045           0 :             fLocale, skeleton, status);
    1046           0 :     if ( U_FAILURE(status) ) {
    1047           0 :         return;
    1048             :     }
    1049           0 :     setPatternInfo(field, NULL, &pattern, fInfo->getDefaultOrder());
    1050             : }
    1051             : 
    1052             : 
    1053             : 
    1054             : 
    1055             : void
    1056           0 : DateIntervalFormat::setPatternInfo(UCalendarDateFields field,
    1057             :                                    const UnicodeString* firstPart,
    1058             :                                    const UnicodeString* secondPart,
    1059             :                                    UBool laterDateFirst) {
    1060             :     // for fall back interval patterns,
    1061             :     // the first part of the pattern is empty,
    1062             :     // the second part of the pattern is the full-pattern
    1063             :     // should be used in fall-back.
    1064           0 :     UErrorCode status = U_ZERO_ERROR;
    1065             :     // following should not set any wrong status.
    1066           0 :     int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
    1067           0 :                                                                         status);
    1068           0 :     if ( U_FAILURE(status) ) {
    1069           0 :         return;
    1070             :     }
    1071           0 :     PatternInfo& ptn = fIntervalPatterns[itvPtnIndex];
    1072           0 :     if ( firstPart ) {
    1073           0 :         ptn.firstPart = *firstPart;
    1074             :     }
    1075           0 :     if ( secondPart ) {
    1076           0 :         ptn.secondPart = *secondPart;
    1077             :     }
    1078           0 :     ptn.laterDateFirst = laterDateFirst;
    1079             : }
    1080             : 
    1081             : void
    1082           0 : DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
    1083             :                                        const UnicodeString& intervalPattern) {
    1084           0 :     UBool order = fInfo->getDefaultOrder();
    1085           0 :     setIntervalPattern(field, intervalPattern, order);
    1086           0 : }
    1087             : 
    1088             : 
    1089             : void
    1090           0 : DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
    1091             :                                        const UnicodeString& intervalPattern,
    1092             :                                        UBool laterDateFirst) {
    1093           0 :     const UnicodeString* pattern = &intervalPattern;
    1094           0 :     UBool order = laterDateFirst;
    1095             :     // check for "latestFirst:" or "earliestFirst:" prefix
    1096           0 :     int8_t prefixLength = UPRV_LENGTHOF(gLaterFirstPrefix);
    1097           0 :     int8_t earliestFirstLength = UPRV_LENGTHOF(gEarlierFirstPrefix);
    1098           0 :     UnicodeString realPattern;
    1099           0 :     if ( intervalPattern.startsWith(gLaterFirstPrefix, prefixLength) ) {
    1100           0 :         order = true;
    1101           0 :         intervalPattern.extract(prefixLength,
    1102           0 :                                 intervalPattern.length() - prefixLength,
    1103           0 :                                 realPattern);
    1104           0 :         pattern = &realPattern;
    1105           0 :     } else if ( intervalPattern.startsWith(gEarlierFirstPrefix,
    1106             :                                            earliestFirstLength) ) {
    1107           0 :         order = false;
    1108           0 :         intervalPattern.extract(earliestFirstLength,
    1109           0 :                                 intervalPattern.length() - earliestFirstLength,
    1110           0 :                                 realPattern);
    1111           0 :         pattern = &realPattern;
    1112             :     }
    1113             : 
    1114           0 :     int32_t splitPoint = splitPatternInto2Part(*pattern);
    1115             : 
    1116           0 :     UnicodeString firstPart;
    1117           0 :     UnicodeString secondPart;
    1118           0 :     pattern->extract(0, splitPoint, firstPart);
    1119           0 :     if ( splitPoint < pattern->length() ) {
    1120           0 :         pattern->extract(splitPoint, pattern->length()-splitPoint, secondPart);
    1121             :     }
    1122           0 :     setPatternInfo(field, &firstPart, &secondPart, order);
    1123           0 : }
    1124             : 
    1125             : 
    1126             : 
    1127             : 
    1128             : /**
    1129             :  * Generate interval pattern from existing resource
    1130             :  *
    1131             :  * It not only save the interval patterns,
    1132             :  * but also return the extended skeleton and its best match skeleton.
    1133             :  *
    1134             :  * @param field           largest different calendar field
    1135             :  * @param skeleton        skeleton
    1136             :  * @param bestSkeleton    the best match skeleton which has interval pattern
    1137             :  *                        defined in resource
    1138             :  * @param differenceInfo  the difference between skeleton and best skeleton
    1139             :  *         0 means the best matched skeleton is the same as input skeleton
    1140             :  *         1 means the fields are the same, but field width are different
    1141             :  *         2 means the only difference between fields are v/z,
    1142             :  *        -1 means there are other fields difference
    1143             :  *
    1144             :  * @param extendedSkeleton      extended skeleton
    1145             :  * @param extendedBestSkeleton  extended best match skeleton
    1146             :  * @return                      whether the interval pattern is found
    1147             :  *                              through extending skeleton or not.
    1148             :  *                              TRUE if interval pattern is found by
    1149             :  *                              extending skeleton, FALSE otherwise.
    1150             :  * @stable ICU 4.0
    1151             :  */
    1152             : UBool
    1153           0 : DateIntervalFormat::setIntervalPattern(UCalendarDateFields field,
    1154             :                                        const UnicodeString* skeleton,
    1155             :                                        const UnicodeString* bestSkeleton,
    1156             :                                        int8_t differenceInfo,
    1157             :                                        UnicodeString* extendedSkeleton,
    1158             :                                        UnicodeString* extendedBestSkeleton) {
    1159           0 :     UErrorCode status = U_ZERO_ERROR;
    1160             :     // following getIntervalPattern() should not generate error status
    1161           0 :     UnicodeString pattern;
    1162           0 :     fInfo->getIntervalPattern(*bestSkeleton, field, pattern, status);
    1163           0 :     if ( pattern.isEmpty() ) {
    1164             :         // single date
    1165           0 :         if ( SimpleDateFormat::isFieldUnitIgnored(*bestSkeleton, field) ) {
    1166             :             // do nothing, format will handle it
    1167           0 :             return false;
    1168             :         }
    1169             : 
    1170             :         // for 24 hour system, interval patterns in resource file
    1171             :         // might not include pattern when am_pm differ,
    1172             :         // which should be the same as hour differ.
    1173             :         // add it here for simplicity
    1174           0 :         if ( field == UCAL_AM_PM ) {
    1175           0 :             fInfo->getIntervalPattern(*bestSkeleton, UCAL_HOUR, pattern,status);
    1176           0 :             if ( !pattern.isEmpty() ) {
    1177           0 :                 setIntervalPattern(field, pattern);
    1178             :             }
    1179           0 :             return false;
    1180             :         }
    1181             :         // else, looking for pattern when 'y' differ for 'dMMMM' skeleton,
    1182             :         // first, get best match pattern "MMMd",
    1183             :         // since there is no pattern for 'y' differs for skeleton 'MMMd',
    1184             :         // need to look for it from skeleton 'yMMMd',
    1185             :         // if found, adjust field width in interval pattern from
    1186             :         // "MMM" to "MMMM".
    1187           0 :         UChar fieldLetter = fgCalendarFieldToPatternLetter[field];
    1188           0 :         if ( extendedSkeleton ) {
    1189           0 :             *extendedSkeleton = *skeleton;
    1190           0 :             *extendedBestSkeleton = *bestSkeleton;
    1191           0 :             extendedSkeleton->insert(0, fieldLetter);
    1192           0 :             extendedBestSkeleton->insert(0, fieldLetter);
    1193             :             // for example, looking for patterns when 'y' differ for
    1194             :             // skeleton "MMMM".
    1195           0 :             fInfo->getIntervalPattern(*extendedBestSkeleton,field,pattern,status);
    1196           0 :             if ( pattern.isEmpty() && differenceInfo == 0 ) {
    1197             :                 // if there is no skeleton "yMMMM" defined,
    1198             :                 // look for the best match skeleton, for example: "yMMM"
    1199           0 :                 const UnicodeString* tmpBest = fInfo->getBestSkeleton(
    1200           0 :                                         *extendedBestSkeleton, differenceInfo);
    1201           0 :                 if ( tmpBest != 0 && differenceInfo != -1 ) {
    1202           0 :                     fInfo->getIntervalPattern(*tmpBest, field, pattern, status);
    1203           0 :                     bestSkeleton = tmpBest;
    1204             :                 }
    1205             :             }
    1206             :         }
    1207             :     }
    1208           0 :     if ( !pattern.isEmpty() ) {
    1209           0 :         if ( differenceInfo != 0 ) {
    1210           0 :             UnicodeString adjustIntervalPattern;
    1211           0 :             adjustFieldWidth(*skeleton, *bestSkeleton, pattern, differenceInfo,
    1212           0 :                               adjustIntervalPattern);
    1213           0 :             setIntervalPattern(field, adjustIntervalPattern);
    1214             :         } else {
    1215           0 :             setIntervalPattern(field, pattern);
    1216             :         }
    1217           0 :         if ( extendedSkeleton && !extendedSkeleton->isEmpty() ) {
    1218           0 :             return TRUE;
    1219             :         }
    1220             :     }
    1221           0 :     return FALSE;
    1222             : }
    1223             : 
    1224             : 
    1225             : 
    1226             : int32_t  U_EXPORT2
    1227           0 : DateIntervalFormat::splitPatternInto2Part(const UnicodeString& intervalPattern) {
    1228           0 :     UBool inQuote = false;
    1229           0 :     UChar prevCh = 0;
    1230           0 :     int32_t count = 0;
    1231             : 
    1232             :     /* repeatedPattern used to record whether a pattern has already seen.
    1233             :        It is a pattern applies to first calendar if it is first time seen,
    1234             :        otherwise, it is a pattern applies to the second calendar
    1235             :      */
    1236             :     UBool patternRepeated[] =
    1237             :     {
    1238             :     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
    1239             :              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1240             :     //   P   Q   R   S   T   U   V   W   X   Y   Z
    1241             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0,  0, 0, 0,
    1242             :     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
    1243             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1244             :     //   p   q   r   s   t   u   v   w   x   y   z
    1245             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
    1246           0 :     };
    1247             : 
    1248           0 :     int8_t PATTERN_CHAR_BASE = 0x41;
    1249             : 
    1250             :     /* loop through the pattern string character by character looking for
    1251             :      * the first repeated pattern letter, which breaks the interval pattern
    1252             :      * into 2 parts.
    1253             :      */
    1254             :     int32_t i;
    1255           0 :     UBool foundRepetition = false;
    1256           0 :     for (i = 0; i < intervalPattern.length(); ++i) {
    1257           0 :         UChar ch = intervalPattern.charAt(i);
    1258             : 
    1259           0 :         if (ch != prevCh && count > 0) {
    1260             :             // check the repeativeness of pattern letter
    1261           0 :             UBool repeated = patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)];
    1262           0 :             if ( repeated == FALSE ) {
    1263           0 :                 patternRepeated[prevCh - PATTERN_CHAR_BASE] = TRUE;
    1264             :             } else {
    1265           0 :                 foundRepetition = true;
    1266           0 :                 break;
    1267             :             }
    1268           0 :             count = 0;
    1269             :         }
    1270           0 :         if (ch == 0x0027 /*'*/) {
    1271             :             // Consecutive single quotes are a single quote literal,
    1272             :             // either outside of quotes or between quotes
    1273           0 :             if ((i+1) < intervalPattern.length() &&
    1274           0 :                 intervalPattern.charAt(i+1) == 0x0027 /*'*/) {
    1275           0 :                 ++i;
    1276             :             } else {
    1277           0 :                 inQuote = ! inQuote;
    1278             :             }
    1279             :         }
    1280           0 :         else if (!inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
    1281           0 :                     || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
    1282             :             // ch is a date-time pattern character
    1283           0 :             prevCh = ch;
    1284           0 :             ++count;
    1285             :         }
    1286             :     }
    1287             :     // check last pattern char, distinguish
    1288             :     // "dd MM" ( no repetition ),
    1289             :     // "d-d"(last char repeated ), and
    1290             :     // "d-d MM" ( repetition found )
    1291           0 :     if ( count > 0 && foundRepetition == FALSE ) {
    1292           0 :         if ( patternRepeated[(int)(prevCh - PATTERN_CHAR_BASE)] == FALSE ) {
    1293           0 :             count = 0;
    1294             :         }
    1295             :     }
    1296           0 :     return (i - count);
    1297             : }
    1298             : 
    1299             : static const UChar bracketedZero[] = {0x7B,0x30,0x7D};
    1300             : static const UChar bracketedOne[]  = {0x7B,0x31,0x7D};
    1301             : 
    1302             : void
    1303           0 : DateIntervalFormat::adjustPosition(UnicodeString& combiningPattern, // has {0} and {1} in it
    1304             :                                    UnicodeString& pat0, FieldPosition& pos0, // pattern and pos corresponding to {0}
    1305             :                                    UnicodeString& pat1, FieldPosition& pos1, // pattern and pos corresponding to {1}
    1306             :                                    FieldPosition& posResult)  {
    1307           0 :     int32_t index0 = combiningPattern.indexOf(bracketedZero, 3, 0);
    1308           0 :     int32_t index1 = combiningPattern.indexOf(bracketedOne,  3, 0);
    1309           0 :     if (index0 < 0 || index1 < 0) {
    1310           0 :         return;
    1311             :     }
    1312           0 :     int32_t placeholderLen = 3; // length of "{0}" or "{1}"
    1313           0 :     if (index0 < index1) {
    1314           0 :         if (pos0.getEndIndex() > 0) {
    1315           0 :             posResult.setBeginIndex(pos0.getBeginIndex() + index0);
    1316           0 :             posResult.setEndIndex(pos0.getEndIndex() + index0);
    1317           0 :         } else if (pos1.getEndIndex() > 0) {
    1318             :             // here index1 >= 3
    1319           0 :             index1 += pat0.length() - placeholderLen; // adjust for pat0 replacing {0}
    1320           0 :             posResult.setBeginIndex(pos1.getBeginIndex() + index1);
    1321           0 :             posResult.setEndIndex(pos1.getEndIndex() + index1);
    1322             :         }
    1323             :     } else {
    1324           0 :         if (pos1.getEndIndex() > 0) {
    1325           0 :             posResult.setBeginIndex(pos1.getBeginIndex() + index1);
    1326           0 :             posResult.setEndIndex(pos1.getEndIndex() + index1);
    1327           0 :         } else if (pos0.getEndIndex() > 0) {
    1328             :             // here index0 >= 3
    1329           0 :             index0 += pat1.length() - placeholderLen; // adjust for pat1 replacing {1}
    1330           0 :             posResult.setBeginIndex(pos0.getBeginIndex() + index0);
    1331           0 :             posResult.setEndIndex(pos0.getEndIndex() + index0);
    1332             :         }
    1333             :     }
    1334             : }
    1335             : 
    1336             : UnicodeString&
    1337           0 : DateIntervalFormat::fallbackFormat(Calendar& fromCalendar,
    1338             :                                    Calendar& toCalendar,
    1339             :                                    UBool fromToOnSameDay, // new
    1340             :                                    UnicodeString& appendTo,
    1341             :                                    FieldPosition& pos,
    1342             :                                    UErrorCode& status) const {
    1343           0 :     if ( U_FAILURE(status) ) {
    1344           0 :         return appendTo;
    1345             :     }
    1346           0 :     UnicodeString fullPattern; // for saving the pattern in fDateFormat
    1347           0 :     UBool formatDatePlusTimeRange = (fromToOnSameDay && fDatePattern && fTimePattern);
    1348             :     // the fall back
    1349           0 :     if (formatDatePlusTimeRange) {
    1350           0 :         fDateFormat->toPattern(fullPattern); // save current pattern, restore later
    1351           0 :         fDateFormat->applyPattern(*fTimePattern);
    1352             :     }
    1353           0 :     FieldPosition otherPos;
    1354           0 :     otherPos.setField(pos.getField());
    1355           0 :     UnicodeString earlierDate;
    1356           0 :     fDateFormat->format(fromCalendar, earlierDate, pos);
    1357           0 :     UnicodeString laterDate;
    1358           0 :     fDateFormat->format(toCalendar, laterDate, otherPos);
    1359           0 :     UnicodeString fallbackPattern;
    1360           0 :     fInfo->getFallbackIntervalPattern(fallbackPattern);
    1361           0 :     adjustPosition(fallbackPattern, earlierDate, pos, laterDate, otherPos, pos);
    1362           0 :     UnicodeString fallbackRange;
    1363           0 :     SimpleFormatter(fallbackPattern, 2, 2, status).
    1364           0 :             format(earlierDate, laterDate, fallbackRange, status);
    1365           0 :     if ( U_SUCCESS(status) && formatDatePlusTimeRange ) {
    1366             :         // fallbackRange has just the time range, need to format the date part and combine that
    1367           0 :         fDateFormat->applyPattern(*fDatePattern);
    1368           0 :         UnicodeString datePortion;
    1369           0 :         otherPos.setBeginIndex(0);
    1370           0 :         otherPos.setEndIndex(0);
    1371           0 :         fDateFormat->format(fromCalendar, datePortion, otherPos);
    1372           0 :         adjustPosition(*fDateTimeFormat, fallbackRange, pos, datePortion, otherPos, pos);
    1373             :         const UnicodeString *values[2] = {
    1374             :             &fallbackRange,  // {0} is time range
    1375             :             &datePortion,  // {1} is single date portion
    1376           0 :         };
    1377           0 :         SimpleFormatter(*fDateTimeFormat, 2, 2, status).
    1378           0 :                 formatAndReplace(values, 2, fallbackRange, NULL, 0, status);
    1379             :     }
    1380           0 :     if ( U_SUCCESS(status) ) {
    1381           0 :         appendTo.append(fallbackRange);
    1382             :     }
    1383           0 :     if (formatDatePlusTimeRange) {
    1384             :         // restore full pattern
    1385           0 :         fDateFormat->applyPattern(fullPattern);
    1386             :     }
    1387           0 :     return appendTo;
    1388             : }
    1389             : 
    1390             : 
    1391             : 
    1392             : 
    1393             : UBool  U_EXPORT2
    1394           0 : DateIntervalFormat::fieldExistsInSkeleton(UCalendarDateFields field,
    1395             :                                           const UnicodeString& skeleton)
    1396             : {
    1397           0 :     const UChar fieldChar = fgCalendarFieldToPatternLetter[field];
    1398           0 :     return ( (skeleton.indexOf(fieldChar) == -1)?FALSE:TRUE ) ;
    1399             : }
    1400             : 
    1401             : 
    1402             : 
    1403             : void  U_EXPORT2
    1404           0 : DateIntervalFormat::adjustFieldWidth(const UnicodeString& inputSkeleton,
    1405             :                  const UnicodeString& bestMatchSkeleton,
    1406             :                  const UnicodeString& bestIntervalPattern,
    1407             :                  int8_t differenceInfo,
    1408             :                  UnicodeString& adjustedPtn) {
    1409           0 :     adjustedPtn = bestIntervalPattern;
    1410             :     int32_t inputSkeletonFieldWidth[] =
    1411             :     {
    1412             :     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
    1413             :              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1414             :     //   P   Q   R   S   T   U   V   W   X   Y   Z
    1415             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0,  0, 0, 0,
    1416             :     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
    1417             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1418             :     //   p   q   r   s   t   u   v   w   x   y   z
    1419             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
    1420           0 :     };
    1421             : 
    1422             :     int32_t bestMatchSkeletonFieldWidth[] =
    1423             :     {
    1424             :     //       A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
    1425             :              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1426             :     //   P   Q   R   S   T   U   V   W   X   Y   Z
    1427             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0, 0,  0, 0, 0,
    1428             :     //       a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
    1429             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1430             :     //   p   q   r   s   t   u   v   w   x   y   z
    1431             :          0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0
    1432           0 :     };
    1433             : 
    1434           0 :     DateIntervalInfo::parseSkeleton(inputSkeleton, inputSkeletonFieldWidth);
    1435           0 :     DateIntervalInfo::parseSkeleton(bestMatchSkeleton, bestMatchSkeletonFieldWidth);
    1436           0 :     if ( differenceInfo == 2 ) {
    1437           0 :         adjustedPtn.findAndReplace(UnicodeString((UChar)0x76 /* v */),
    1438           0 :                                    UnicodeString((UChar)0x7a /* z */));
    1439             :     }
    1440             : 
    1441           0 :     UBool inQuote = false;
    1442           0 :     UChar prevCh = 0;
    1443           0 :     int32_t count = 0;
    1444             : 
    1445           0 :     const int8_t PATTERN_CHAR_BASE = 0x41;
    1446             : 
    1447             :     // loop through the pattern string character by character
    1448           0 :     int32_t adjustedPtnLength = adjustedPtn.length();
    1449             :     int32_t i;
    1450           0 :     for (i = 0; i < adjustedPtnLength; ++i) {
    1451           0 :         UChar ch = adjustedPtn.charAt(i);
    1452           0 :         if (ch != prevCh && count > 0) {
    1453             :             // check the repeativeness of pattern letter
    1454           0 :             UChar skeletonChar = prevCh;
    1455           0 :             if ( skeletonChar ==  CAP_L ) {
    1456             :                 // there is no "L" (always be "M") in skeleton,
    1457             :                 // but there is "L" in pattern.
    1458             :                 // for skeleton "M+", the pattern might be "...L..."
    1459           0 :                 skeletonChar = CAP_M;
    1460             :             }
    1461           0 :             int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
    1462           0 :             int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
    1463           0 :             if ( fieldCount == count && inputFieldCount > fieldCount ) {
    1464           0 :                 count = inputFieldCount - fieldCount;
    1465             :                 int32_t j;
    1466           0 :                 for ( j = 0; j < count; ++j ) {
    1467           0 :                     adjustedPtn.insert(i, prevCh);
    1468             :                 }
    1469           0 :                 i += count;
    1470           0 :                 adjustedPtnLength += count;
    1471             :             }
    1472           0 :             count = 0;
    1473             :         }
    1474           0 :         if (ch == 0x0027 /*'*/) {
    1475             :             // Consecutive single quotes are a single quote literal,
    1476             :             // either outside of quotes or between quotes
    1477           0 :             if ((i+1) < adjustedPtn.length() && adjustedPtn.charAt(i+1) == 0x0027 /* ' */) {
    1478           0 :                 ++i;
    1479             :             } else {
    1480           0 :                 inQuote = ! inQuote;
    1481             :             }
    1482             :         }
    1483           0 :         else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/)
    1484           0 :                     || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) {
    1485             :             // ch is a date-time pattern character
    1486           0 :             prevCh = ch;
    1487           0 :             ++count;
    1488             :         }
    1489             :     }
    1490           0 :     if ( count > 0 ) {
    1491             :         // last item
    1492             :         // check the repeativeness of pattern letter
    1493           0 :         UChar skeletonChar = prevCh;
    1494           0 :         if ( skeletonChar == CAP_L ) {
    1495             :             // there is no "L" (always be "M") in skeleton,
    1496             :             // but there is "L" in pattern.
    1497             :             // for skeleton "M+", the pattern might be "...L..."
    1498           0 :             skeletonChar = CAP_M;
    1499             :         }
    1500           0 :         int32_t fieldCount = bestMatchSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
    1501           0 :         int32_t inputFieldCount = inputSkeletonFieldWidth[(int)(skeletonChar - PATTERN_CHAR_BASE)];
    1502           0 :         if ( fieldCount == count && inputFieldCount > fieldCount ) {
    1503           0 :             count = inputFieldCount - fieldCount;
    1504             :             int32_t j;
    1505           0 :             for ( j = 0; j < count; ++j ) {
    1506           0 :                 adjustedPtn.append(prevCh);
    1507             :             }
    1508             :         }
    1509             :     }
    1510           0 : }
    1511             : 
    1512             : 
    1513             : 
    1514             : void
    1515           0 : DateIntervalFormat::concatSingleDate2TimeInterval(UnicodeString& format,
    1516             :                                               const UnicodeString& datePattern,
    1517             :                                               UCalendarDateFields field,
    1518             :                                               UErrorCode& status) {
    1519             :     // following should not set wrong status
    1520           0 :     int32_t itvPtnIndex = DateIntervalInfo::calendarFieldToIntervalIndex(field,
    1521           0 :                                                                         status);
    1522           0 :     if ( U_FAILURE(status) ) {
    1523           0 :         return;
    1524             :     }
    1525           0 :     PatternInfo&  timeItvPtnInfo = fIntervalPatterns[itvPtnIndex];
    1526           0 :     if ( !timeItvPtnInfo.firstPart.isEmpty() ) {
    1527           0 :         UnicodeString timeIntervalPattern(timeItvPtnInfo.firstPart);
    1528           0 :         timeIntervalPattern.append(timeItvPtnInfo.secondPart);
    1529           0 :         UnicodeString combinedPattern;
    1530           0 :         SimpleFormatter(format, 2, 2, status).
    1531           0 :                 format(timeIntervalPattern, datePattern, combinedPattern, status);
    1532           0 :         if ( U_FAILURE(status) ) {
    1533           0 :             return;
    1534             :         }
    1535           0 :         setIntervalPattern(field, combinedPattern, timeItvPtnInfo.laterDateFirst);
    1536             :     }
    1537             :     // else: fall back
    1538             :     // it should not happen if the interval format defined is valid
    1539             : }
    1540             : 
    1541             : 
    1542             : 
    1543             : const UChar
    1544             : DateIntervalFormat::fgCalendarFieldToPatternLetter[] =
    1545             : {
    1546             :     /*GyM*/ CAP_G, LOW_Y, CAP_M,
    1547             :     /*wWd*/ LOW_W, CAP_W, LOW_D,
    1548             :     /*DEF*/ CAP_D, CAP_E, CAP_F,
    1549             :     /*ahH*/ LOW_A, LOW_H, CAP_H,
    1550             :     /*msS*/ LOW_M, LOW_S, CAP_S, // MINUTE, SECOND, MILLISECOND
    1551             :     /*z.Y*/ LOW_Z, SPACE, CAP_Y, // ZONE_OFFSET, DST_OFFSET, YEAR_WOY,
    1552             :     /*eug*/ LOW_E, LOW_U, LOW_G, // DOW_LOCAL, EXTENDED_YEAR, JULIAN_DAY,
    1553             :     /*A..*/ CAP_A, SPACE, SPACE, // MILLISECONDS_IN_DAY, IS_LEAP_MONTH, FIELD_COUNT
    1554             : };
    1555             : 
    1556             : 
    1557             : U_NAMESPACE_END
    1558             : 
    1559             : #endif

Generated by: LCOV version 1.13