1 // © 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 class U_I18N_API DateIntervalInfo U_FINAL : public UObject {
153 public:
154     /**
155      * Default constructor.
156      * It does not initialize any interval patterns except
157      * that it initialize default fall-back pattern as "{0} - {1}",
158      * which can be reset by setFallbackIntervalPattern().
159      * It should be followed by setFallbackIntervalPattern() and
160      * setIntervalPattern(),
161      * and is recommended to be used only for power users who
162      * wants to create their own interval patterns and use them to create
163      * date interval formatter.
164      * @param status   output param set to success/failure code on exit
165      * @internal ICU 4.0
166      */
167     DateIntervalInfo(UErrorCode& status);
168 
169 
170     /**
171      * Construct DateIntervalInfo for the given locale,
172      * @param locale  the interval patterns are loaded from the appropriate calendar
173      *                data (specified calendar or default calendar) in this locale.
174      * @param status  output param set to success/failure code on exit
175      * @stable ICU 4.0
176      */
177     DateIntervalInfo(const Locale& locale, UErrorCode& status);
178 
179 
180     /**
181      * Copy constructor.
182      * @stable ICU 4.0
183      */
184     DateIntervalInfo(const DateIntervalInfo&);
185 
186     /**
187      * Assignment operator
188      * @stable ICU 4.0
189      */
190     DateIntervalInfo& operator=(const DateIntervalInfo&);
191 
192     /**
193      * Clone this object polymorphically.
194      * The caller owns the result and should delete it when done.
195      * @return   a copy of the object
196      * @stable ICU 4.0
197      */
198     virtual DateIntervalInfo* clone(void) const;
199 
200     /**
201      * Destructor.
202      * It is virtual to be safe, but it is not designed to be subclassed.
203      * @stable ICU 4.0
204      */
205     virtual ~DateIntervalInfo();
206 
207 
208     /**
209      * Return true if another object is semantically equal to this one.
210      *
211      * @param other    the DateIntervalInfo object to be compared with.
212      * @return         true if other is semantically equal to this.
213      * @stable ICU 4.0
214      */
215     virtual UBool operator==(const DateIntervalInfo& other) const;
216 
217     /**
218      * Return true if another object is semantically unequal to this one.
219      *
220      * @param other    the DateIntervalInfo object to be compared with.
221      * @return         true if other is semantically unequal to this.
222      * @stable ICU 4.0
223      */
224     UBool operator!=(const DateIntervalInfo& other) const;
225 
226 
227 
228     /**
229      * Provides a way for client to build interval patterns.
230      * User could construct DateIntervalInfo by providing a list of skeletons
231      * and their patterns.
232      * <P>
233      * For example:
234      * <pre>
235      * UErrorCode status = U_ZERO_ERROR;
236      * DateIntervalInfo dIntervalInfo = new DateIntervalInfo();
237      * dIntervalInfo->setFallbackIntervalPattern("{0} ~ {1}");
238      * dIntervalInfo->setIntervalPattern("yMd", UCAL_YEAR, "'from' yyyy-M-d 'to' yyyy-M-d", status);
239      * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_MONTH, "'from' yyyy MMM d 'to' MMM d", status);
240      * dIntervalInfo->setIntervalPattern("yMMMd", UCAL_DAY, "yyyy MMM d-d", status, status);
241      * </pre>
242      *
243      * Restriction:
244      * Currently, users can only set interval patterns when the following
245      * calendar fields are different: ERA, YEAR, MONTH, DATE,  DAY_OF_MONTH,
246      * DAY_OF_WEEK, AM_PM,  HOUR, HOUR_OF_DAY, and MINUTE.
247      * Interval patterns when other calendar fields are different are
248      * not supported.
249      *
250      * @param skeleton         the skeleton on which interval pattern based
251      * @param lrgDiffCalUnit   the largest different calendar unit.
252      * @param intervalPattern  the interval pattern on the largest different
253      *                         calendar unit.
254      *                         For example, if lrgDiffCalUnit is
255      *                         "year", the interval pattern for en_US when year
256      *                         is different could be "'from' yyyy 'to' yyyy".
257      * @param status           output param set to success/failure code on exit
258      * @stable ICU 4.0
259      */
260     void setIntervalPattern(const UnicodeString& skeleton,
261                             UCalendarDateFields lrgDiffCalUnit,
262                             const UnicodeString& intervalPattern,
263                             UErrorCode& status);
264 
265     /**
266      * Get the interval pattern given skeleton and
267      * the largest different calendar field.
268      * @param skeleton   the skeleton
269      * @param field      the largest different calendar field
270      * @param result     output param to receive the pattern
271      * @param status     output param set to success/failure code on exit
272      * @return a reference to 'result'
273      * @stable ICU 4.0
274      */
275     UnicodeString& getIntervalPattern(const UnicodeString& skeleton,
276                                       UCalendarDateFields field,
277                                       UnicodeString& result,
278                                       UErrorCode& status) const;
279 
280     /**
281      * Get the fallback interval pattern.
282      * @param  result   output param to receive the pattern
283      * @return a reference to 'result'
284      * @stable ICU 4.0
285      */
286     UnicodeString& getFallbackIntervalPattern(UnicodeString& result) const;
287 
288 
289     /**
290      * Re-set the fallback interval pattern.
291      *
292      * In construction, default fallback pattern is set as "{0} - {1}".
293      * And constructor taking locale as parameter will set the
294      * fallback pattern as what defined in the locale resource file.
295      *
296      * This method provides a way for user to replace the fallback pattern.
297      *
298      * @param fallbackPattern  fall-back interval pattern.
299      * @param status           output param set to success/failure code on exit
300      * @stable ICU 4.0
301      */
302     void setFallbackIntervalPattern(const UnicodeString& fallbackPattern,
303                                     UErrorCode& status);
304 
305 
306     /** Get default order -- whether the first date in pattern is later date
307                              or not.
308      * return default date ordering in interval pattern. TRUE if the first date
309      *        in pattern is later date, FALSE otherwise.
310      * @stable ICU 4.0
311      */
312     UBool getDefaultOrder() const;
313 
314 
315     /**
316      * ICU "poor man's RTTI", returns a UClassID for the actual class.
317      *
318      * @stable ICU 4.0
319      */
320     virtual UClassID getDynamicClassID() const;
321 
322     /**
323      * ICU "poor man's RTTI", returns a UClassID for this class.
324      *
325      * @stable ICU 4.0
326      */
327     static UClassID U_EXPORT2 getStaticClassID();
328 
329 
330 private:
331     /**
332      * DateIntervalFormat will need access to
333      * getBestSkeleton(), parseSkeleton(), enum IntervalPatternIndex,
334      * and calendarFieldToPatternIndex().
335      *
336      * Instead of making above public,
337      * make DateIntervalFormat a friend of DateIntervalInfo.
338      */
339     friend class DateIntervalFormat;
340 
341     /**
342      * Internal struct used to load resource bundle data.
343      */
344     struct DateIntervalSink;
345 
346     /**
347      * Following is for saving the interval patterns.
348      * We only support interval patterns on
349      * ERA, YEAR, MONTH, DAY, AM_PM, HOUR, and MINUTE
350      */
351     enum IntervalPatternIndex
352     {
353         kIPI_ERA,
354         kIPI_YEAR,
355         kIPI_MONTH,
356         kIPI_DATE,
357         kIPI_AM_PM,
358         kIPI_HOUR,
359         kIPI_MINUTE,
360         kIPI_SECOND,
361         kIPI_MAX_INDEX
362     };
363 public:
364 #ifndef U_HIDE_INTERNAL_API
365     /**
366      * Max index for stored interval patterns
367      * @internal ICU 4.4
368      */
369      enum {
370          kMaxIntervalPatternIndex = kIPI_MAX_INDEX
371      };
372 #endif  /* U_HIDE_INTERNAL_API */
373 private:
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      */
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      */
394     void setIntervalPatternInternally(const UnicodeString& skeleton,
395                                       UCalendarDateFields lrgDiffCalUnit,
396                                       const UnicodeString& intervalPattern,
397                                       UErrorCode& status);
398 
399 
400     /**given an input skeleton, get the best match skeleton
401      * which has pre-defined interval pattern in resource file.
402      * Also return the difference between the input skeleton
403      * and the best match skeleton.
404      *
405      * TODO (xji): set field weight or
406      *             isolate the funtionality in DateTimePatternGenerator
407      * @param  skeleton               input skeleton
408      * @param  bestMatchDistanceInfo  the difference between input skeleton
409      *                                and best match skeleton.
410      *         0, if there is exact match for input skeleton
411      *         1, if there is only field width difference between
412      *            the best match and the input skeleton
413      *         2, the only field difference is 'v' and 'z'
414      *        -1, if there is calendar field difference between
415      *            the best match and the input skeleton
416      * @return                        best match skeleton
417      */
418     const UnicodeString* getBestSkeleton(const UnicodeString& skeleton,
419                                          int8_t& bestMatchDistanceInfo) const;
420 
421 
422     /**
423      * Parse skeleton, save each field's width.
424      * It is used for looking for best match skeleton,
425      * and adjust pattern field width.
426      * @param skeleton            skeleton to be parsed
427      * @param skeletonFieldWidth  parsed skeleton field width
428      */
429     static void U_EXPORT2 parseSkeleton(const UnicodeString& skeleton,
430                                         int32_t* skeletonFieldWidth);
431 
432 
433     /**
434      * Check whether one field width is numeric while the other is string.
435      *
436      * TODO (xji): make it general
437      *
438      * @param fieldWidth          one field width
439      * @param anotherFieldWidth   another field width
440      * @param patternLetter       pattern letter char
441      * @return true if one field width is numeric and the other is string,
442      *         false otherwise.
443      */
444     static UBool U_EXPORT2 stringNumeric(int32_t fieldWidth,
445                                          int32_t anotherFieldWidth,
446                                          char patternLetter);
447 
448 
449     /**
450      * Convert calendar field to the interval pattern index in
451      * hash table.
452      *
453      * Since we only support the following calendar fields:
454      * ERA, YEAR, MONTH, DATE,  DAY_OF_MONTH, DAY_OF_WEEK,
455      * AM_PM,  HOUR, HOUR_OF_DAY, and MINUTE,
456      * We reserve only 4 interval patterns for a skeleton.
457      *
458      * @param field    calendar field
459      * @param status   output param set to success/failure code on exit
460      * @return  interval pattern index in hash table
461      */
462     static IntervalPatternIndex U_EXPORT2 calendarFieldToIntervalIndex(
463                                                       UCalendarDateFields field,
464                                                       UErrorCode& status);
465 
466 
467     /**
468      * delete hash table (of type fIntervalPatterns).
469      *
470      * @param hTable  hash table to be deleted
471      */
472     void deleteHash(Hashtable* hTable);
473 
474 
475     /**
476      * initialize hash table (of type fIntervalPatterns).
477      *
478      * @param status   output param set to success/failure code on exit
479      * @return         hash table initialized
480      */
481     Hashtable* initHash(UErrorCode& status);
482 
483 
484 
485     /**
486      * copy hash table (of type fIntervalPatterns).
487      *
488      * @param source   the source to copy from
489      * @param target   the target to copy to
490      * @param status   output param set to success/failure code on exit
491      */
492     void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status);
493 
494 
495     // data members
496     // fallback interval pattern
497     UnicodeString fFallbackIntervalPattern;
498     // default order
499     UBool fFirstDateInPtnIsLaterDate;
500 
501     // HashMap<UnicodeString, UnicodeString[kIPI_MAX_INDEX]>
502     // HashMap( skeleton, pattern[largest_different_field] )
503     Hashtable* fIntervalPatterns;
504 
505 };// end class DateIntervalInfo
506 
507 
508 inline UBool
509 DateIntervalInfo::operator!=(const DateIntervalInfo& other) const {
510     return !operator==(other);
511 }
512 
513 
514 U_NAMESPACE_END
515 
516 #endif
517 
518 #endif
519