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