Home | History | Annotate | Download | only in unicode
      1 /*
      2  *******************************************************************************
      3  * Copyright (C) 2008-2010, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  *******************************************************************************
      6  *
      7  * File DTITVINF.H
      8  *
      9  *******************************************************************************
     10  */
     11 
     12 #ifndef __DTITVINF_H__
     13 #define __DTITVINF_H__
     14 
     15 #include "unicode/utypes.h"
     16 
     17 /**
     18  * \file
     19  * \brief C++ API: Date/Time interval patterns for formatting date/time interval
     20  */
     21 
     22 #if !UCONFIG_NO_FORMATTING
     23 
     24 #include "unicode/udat.h"
     25 #include "unicode/locid.h"
     26 #include "unicode/ucal.h"
     27 #include "unicode/dtptngen.h"
     28 //#include "dtitv_impl.h"
     29 
     30 /**
     31  * @internal ICU 4.0
     32  */
     33 
     34 union UHashTok;
     35 
     36 
     37 U_NAMESPACE_BEGIN
     38 
     39 /**
     40  * DateIntervalInfo is a public class for encapsulating localizable
     41  * date time interval patterns. It is used by DateIntervalFormat.
     42  *
     43  * <P>
     44  * For most users, ordinary use of DateIntervalFormat does not need to create
     45  * DateIntervalInfo object directly.
     46  * DateIntervalFormat will take care of it when creating a date interval
     47  * formatter when user pass in skeleton and locale.
     48  *
     49  * <P>
     50  * For power users, who want to create their own date interval patterns,
     51  * or want to re-set date interval patterns, they could do so by
     52  * directly creating DateIntervalInfo and manupulating it.
     53  *
     54  * <P>
     55  * Logically, the interval patterns are mappings
     56  * from (skeleton, the_largest_different_calendar_field)
     57  * to (date_interval_pattern).
     58  *
     59  * <P>
     60  * A skeleton
     61  * <ol>
     62  * <li>
     63  * only keeps the field pattern letter and ignores all other parts
     64  * in a pattern, such as space, punctuations, and string literals.
     65  * <li>
     66  * hides the order of fields.
     67  * <li>
     68  * might hide a field's pattern letter length.
     69  *
     70  * For those non-digit calendar fields, the pattern letter length is
     71  * important, such as MMM, MMMM, and MMMMM; EEE and EEEE,
     72  * and the field's pattern letter length is honored.
     73  *
     74  * For the digit calendar fields,  such as M or MM, d or dd, yy or yyyy,
     75  * the field pattern length is ignored and the best match, which is defined
     76  * in date time patterns, will be returned without honor the field pattern
     77  * letter length in skeleton.
     78  * </ol>
     79  *
     80  * <P>
     81  * The calendar fields we support for interval formatting are:
     82  * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
     83  * Those calendar fields can be defined in the following order:
     84  * year >  month > date > am-pm > hour >  minute
     85  *
     86  * The largest different calendar fields between 2 calendars is the
     87  * first different calendar field in above order.
     88  *
     89  * For example: the largest different calendar fields between &quot;Jan 10, 2007&quot;
     90  * and &quot;Feb 20, 2008&quot; is year.
     91  *
     92  * <P>
     93  * There is a set of pre-defined static skeleton strings.
     94  * There are pre-defined interval patterns for those pre-defined skeletons
     95  * in locales' resource files.
     96  * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is  &quot;yMMMd&quot;,
     97  * in  en_US, if the largest different calendar field between date1 and date2
     98  * is &quot;year&quot;, the date interval pattern  is &quot;MMM d, yyyy - MMM d, yyyy&quot;,
     99  * such as &quot;Jan 10, 2007 - Jan 10, 2008&quot;.
    100  * If the largest different calendar field between date1 and date2 is &quot;month&quot;,
    101  * the date interval pattern is &quot;MMM d - MMM d, yyyy&quot;,
    102  * such as &quot;Jan 10 - Feb 10, 2007&quot;.
    103  * If the largest different calendar field between date1 and date2 is &quot;day&quot;,
    104  * the date interval pattern is &quot;MMM d-d, yyyy&quot;, such as &quot;Jan 10-20, 2007&quot;.
    105  *
    106  * For date skeleton, the interval patterns when year, or month, or date is
    107  * different are defined in resource files.
    108  * For time skeleton, the interval patterns when am/pm, or hour, or minute is
    109  * different are defined in resource files.
    110  *
    111  *
    112  * <P>
    113  * There are 2 dates in interval pattern. For most locales, the first date
    114  * in an interval pattern is the earlier date. There might be a locale in which
    115  * the first date in an interval pattern is the later date.
    116  * We use fallback format for the default order for the locale.
    117  * For example, if the fallback format is &quot;{0} - {1}&quot;, it means
    118  * the first date in the interval pattern for this locale is earlier date.
    119  * If the fallback format is &quot;{1} - {0}&quot;, it means the first date is the
    120  * later date.
    121  * For a particular interval pattern, the default order can be overriden
    122  * by prefixing &quot;latestFirst:&quot; or &quot;earliestFirst:&quot; to the interval pattern.
    123  * For example, if the fallback format is &quot;{0}-{1}&quot;,
    124  * but for skeleton &quot;yMMMd&quot;, the interval pattern when day is different is
    125  * &quot;latestFirst:d-d MMM yy&quot;, it means by default, the first date in interval
    126  * pattern is the earlier date. But for skeleton &quot;yMMMd&quot;, when day is different,
    127  * the first date in &quot;d-d MMM yy&quot; is the later date.
    128  *
    129  * <P>
    130  * The recommended way to create a DateIntervalFormat object is to pass in
    131  * the locale.
    132  * By using a Locale parameter, the DateIntervalFormat object is
    133  * initialized with the pre-defined interval patterns for a given or
    134  * default locale.
    135  * <P>
    136  * Users can also create DateIntervalFormat object
    137  * by supplying their own interval patterns.
    138  * It provides flexibility for power users.
    139  *
    140  * <P>
    141  * After a DateIntervalInfo object is created, clients may modify
    142  * the interval patterns using setIntervalPattern function as so desired.
    143  * Currently, users can only set interval patterns when the following
    144  * calendar fields are different: ERA, YEAR, MONTH, DATE,  DAY_OF_MONTH,
    145  * DAY_OF_WEEK, AM_PM,  HOUR, HOUR_OF_DAY, and MINUTE.
    146  * Interval patterns when other calendar fields are different is not supported.
    147  * <P>
    148  * DateIntervalInfo objects are cloneable.
    149  * When clients obtain a DateIntervalInfo object,
    150  * they can feel free to modify it as necessary.
    151  * <P>
    152  * DateIntervalInfo are not expected to be subclassed.
    153  * Data for a calendar is loaded out of resource bundles.
    154  * Through ICU 4.4, date interval patterns are only supported in the Gregorian
    155  * calendar; non-Gregorian calendars are supported from ICU 4.4.1.
    156  * @stable ICU 4.0
    157 **/
    158 
    159 class U_I18N_API DateIntervalInfo : public UObject {
    160 public:
    161     /**
    162      * Default constructor.
    163      * It does not initialize any interval patterns except
    164      * that it initialize default fall-back pattern as "{0} - {1}",
    165      * which can be reset by setFallbackIntervalPattern().
    166      * It should be followed by setFallbackIntervalPattern() and
    167      * setIntervalPattern(),
    168      * and is recommended to be used only for power users who
    169      * wants to create their own interval patterns and use them to create
    170      * date interval formatter.
    171      * @param status   output param set to success/failure code on exit
    172      * @internal ICU 4.0
    173      */
    174     DateIntervalInfo(UErrorCode& status);
    175 
    176 
    177     /**
    178      * Construct DateIntervalInfo for the given locale,
    179      * @param locale  the interval patterns are loaded from the appropriate calendar
    180      *                data (specified calendar or default calendar) in this locale.
    181      * @param status  output param set to success/failure code on exit
    182      * @stable ICU 4.0
    183      */
    184     DateIntervalInfo(const Locale& locale, UErrorCode& status);
    185 
    186 
    187     /**
    188      * Copy constructor.
    189      * @stable ICU 4.0
    190      */
    191     DateIntervalInfo(const DateIntervalInfo&);
    192 
    193     /**
    194      * Assignment operator
    195      * @stable ICU 4.0
    196      */
    197     DateIntervalInfo& operator=(const DateIntervalInfo&);
    198 
    199     /**
    200      * Clone this object polymorphically.
    201      * The caller owns the result and should delete it when done.
    202      * @return   a copy of the object
    203      * @stable ICU 4.0
    204      */
    205     virtual DateIntervalInfo* clone(void) const;
    206 
    207     /**
    208      * Destructor.
    209      * It is virtual to be safe, but it is not designed to be subclassed.
    210      * @stable ICU 4.0
    211      */
    212     virtual ~DateIntervalInfo();
    213 
    214 
    215     /**
    216      * Return true if another object is semantically equal to this one.
    217      *
    218      * @param other    the DateIntervalInfo object to be compared with.
    219      * @return         true if other is semantically equal to this.
    220      * @stable ICU 4.0
    221      */
    222     virtual UBool operator==(const DateIntervalInfo& other) const;
    223 
    224     /**
    225      * Return true if another object is semantically unequal to this one.
    226      *
    227      * @param other    the DateIntervalInfo object to be compared with.
    228      * @return         true if other is semantically unequal to this.
    229      * @stable ICU 4.0
    230      */
    231     UBool operator!=(const DateIntervalInfo& other) const;
    232 
    233 
    234 
    235     /**
    236      * Provides a way for client to build interval patterns.
    237      * User could construct DateIntervalInfo by providing a list of skeletons
    238      * and their patterns.
    239      * <P>
    240      * For example:
    241      * <pre>
    242      * UErrorCode status = U_ZERO_ERROR;
    243      * DateIntervalInfo dIntervalInfo = new DateIntervalInfo();
    244      * dIntervalInfo->setFallbackIntervalPattern("{0} ~ {1}");
    245      * dIntervalInfo->setIntervalPattern("yMd", UCAL_YEAR, "'from' yyyy-M-d 'to' yyyy-M-d", status);
    246      * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_MONTH, "'from' yyyy MMM d 'to' MMM d", status);
    247      * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_DAY, "yyyy MMM d-d", status, status);
    248      * </pre>
    249      *
    250      * Restriction:
    251      * Currently, users can only set interval patterns when the following
    252      * calendar fields are different: ERA, YEAR, MONTH, DATE,  DAY_OF_MONTH,
    253      * DAY_OF_WEEK, AM_PM,  HOUR, HOUR_OF_DAY, and MINUTE.
    254      * Interval patterns when other calendar fields are different are
    255      * not supported.
    256      *
    257      * @param skeleton         the skeleton on which interval pattern based
    258      * @param lrgDiffCalUnit   the largest different calendar unit.
    259      * @param intervalPattern  the interval pattern on the largest different
    260      *                         calendar unit.
    261      *                         For example, if lrgDiffCalUnit is
    262      *                         "year", the interval pattern for en_US when year
    263      *                         is different could be "'from' yyyy 'to' yyyy".
    264      * @param status           output param set to success/failure code on exit
    265      * @stable ICU 4.0
    266      */
    267     void setIntervalPattern(const UnicodeString& skeleton,
    268                             UCalendarDateFields lrgDiffCalUnit,
    269                             const UnicodeString& intervalPattern,
    270                             UErrorCode& status);
    271 
    272     /**
    273      * Get the interval pattern given skeleton and
    274      * the largest different calendar field.
    275      * @param skeleton   the skeleton
    276      * @param field      the largest different calendar field
    277      * @param result     output param to receive the pattern
    278      * @param status     output param set to success/failure code on exit
    279      * @return a reference to 'result'
    280      * @stable ICU 4.0
    281      */
    282     UnicodeString& getIntervalPattern(const UnicodeString& skeleton,
    283                                       UCalendarDateFields field,
    284                                       UnicodeString& result,
    285                                       UErrorCode& status) const;
    286 
    287     /**
    288      * Get the fallback interval pattern.
    289      * @param  result   output param to receive the pattern
    290      * @return a reference to 'result'
    291      * @stable ICU 4.0
    292      */
    293     UnicodeString& getFallbackIntervalPattern(UnicodeString& result) const;
    294 
    295 
    296     /**
    297      * Re-set the fallback interval pattern.
    298      *
    299      * In construction, default fallback pattern is set as "{0} - {1}".
    300      * And constructor taking locale as parameter will set the
    301      * fallback pattern as what defined in the locale resource file.
    302      *
    303      * This method provides a way for user to replace the fallback pattern.
    304      *
    305      * @param fallbackPattern  fall-back interval pattern.
    306      * @param status           output param set to success/failure code on exit
    307      * @stable ICU 4.0
    308      */
    309     void setFallbackIntervalPattern(const UnicodeString& fallbackPattern,
    310                                     UErrorCode& status);
    311 
    312 
    313     /** Get default order -- whether the first date in pattern is later date
    314                              or not.
    315      * return default date ordering in interval pattern. TRUE if the first date
    316      *        in pattern is later date, FALSE otherwise.
    317      * @stable ICU 4.0
    318      */
    319     UBool getDefaultOrder() const;
    320 
    321 
    322     /**
    323      * ICU "poor man's RTTI", returns a UClassID for the actual class.
    324      *
    325      * @stable ICU 4.0
    326      */
    327     virtual UClassID getDynamicClassID() const;
    328 
    329     /**
    330      * ICU "poor man's RTTI", returns a UClassID for this class.
    331      *
    332      * @stable ICU 4.0
    333      */
    334     static UClassID U_EXPORT2 getStaticClassID();
    335 
    336 
    337 private:
    338     /**
    339      * DateIntervalFormat will need access to
    340      * getBestSkeleton(), parseSkeleton(), enum IntervalPatternIndex,
    341      * and calendarFieldToPatternIndex().
    342      *
    343      * Instead of making above public,
    344      * make DateIntervalFormat a friend of DateIntervalInfo.
    345      */
    346     friend class DateIntervalFormat;
    347 
    348     /**
    349      * Following is for saving the interval patterns.
    350      * We only support interval patterns on
    351      * ERA, YEAR, MONTH, DAY, AM_PM, HOUR, and MINUTE
    352      */
    353     enum IntervalPatternIndex
    354     {
    355         kIPI_ERA,
    356         kIPI_YEAR,
    357         kIPI_MONTH,
    358         kIPI_DATE,
    359         kIPI_AM_PM,
    360         kIPI_HOUR,
    361         kIPI_MINUTE,
    362         kIPI_MAX_INDEX
    363     };
    364 public:
    365     /**
    366      * Max index for stored interval patterns
    367      * @internal ICU 4.4
    368      */
    369      enum {
    370      	kMaxIntervalPatternIndex = kIPI_MAX_INDEX
    371      };
    372 private:
    373 
    374 
    375     /**
    376      * Initialize the DateIntervalInfo from locale
    377      * @param locale   the given locale.
    378      * @param status   output param set to success/failure code on exit
    379      * @internal ICU 4.0
    380      */
    381     void initializeData(const Locale& locale, UErrorCode& status);
    382 
    383 
    384     /* Set Interval pattern.
    385      *
    386      * It sets interval pattern into the hash map.
    387      *
    388      * @param skeleton         skeleton on which the interval pattern based
    389      * @param lrgDiffCalUnit   the largest different calendar unit.
    390      * @param intervalPattern  the interval pattern on the largest different
    391      *                         calendar unit.
    392      * @param status           output param set to success/failure code on exit
    393      * @internal ICU 4.0
    394      */
    395     void setIntervalPatternInternally(const UnicodeString& skeleton,
    396                                       UCalendarDateFields lrgDiffCalUnit,
    397                                       const UnicodeString& intervalPattern,
    398                                       UErrorCode& status);
    399 
    400 
    401     /**given an input skeleton, get the best match skeleton
    402      * which has pre-defined interval pattern in resource file.
    403      * Also return the difference between the input skeleton
    404      * and the best match skeleton.
    405      *
    406      * TODO (xji): set field weight or
    407      *             isolate the funtionality in DateTimePatternGenerator
    408      * @param  skeleton               input skeleton
    409      * @param  bestMatchDistanceInfo  the difference between input skeleton
    410      *                                and best match skeleton.
    411      *         0, if there is exact match for input skeleton
    412      *         1, if there is only field width difference between
    413      *            the best match and the input skeleton
    414      *         2, the only field difference is 'v' and 'z'
    415      *        -1, if there is calendar field difference between
    416      *            the best match and the input skeleton
    417      * @return                        best match skeleton
    418      * @internal ICU 4.0
    419      */
    420     const UnicodeString* getBestSkeleton(const UnicodeString& skeleton,
    421                                          int8_t& bestMatchDistanceInfo) const;
    422 
    423 
    424     /**
    425      * Parse skeleton, save each field's width.
    426      * It is used for looking for best match skeleton,
    427      * and adjust pattern field width.
    428      * @param skeleton            skeleton to be parsed
    429      * @param skeletonFieldWidth  parsed skeleton field width
    430      * @internal ICU 4.0
    431      */
    432     static void U_EXPORT2 parseSkeleton(const UnicodeString& skeleton,
    433                                         int32_t* skeletonFieldWidth);
    434 
    435 
    436     /**
    437      * Check whether one field width is numeric while the other is string.
    438      *
    439      * TODO (xji): make it general
    440      *
    441      * @param fieldWidth          one field width
    442      * @param anotherFieldWidth   another field width
    443      * @param patternLetter       pattern letter char
    444      * @return true if one field width is numeric and the other is string,
    445      *         false otherwise.
    446      * @internal ICU 4.0
    447      */
    448     static UBool U_EXPORT2 stringNumeric(int32_t fieldWidth,
    449                                          int32_t anotherFieldWidth,
    450                                          char patternLetter);
    451 
    452 
    453     /**
    454      * Convert calendar field to the interval pattern index in
    455      * hash table.
    456      *
    457      * Since we only support the following calendar fields:
    458      * ERA, YEAR, MONTH, DATE,  DAY_OF_MONTH, DAY_OF_WEEK,
    459      * AM_PM,  HOUR, HOUR_OF_DAY, and MINUTE,
    460      * We reserve only 4 interval patterns for a skeleton.
    461      *
    462      * @param field    calendar field
    463      * @param status   output param set to success/failure code on exit
    464      * @return  interval pattern index in hash table
    465      * @internal ICU 4.0
    466      */
    467     static IntervalPatternIndex U_EXPORT2 calendarFieldToIntervalIndex(
    468                                                       UCalendarDateFields field,
    469                                                       UErrorCode& status);
    470 
    471 
    472     /**
    473      * delete hash table (of type fIntervalPatterns).
    474      *
    475      * @param hTable  hash table to be deleted
    476      * @internal ICU 4.0
    477      */
    478     void deleteHash(Hashtable* hTable);
    479 
    480 
    481     /**
    482      * initialize hash table (of type fIntervalPatterns).
    483      *
    484      * @param status   output param set to success/failure code on exit
    485      * @return         hash table initialized
    486      * @internal ICU 4.0
    487      */
    488     Hashtable* initHash(UErrorCode& status);
    489 
    490 
    491 
    492     /**
    493      * copy hash table (of type fIntervalPatterns).
    494      *
    495      * @param source   the source to copy from
    496      * @param target   the target to copy to
    497      * @param status   output param set to success/failure code on exit
    498      * @internal ICU 4.0
    499      */
    500     void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
    501 
    502 
    503     // data members
    504     // fallback interval pattern
    505     UnicodeString fFallbackIntervalPattern;
    506     // default order
    507     UBool fFirstDateInPtnIsLaterDate;
    508 
    509     // HashMap<UnicodeString, UnicodeString[kIPI_MAX_INDEX]>
    510     // HashMap( skeleton, pattern[largest_different_field] )
    511     Hashtable* fIntervalPatterns;
    512 
    513 };// end class DateIntervalInfo
    514 
    515 
    516 inline UBool
    517 DateIntervalInfo::operator!=(const DateIntervalInfo& other) const {
    518     return !operator==(other);
    519 }
    520 
    521 
    522 U_NAMESPACE_END
    523 
    524 #endif
    525 
    526 #endif
    527 
    528