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