1 /* 2 ******************************************************************************* 3 * Copyright (C) 2008-2011,2013, 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 29 U_NAMESPACE_BEGIN 30 31 /** 32 * DateIntervalInfo is a public class for encapsulating localizable 33 * date time interval patterns. It is used by DateIntervalFormat. 34 * 35 * <P> 36 * For most users, ordinary use of DateIntervalFormat does not need to create 37 * DateIntervalInfo object directly. 38 * DateIntervalFormat will take care of it when creating a date interval 39 * formatter when user pass in skeleton and locale. 40 * 41 * <P> 42 * For power users, who want to create their own date interval patterns, 43 * or want to re-set date interval patterns, they could do so by 44 * directly creating DateIntervalInfo and manupulating it. 45 * 46 * <P> 47 * Logically, the interval patterns are mappings 48 * from (skeleton, the_largest_different_calendar_field) 49 * to (date_interval_pattern). 50 * 51 * <P> 52 * A skeleton 53 * <ol> 54 * <li> 55 * only keeps the field pattern letter and ignores all other parts 56 * in a pattern, such as space, punctuations, and string literals. 57 * <li> 58 * hides the order of fields. 59 * <li> 60 * might hide a field's pattern letter length. 61 * 62 * For those non-digit calendar fields, the pattern letter length is 63 * important, such as MMM, MMMM, and MMMMM; EEE and EEEE, 64 * and the field's pattern letter length is honored. 65 * 66 * For the digit calendar fields, such as M or MM, d or dd, yy or yyyy, 67 * the field pattern length is ignored and the best match, which is defined 68 * in date time patterns, will be returned without honor the field pattern 69 * letter length in skeleton. 70 * </ol> 71 * 72 * <P> 73 * The calendar fields we support for interval formatting are: 74 * year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute. 75 * Those calendar fields can be defined in the following order: 76 * year > month > date > am-pm > hour > minute 77 * 78 * The largest different calendar fields between 2 calendars is the 79 * first different calendar field in above order. 80 * 81 * For example: the largest different calendar fields between "Jan 10, 2007" 82 * and "Feb 20, 2008" is year. 83 * 84 * <P> 85 * There is a set of pre-defined static skeleton strings. 86 * There are pre-defined interval patterns for those pre-defined skeletons 87 * in locales' resource files. 88 * For example, for a skeleton UDAT_YEAR_ABBR_MONTH_DAY, which is "yMMMd", 89 * in en_US, if the largest different calendar field between date1 and date2 90 * is "year", the date interval pattern is "MMM d, yyyy - MMM d, yyyy", 91 * such as "Jan 10, 2007 - Jan 10, 2008". 92 * If the largest different calendar field between date1 and date2 is "month", 93 * the date interval pattern is "MMM d - MMM d, yyyy", 94 * such as "Jan 10 - Feb 10, 2007". 95 * If the largest different calendar field between date1 and date2 is "day", 96 * the date interval pattern is "MMM d-d, yyyy", such as "Jan 10-20, 2007". 97 * 98 * For date skeleton, the interval patterns when year, or month, or date is 99 * different are defined in resource files. 100 * For time skeleton, the interval patterns when am/pm, or hour, or minute is 101 * different are defined in resource files. 102 * 103 * 104 * <P> 105 * There are 2 dates in interval pattern. For most locales, the first date 106 * in an interval pattern is the earlier date. There might be a locale in which 107 * the first date in an interval pattern is the later date. 108 * We use fallback format for the default order for the locale. 109 * For example, if the fallback format is "{0} - {1}", it means 110 * the first date in the interval pattern for this locale is earlier date. 111 * If the fallback format is "{1} - {0}", it means the first date is the 112 * later date. 113 * For a particular interval pattern, the default order can be overriden 114 * by prefixing "latestFirst:" or "earliestFirst:" to the interval pattern. 115 * For example, if the fallback format is "{0}-{1}", 116 * but for skeleton "yMMMd", the interval pattern when day is different is 117 * "latestFirst:d-d MMM yy", it means by default, the first date in interval 118 * pattern is the earlier date. But for skeleton "yMMMd", when day is different, 119 * the first date in "d-d MMM yy" is the later date. 120 * 121 * <P> 122 * The recommended way to create a DateIntervalFormat object is to pass in 123 * the locale. 124 * By using a Locale parameter, the DateIntervalFormat object is 125 * initialized with the pre-defined interval patterns for a given or 126 * default locale. 127 * <P> 128 * Users can also create DateIntervalFormat object 129 * by supplying their own interval patterns. 130 * It provides flexibility for power users. 131 * 132 * <P> 133 * After a DateIntervalInfo object is created, clients may modify 134 * the interval patterns using setIntervalPattern function as so desired. 135 * Currently, users can only set interval patterns when the following 136 * calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, 137 * DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE. 138 * Interval patterns when other calendar fields are different is not supported. 139 * <P> 140 * DateIntervalInfo objects are cloneable. 141 * When clients obtain a DateIntervalInfo object, 142 * they can feel free to modify it as necessary. 143 * <P> 144 * DateIntervalInfo are not expected to be subclassed. 145 * Data for a calendar is loaded out of resource bundles. 146 * Through ICU 4.4, date interval patterns are only supported in the Gregorian 147 * calendar; non-Gregorian calendars are supported from ICU 4.4.1. 148 * @stable ICU 4.0 149 **/ 150 151 class U_I18N_API DateIntervalInfo : public UObject { 152 public: 153 #ifndef U_HIDE_INTERNAL_API 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 #endif /* U_HIDE_INTERNAL_API */ 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 * Following is for saving the interval patterns. 344 * We only support interval patterns on 345 * ERA, YEAR, MONTH, DAY, AM_PM, HOUR, and MINUTE 346 */ 347 enum IntervalPatternIndex 348 { 349 kIPI_ERA, 350 kIPI_YEAR, 351 kIPI_MONTH, 352 kIPI_DATE, 353 kIPI_AM_PM, 354 kIPI_HOUR, 355 kIPI_MINUTE, 356 kIPI_MAX_INDEX 357 }; 358 public: 359 #ifndef U_HIDE_INTERNAL_API 360 /** 361 * Max index for stored interval patterns 362 * @internal ICU 4.4 363 */ 364 enum { 365 kMaxIntervalPatternIndex = kIPI_MAX_INDEX 366 }; 367 #endif /* U_HIDE_INTERNAL_API */ 368 private: 369 370 371 /** 372 * Initialize the DateIntervalInfo from locale 373 * @param locale the given locale. 374 * @param status output param set to success/failure code on exit 375 */ 376 void initializeData(const Locale& locale, UErrorCode& status); 377 378 379 /* Set Interval pattern. 380 * 381 * It sets interval pattern into the hash map. 382 * 383 * @param skeleton skeleton on which the interval pattern based 384 * @param lrgDiffCalUnit the largest different calendar unit. 385 * @param intervalPattern the interval pattern on the largest different 386 * calendar unit. 387 * @param status output param set to success/failure code on exit 388 */ 389 void setIntervalPatternInternally(const UnicodeString& skeleton, 390 UCalendarDateFields lrgDiffCalUnit, 391 const UnicodeString& intervalPattern, 392 UErrorCode& status); 393 394 395 /**given an input skeleton, get the best match skeleton 396 * which has pre-defined interval pattern in resource file. 397 * Also return the difference between the input skeleton 398 * and the best match skeleton. 399 * 400 * TODO (xji): set field weight or 401 * isolate the funtionality in DateTimePatternGenerator 402 * @param skeleton input skeleton 403 * @param bestMatchDistanceInfo the difference between input skeleton 404 * and best match skeleton. 405 * 0, if there is exact match for input skeleton 406 * 1, if there is only field width difference between 407 * the best match and the input skeleton 408 * 2, the only field difference is 'v' and 'z' 409 * -1, if there is calendar field difference between 410 * the best match and the input skeleton 411 * @return best match skeleton 412 */ 413 const UnicodeString* getBestSkeleton(const UnicodeString& skeleton, 414 int8_t& bestMatchDistanceInfo) const; 415 416 417 /** 418 * Parse skeleton, save each field's width. 419 * It is used for looking for best match skeleton, 420 * and adjust pattern field width. 421 * @param skeleton skeleton to be parsed 422 * @param skeletonFieldWidth parsed skeleton field width 423 */ 424 static void U_EXPORT2 parseSkeleton(const UnicodeString& skeleton, 425 int32_t* skeletonFieldWidth); 426 427 428 /** 429 * Check whether one field width is numeric while the other is string. 430 * 431 * TODO (xji): make it general 432 * 433 * @param fieldWidth one field width 434 * @param anotherFieldWidth another field width 435 * @param patternLetter pattern letter char 436 * @return true if one field width is numeric and the other is string, 437 * false otherwise. 438 */ 439 static UBool U_EXPORT2 stringNumeric(int32_t fieldWidth, 440 int32_t anotherFieldWidth, 441 char patternLetter); 442 443 444 /** 445 * Convert calendar field to the interval pattern index in 446 * hash table. 447 * 448 * Since we only support the following calendar fields: 449 * ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, DAY_OF_WEEK, 450 * AM_PM, HOUR, HOUR_OF_DAY, and MINUTE, 451 * We reserve only 4 interval patterns for a skeleton. 452 * 453 * @param field calendar field 454 * @param status output param set to success/failure code on exit 455 * @return interval pattern index in hash table 456 */ 457 static IntervalPatternIndex U_EXPORT2 calendarFieldToIntervalIndex( 458 UCalendarDateFields field, 459 UErrorCode& status); 460 461 462 /** 463 * delete hash table (of type fIntervalPatterns). 464 * 465 * @param hTable hash table to be deleted 466 */ 467 void deleteHash(Hashtable* hTable); 468 469 470 /** 471 * initialize hash table (of type fIntervalPatterns). 472 * 473 * @param status output param set to success/failure code on exit 474 * @return hash table initialized 475 */ 476 Hashtable* initHash(UErrorCode& status); 477 478 479 480 /** 481 * copy hash table (of type fIntervalPatterns). 482 * 483 * @param source the source to copy from 484 * @param target the target to copy to 485 * @param status output param set to success/failure code on exit 486 */ 487 void copyHash(const Hashtable* source, Hashtable* target, UErrorCode& status); 488 489 490 // data members 491 // fallback interval pattern 492 UnicodeString fFallbackIntervalPattern; 493 // default order 494 UBool fFirstDateInPtnIsLaterDate; 495 496 // HashMap<UnicodeString, UnicodeString[kIPI_MAX_INDEX]> 497 // HashMap( skeleton, pattern[largest_different_field] ) 498 Hashtable* fIntervalPatterns; 499 500 };// end class DateIntervalInfo 501 502 503 inline UBool 504 DateIntervalInfo::operator!=(const DateIntervalInfo& other) const { 505 return !operator==(other); 506 } 507 508 509 U_NAMESPACE_END 510 511 #endif 512 513 #endif 514 515