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