1 /* 2 ******************************************************************************* 3 * Copyright (C) 1997-2015, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 * 7 * File SMPDTFMT.CPP 8 * 9 * Modification History: 10 * 11 * Date Name Description 12 * 02/19/97 aliu Converted from java. 13 * 03/31/97 aliu Modified extensively to work with 50 locales. 14 * 04/01/97 aliu Added support for centuries. 15 * 07/09/97 helena Made ParsePosition into a class. 16 * 07/21/98 stephen Added initializeDefaultCentury. 17 * Removed getZoneIndex (added in DateFormatSymbols) 18 * Removed subParseLong 19 * Removed chk 20 * 02/22/99 stephen Removed character literals for EBCDIC safety 21 * 10/14/99 aliu Updated 2-digit year parsing so that only "00" thru 22 * "99" are recognized. {j28 4182066} 23 * 11/15/99 weiv Added support for week of year/day of week format 24 ******************************************************************************** 25 */ 26 27 #define ZID_KEY_MAX 128 28 29 #include "unicode/utypes.h" 30 31 #if !UCONFIG_NO_FORMATTING 32 #include "unicode/smpdtfmt.h" 33 #include "unicode/dtfmtsym.h" 34 #include "unicode/ures.h" 35 #include "unicode/msgfmt.h" 36 #include "unicode/calendar.h" 37 #include "unicode/gregocal.h" 38 #include "unicode/timezone.h" 39 #include "unicode/decimfmt.h" 40 #include "unicode/dcfmtsym.h" 41 #include "unicode/uchar.h" 42 #include "unicode/uniset.h" 43 #include "unicode/ustring.h" 44 #include "unicode/basictz.h" 45 #include "unicode/simpletz.h" 46 #include "unicode/rbtz.h" 47 #include "unicode/tzfmt.h" 48 #include "unicode/utf16.h" 49 #include "unicode/vtzone.h" 50 #include "unicode/udisplaycontext.h" 51 #include "unicode/brkiter.h" 52 #include "olsontz.h" 53 #include "patternprops.h" 54 #include "fphdlimp.h" 55 #include "gregoimp.h" 56 #include "hebrwcal.h" 57 #include "cstring.h" 58 #include "uassert.h" 59 #include "cmemory.h" 60 #include "umutex.h" 61 #include <float.h> 62 #include "smpdtfst.h" 63 #include "sharednumberformat.h" 64 #include "ustr_imp.h" 65 66 #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL) 67 #include <stdio.h> 68 #endif 69 70 // ***************************************************************************** 71 // class SimpleDateFormat 72 // ***************************************************************************** 73 74 U_NAMESPACE_BEGIN 75 76 /** 77 * Last-resort string to use for "GMT" when constructing time zone strings. 78 */ 79 // For time zones that have no names, use strings GMT+minutes and 80 // GMT-minutes. For instance, in France the time zone is GMT+60. 81 // Also accepted are GMT+H:MM or GMT-H:MM. 82 // Currently not being used 83 //static const UChar gGmt[] = {0x0047, 0x004D, 0x0054, 0x0000}; // "GMT" 84 //static const UChar gGmtPlus[] = {0x0047, 0x004D, 0x0054, 0x002B, 0x0000}; // "GMT+" 85 //static const UChar gGmtMinus[] = {0x0047, 0x004D, 0x0054, 0x002D, 0x0000}; // "GMT-" 86 //static const UChar gDefGmtPat[] = {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */ 87 //static const UChar gDefGmtNegHmsPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* -HH:mm:ss */ 88 //static const UChar gDefGmtNegHmPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* -HH:mm */ 89 //static const UChar gDefGmtPosHmsPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* +HH:mm:ss */ 90 //static const UChar gDefGmtPosHmPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* +HH:mm */ 91 //static const UChar gUt[] = {0x0055, 0x0054, 0x0000}; // "UT" 92 //static const UChar gUtc[] = {0x0055, 0x0054, 0x0043, 0x0000}; // "UT" 93 94 typedef enum GmtPatSize { 95 kGmtLen = 3, 96 kGmtPatLen = 6, 97 kNegHmsLen = 9, 98 kNegHmLen = 6, 99 kPosHmsLen = 9, 100 kPosHmLen = 6, 101 kUtLen = 2, 102 kUtcLen = 3 103 } GmtPatSize; 104 105 // Stuff needed for numbering system overrides 106 107 typedef enum OvrStrType { 108 kOvrStrDate = 0, 109 kOvrStrTime = 1, 110 kOvrStrBoth = 2 111 } OvrStrType; 112 113 static const UDateFormatField kDateFields[] = { 114 UDAT_YEAR_FIELD, 115 UDAT_MONTH_FIELD, 116 UDAT_DATE_FIELD, 117 UDAT_DAY_OF_YEAR_FIELD, 118 UDAT_DAY_OF_WEEK_IN_MONTH_FIELD, 119 UDAT_WEEK_OF_YEAR_FIELD, 120 UDAT_WEEK_OF_MONTH_FIELD, 121 UDAT_YEAR_WOY_FIELD, 122 UDAT_EXTENDED_YEAR_FIELD, 123 UDAT_JULIAN_DAY_FIELD, 124 UDAT_STANDALONE_DAY_FIELD, 125 UDAT_STANDALONE_MONTH_FIELD, 126 UDAT_QUARTER_FIELD, 127 UDAT_STANDALONE_QUARTER_FIELD, 128 UDAT_YEAR_NAME_FIELD, 129 UDAT_RELATED_YEAR_FIELD }; 130 static const int8_t kDateFieldsCount = 16; 131 132 static const UDateFormatField kTimeFields[] = { 133 UDAT_HOUR_OF_DAY1_FIELD, 134 UDAT_HOUR_OF_DAY0_FIELD, 135 UDAT_MINUTE_FIELD, 136 UDAT_SECOND_FIELD, 137 UDAT_FRACTIONAL_SECOND_FIELD, 138 UDAT_HOUR1_FIELD, 139 UDAT_HOUR0_FIELD, 140 UDAT_MILLISECONDS_IN_DAY_FIELD, 141 UDAT_TIMEZONE_RFC_FIELD, 142 UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD }; 143 static const int8_t kTimeFieldsCount = 10; 144 145 146 // This is a pattern-of-last-resort used when we can't load a usable pattern out 147 // of a resource. 148 static const UChar gDefaultPattern[] = 149 { 150 0x79, 0x79, 0x79, 0x79, 0x4D, 0x4D, 0x64, 0x64, 0x20, 0x68, 0x68, 0x3A, 0x6D, 0x6D, 0x20, 0x61, 0 151 }; /* "yyyyMMdd hh:mm a" */ 152 153 // This prefix is designed to NEVER MATCH real text, in order to 154 // suppress the parsing of negative numbers. Adjust as needed (if 155 // this becomes valid Unicode). 156 static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0}; 157 158 /** 159 * These are the tags we expect to see in normal resource bundle files associated 160 * with a locale. 161 */ 162 static const char gDateTimePatternsTag[]="DateTimePatterns"; 163 164 //static const UChar gEtcUTC[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x54, 0x43, 0x00}; // "Etc/UTC" 165 static const UChar QUOTE = 0x27; // Single quote 166 167 /* 168 * The field range check bias for each UDateFormatField. 169 * The bias is added to the minimum and maximum values 170 * before they are compared to the parsed number. 171 * For example, the calendar stores zero-based month numbers 172 * but the parsed month numbers start at 1, so the bias is 1. 173 * 174 * A value of -1 means that the value is not checked. 175 */ 176 static const int32_t gFieldRangeBias[] = { 177 -1, // 'G' - UDAT_ERA_FIELD 178 -1, // 'y' - UDAT_YEAR_FIELD 179 1, // 'M' - UDAT_MONTH_FIELD 180 0, // 'd' - UDAT_DATE_FIELD 181 -1, // 'k' - UDAT_HOUR_OF_DAY1_FIELD 182 -1, // 'H' - UDAT_HOUR_OF_DAY0_FIELD 183 0, // 'm' - UDAT_MINUTE_FIELD 184 0, // 's' - UDAT_SECOND_FIELD 185 -1, // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?) 186 -1, // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?) 187 -1, // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?) 188 -1, // 'F' - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD (1-5?) 189 -1, // 'w' - UDAT_WEEK_OF_YEAR_FIELD (1-52?) 190 -1, // 'W' - UDAT_WEEK_OF_MONTH_FIELD (1-5?) 191 -1, // 'a' - UDAT_AM_PM_FIELD 192 -1, // 'h' - UDAT_HOUR1_FIELD 193 -1, // 'K' - UDAT_HOUR0_FIELD 194 -1, // 'z' - UDAT_TIMEZONE_FIELD 195 -1, // 'Y' - UDAT_YEAR_WOY_FIELD 196 -1, // 'e' - UDAT_DOW_LOCAL_FIELD 197 -1, // 'u' - UDAT_EXTENDED_YEAR_FIELD 198 -1, // 'g' - UDAT_JULIAN_DAY_FIELD 199 -1, // 'A' - UDAT_MILLISECONDS_IN_DAY_FIELD 200 -1, // 'Z' - UDAT_TIMEZONE_RFC_FIELD 201 -1, // 'v' - UDAT_TIMEZONE_GENERIC_FIELD 202 0, // 'c' - UDAT_STANDALONE_DAY_FIELD 203 1, // 'L' - UDAT_STANDALONE_MONTH_FIELD 204 -1, // 'Q' - UDAT_QUARTER_FIELD (1-4?) 205 -1, // 'q' - UDAT_STANDALONE_QUARTER_FIELD 206 -1, // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD 207 -1, // 'U' - UDAT_YEAR_NAME_FIELD 208 -1, // 'O' - UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD 209 -1, // 'X' - UDAT_TIMEZONE_ISO_FIELD 210 -1, // 'x' - UDAT_TIMEZONE_ISO_LOCAL_FIELD 211 -1, // 'r' - UDAT_RELATED_YEAR_FIELD 212 -1, // ':' - UDAT_TIME_SEPARATOR_FIELD 213 }; 214 215 // When calendar uses hebr numbering (i.e. he@calendar=hebrew), 216 // offset the years within the current millenium down to 1-999 217 static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000; 218 static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000; 219 220 static UMutex LOCK = U_MUTEX_INITIALIZER; 221 222 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat) 223 224 SimpleDateFormat::NSOverride::~NSOverride() { 225 if (snf != NULL) { 226 snf->removeRef(); 227 } 228 } 229 230 231 void SimpleDateFormat::NSOverride::free() { 232 NSOverride *cur = this; 233 while (cur) { 234 NSOverride *next = cur->next; 235 delete cur; 236 cur = next; 237 } 238 } 239 240 // no matter what the locale's default number format looked like, we want 241 // to modify it so that it doesn't use thousands separators, doesn't always 242 // show the decimal point, and recognizes integers only when parsing 243 static void fixNumberFormatForDates(NumberFormat &nf) { 244 nf.setGroupingUsed(FALSE); 245 DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(&nf); 246 if (decfmt != NULL) { 247 decfmt->setDecimalSeparatorAlwaysShown(FALSE); 248 } 249 nf.setParseIntegerOnly(TRUE); 250 nf.setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00" 251 } 252 253 static const SharedNumberFormat *createSharedNumberFormat( 254 NumberFormat *nfToAdopt) { 255 fixNumberFormatForDates(*nfToAdopt); 256 const SharedNumberFormat *result = new SharedNumberFormat(nfToAdopt); 257 if (result == NULL) { 258 delete nfToAdopt; 259 } 260 return result; 261 } 262 263 static const SharedNumberFormat *createSharedNumberFormat( 264 const Locale &loc, UErrorCode &status) { 265 NumberFormat *nf = NumberFormat::createInstance(loc, status); 266 if (U_FAILURE(status)) { 267 return NULL; 268 } 269 const SharedNumberFormat *result = createSharedNumberFormat(nf); 270 if (result == NULL) { 271 status = U_MEMORY_ALLOCATION_ERROR; 272 } 273 return result; 274 } 275 276 static const SharedNumberFormat **allocSharedNumberFormatters() { 277 const SharedNumberFormat **result = (const SharedNumberFormat**) 278 uprv_malloc(UDAT_FIELD_COUNT * sizeof(const SharedNumberFormat*)); 279 if (result == NULL) { 280 return NULL; 281 } 282 for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) { 283 result[i] = NULL; 284 } 285 return result; 286 } 287 288 static void freeSharedNumberFormatters(const SharedNumberFormat ** list) { 289 for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) { 290 SharedObject::clearPtr(list[i]); 291 } 292 uprv_free(list); 293 } 294 295 const NumberFormat *SimpleDateFormat::getNumberFormatByIndex( 296 UDateFormatField index) const { 297 if (fSharedNumberFormatters == NULL || 298 fSharedNumberFormatters[index] == NULL) { 299 return fNumberFormat; 300 } 301 return &(**fSharedNumberFormatters[index]); 302 } 303 304 class SimpleDateFormatMutableNFNode { 305 public: 306 const NumberFormat *key; 307 NumberFormat *value; 308 SimpleDateFormatMutableNFNode() 309 : key(NULL), value(NULL) { } 310 ~SimpleDateFormatMutableNFNode() { 311 delete value; 312 } 313 private: 314 SimpleDateFormatMutableNFNode(const SimpleDateFormatMutableNFNode &); 315 SimpleDateFormatMutableNFNode &operator=(const SimpleDateFormatMutableNFNode &); 316 }; 317 318 // Single threaded cache of non const NumberFormats. Designed to be stack 319 // allocated and used for a single format call. 320 class SimpleDateFormatMutableNFs : public UMemory { 321 public: 322 SimpleDateFormatMutableNFs() { 323 } 324 325 // Returns a non-const clone of nf which can be safely modified. 326 // Subsequent calls with same nf will return the same non-const clone. 327 // This object maintains ownership of all returned non-const 328 // NumberFormat objects. On memory allocation error returns NULL. 329 // Caller must check for NULL return value. 330 NumberFormat *get(const NumberFormat *nf) { 331 if (nf == NULL) { 332 return NULL; 333 } 334 int32_t idx = 0; 335 while (nodes[idx].value) { 336 if (nf == nodes[idx].key) { 337 return nodes[idx].value; 338 } 339 ++idx; 340 } 341 U_ASSERT(idx < UDAT_FIELD_COUNT); 342 nodes[idx].key = nf; 343 nodes[idx].value = (NumberFormat *) nf->clone(); 344 return nodes[idx].value; 345 } 346 private: 347 // +1 extra for sentinel. If each field had its own NumberFormat, this 348 // cache would have to allocate UDAT_FIELD_COUNT mutable versions worst 349 // case. 350 SimpleDateFormatMutableNFNode nodes[UDAT_FIELD_COUNT + 1]; 351 SimpleDateFormatMutableNFs(const SimpleDateFormatMutableNFs &); 352 SimpleDateFormatMutableNFs &operator=(const SimpleDateFormatMutableNFs &); 353 }; 354 355 //---------------------------------------------------------------------- 356 357 SimpleDateFormat::~SimpleDateFormat() 358 { 359 delete fSymbols; 360 if (fSharedNumberFormatters) { 361 freeSharedNumberFormatters(fSharedNumberFormatters); 362 } 363 if (fTimeZoneFormat) { 364 delete fTimeZoneFormat; 365 } 366 367 #if !UCONFIG_NO_BREAK_ITERATION 368 delete fCapitalizationBrkIter; 369 #endif 370 } 371 372 //---------------------------------------------------------------------- 373 374 SimpleDateFormat::SimpleDateFormat(UErrorCode& status) 375 : fLocale(Locale::getDefault()), 376 fSymbols(NULL), 377 fTimeZoneFormat(NULL), 378 fSharedNumberFormatters(NULL), 379 fCapitalizationBrkIter(NULL) 380 { 381 initializeBooleanAttributes(); 382 construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status); 383 initializeDefaultCentury(); 384 } 385 386 //---------------------------------------------------------------------- 387 388 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 389 UErrorCode &status) 390 : fPattern(pattern), 391 fLocale(Locale::getDefault()), 392 fSymbols(NULL), 393 fTimeZoneFormat(NULL), 394 fSharedNumberFormatters(NULL), 395 fCapitalizationBrkIter(NULL) 396 { 397 fDateOverride.setToBogus(); 398 fTimeOverride.setToBogus(); 399 initializeBooleanAttributes(); 400 initializeCalendar(NULL,fLocale,status); 401 fSymbols = DateFormatSymbols::createForLocale(fLocale, status); 402 initialize(fLocale, status); 403 initializeDefaultCentury(); 404 405 } 406 //---------------------------------------------------------------------- 407 408 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 409 const UnicodeString& override, 410 UErrorCode &status) 411 : fPattern(pattern), 412 fLocale(Locale::getDefault()), 413 fSymbols(NULL), 414 fTimeZoneFormat(NULL), 415 fSharedNumberFormatters(NULL), 416 fCapitalizationBrkIter(NULL) 417 { 418 fDateOverride.setTo(override); 419 fTimeOverride.setToBogus(); 420 initializeBooleanAttributes(); 421 initializeCalendar(NULL,fLocale,status); 422 fSymbols = DateFormatSymbols::createForLocale(fLocale, status); 423 initialize(fLocale, status); 424 initializeDefaultCentury(); 425 426 processOverrideString(fLocale,override,kOvrStrBoth,status); 427 428 } 429 430 //---------------------------------------------------------------------- 431 432 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 433 const Locale& locale, 434 UErrorCode& status) 435 : fPattern(pattern), 436 fLocale(locale), 437 fTimeZoneFormat(NULL), 438 fSharedNumberFormatters(NULL), 439 fCapitalizationBrkIter(NULL) 440 { 441 442 fDateOverride.setToBogus(); 443 fTimeOverride.setToBogus(); 444 initializeBooleanAttributes(); 445 446 initializeCalendar(NULL,fLocale,status); 447 fSymbols = DateFormatSymbols::createForLocale(fLocale, status); 448 initialize(fLocale, status); 449 initializeDefaultCentury(); 450 } 451 452 //---------------------------------------------------------------------- 453 454 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 455 const UnicodeString& override, 456 const Locale& locale, 457 UErrorCode& status) 458 : fPattern(pattern), 459 fLocale(locale), 460 fTimeZoneFormat(NULL), 461 fSharedNumberFormatters(NULL), 462 fCapitalizationBrkIter(NULL) 463 { 464 465 fDateOverride.setTo(override); 466 fTimeOverride.setToBogus(); 467 initializeBooleanAttributes(); 468 469 initializeCalendar(NULL,fLocale,status); 470 fSymbols = DateFormatSymbols::createForLocale(fLocale, status); 471 initialize(fLocale, status); 472 initializeDefaultCentury(); 473 474 processOverrideString(locale,override,kOvrStrBoth,status); 475 476 } 477 478 //---------------------------------------------------------------------- 479 480 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 481 DateFormatSymbols* symbolsToAdopt, 482 UErrorCode& status) 483 : fPattern(pattern), 484 fLocale(Locale::getDefault()), 485 fSymbols(symbolsToAdopt), 486 fTimeZoneFormat(NULL), 487 fSharedNumberFormatters(NULL), 488 fCapitalizationBrkIter(NULL) 489 { 490 491 fDateOverride.setToBogus(); 492 fTimeOverride.setToBogus(); 493 initializeBooleanAttributes(); 494 495 initializeCalendar(NULL,fLocale,status); 496 initialize(fLocale, status); 497 initializeDefaultCentury(); 498 } 499 500 //---------------------------------------------------------------------- 501 502 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 503 const DateFormatSymbols& symbols, 504 UErrorCode& status) 505 : fPattern(pattern), 506 fLocale(Locale::getDefault()), 507 fSymbols(new DateFormatSymbols(symbols)), 508 fTimeZoneFormat(NULL), 509 fSharedNumberFormatters(NULL), 510 fCapitalizationBrkIter(NULL) 511 { 512 513 fDateOverride.setToBogus(); 514 fTimeOverride.setToBogus(); 515 initializeBooleanAttributes(); 516 517 initializeCalendar(NULL, fLocale, status); 518 initialize(fLocale, status); 519 initializeDefaultCentury(); 520 } 521 522 //---------------------------------------------------------------------- 523 524 // Not for public consumption; used by DateFormat 525 SimpleDateFormat::SimpleDateFormat(EStyle timeStyle, 526 EStyle dateStyle, 527 const Locale& locale, 528 UErrorCode& status) 529 : fLocale(locale), 530 fSymbols(NULL), 531 fTimeZoneFormat(NULL), 532 fSharedNumberFormatters(NULL), 533 fCapitalizationBrkIter(NULL) 534 { 535 initializeBooleanAttributes(); 536 construct(timeStyle, dateStyle, fLocale, status); 537 if(U_SUCCESS(status)) { 538 initializeDefaultCentury(); 539 } 540 } 541 542 //---------------------------------------------------------------------- 543 544 /** 545 * Not for public consumption; used by DateFormat. This constructor 546 * never fails. If the resource data is not available, it uses the 547 * the last resort symbols. 548 */ 549 SimpleDateFormat::SimpleDateFormat(const Locale& locale, 550 UErrorCode& status) 551 : fPattern(gDefaultPattern), 552 fLocale(locale), 553 fSymbols(NULL), 554 fTimeZoneFormat(NULL), 555 fSharedNumberFormatters(NULL), 556 fCapitalizationBrkIter(NULL) 557 { 558 if (U_FAILURE(status)) return; 559 initializeBooleanAttributes(); 560 initializeCalendar(NULL, fLocale, status); 561 fSymbols = DateFormatSymbols::createForLocale(fLocale, status); 562 if (U_FAILURE(status)) 563 { 564 status = U_ZERO_ERROR; 565 delete fSymbols; 566 // This constructor doesn't fail; it uses last resort data 567 fSymbols = new DateFormatSymbols(status); 568 /* test for NULL */ 569 if (fSymbols == 0) { 570 status = U_MEMORY_ALLOCATION_ERROR; 571 return; 572 } 573 } 574 575 fDateOverride.setToBogus(); 576 fTimeOverride.setToBogus(); 577 578 initialize(fLocale, status); 579 if(U_SUCCESS(status)) { 580 initializeDefaultCentury(); 581 } 582 } 583 584 //---------------------------------------------------------------------- 585 586 SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other) 587 : DateFormat(other), 588 fLocale(other.fLocale), 589 fSymbols(NULL), 590 fTimeZoneFormat(NULL), 591 fSharedNumberFormatters(NULL), 592 fCapitalizationBrkIter(NULL) 593 { 594 initializeBooleanAttributes(); 595 *this = other; 596 } 597 598 //---------------------------------------------------------------------- 599 600 SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other) 601 { 602 if (this == &other) { 603 return *this; 604 } 605 DateFormat::operator=(other); 606 fDateOverride = other.fDateOverride; 607 fTimeOverride = other.fTimeOverride; 608 609 delete fSymbols; 610 fSymbols = NULL; 611 612 if (other.fSymbols) 613 fSymbols = new DateFormatSymbols(*other.fSymbols); 614 615 fDefaultCenturyStart = other.fDefaultCenturyStart; 616 fDefaultCenturyStartYear = other.fDefaultCenturyStartYear; 617 fHaveDefaultCentury = other.fHaveDefaultCentury; 618 619 fPattern = other.fPattern; 620 621 // TimeZoneFormat in ICU4C only depends on a locale for now 622 if (fLocale != other.fLocale) { 623 delete fTimeZoneFormat; 624 fTimeZoneFormat = NULL; // forces lazy instantiation with the other locale 625 fLocale = other.fLocale; 626 } 627 628 #if !UCONFIG_NO_BREAK_ITERATION 629 if (other.fCapitalizationBrkIter != NULL) { 630 fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone(); 631 } 632 #endif 633 634 if (fSharedNumberFormatters != NULL) { 635 freeSharedNumberFormatters(fSharedNumberFormatters); 636 fSharedNumberFormatters = NULL; 637 } 638 if (other.fSharedNumberFormatters != NULL) { 639 fSharedNumberFormatters = allocSharedNumberFormatters(); 640 if (fSharedNumberFormatters) { 641 for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) { 642 SharedObject::copyPtr( 643 other.fSharedNumberFormatters[i], 644 fSharedNumberFormatters[i]); 645 } 646 } 647 } 648 649 return *this; 650 } 651 652 //---------------------------------------------------------------------- 653 654 Format* 655 SimpleDateFormat::clone() const 656 { 657 return new SimpleDateFormat(*this); 658 } 659 660 //---------------------------------------------------------------------- 661 662 UBool 663 SimpleDateFormat::operator==(const Format& other) const 664 { 665 if (DateFormat::operator==(other)) { 666 // The DateFormat::operator== check for fCapitalizationContext equality above 667 // is sufficient to check equality of all derived context-related data. 668 // DateFormat::operator== guarantees following cast is safe 669 SimpleDateFormat* that = (SimpleDateFormat*)&other; 670 return (fPattern == that->fPattern && 671 fSymbols != NULL && // Check for pathological object 672 that->fSymbols != NULL && // Check for pathological object 673 *fSymbols == *that->fSymbols && 674 fHaveDefaultCentury == that->fHaveDefaultCentury && 675 fDefaultCenturyStart == that->fDefaultCenturyStart); 676 } 677 return FALSE; 678 } 679 680 //---------------------------------------------------------------------- 681 682 void SimpleDateFormat::construct(EStyle timeStyle, 683 EStyle dateStyle, 684 const Locale& locale, 685 UErrorCode& status) 686 { 687 // called by several constructors to load pattern data from the resources 688 if (U_FAILURE(status)) return; 689 690 // We will need the calendar to know what type of symbols to load. 691 initializeCalendar(NULL, locale, status); 692 if (U_FAILURE(status)) return; 693 694 CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status); 695 UResourceBundle *dateTimePatterns = calData.getByKey(gDateTimePatternsTag, status); 696 UResourceBundle *currentBundle; 697 698 if (U_FAILURE(status)) return; 699 700 if (ures_getSize(dateTimePatterns) <= kDateTime) 701 { 702 status = U_INVALID_FORMAT_ERROR; 703 return; 704 } 705 706 setLocaleIDs(ures_getLocaleByType(dateTimePatterns, ULOC_VALID_LOCALE, &status), 707 ures_getLocaleByType(dateTimePatterns, ULOC_ACTUAL_LOCALE, &status)); 708 709 // create a symbols object from the locale 710 fSymbols = DateFormatSymbols::createForLocale(locale, status); 711 if (U_FAILURE(status)) return; 712 /* test for NULL */ 713 if (fSymbols == 0) { 714 status = U_MEMORY_ALLOCATION_ERROR; 715 return; 716 } 717 718 const UChar *resStr,*ovrStr; 719 int32_t resStrLen,ovrStrLen = 0; 720 fDateOverride.setToBogus(); 721 fTimeOverride.setToBogus(); 722 723 // if the pattern should include both date and time information, use the date/time 724 // pattern string as a guide to tell use how to glue together the appropriate date 725 // and time pattern strings. The actual gluing-together is handled by a convenience 726 // method on MessageFormat. 727 if ((timeStyle != kNone) && (dateStyle != kNone)) 728 { 729 Formattable timeDateArray[2]; 730 731 // use Formattable::adoptString() so that we can use fastCopyFrom() 732 // instead of Formattable::setString()'s unaware, safe, deep string clone 733 // see Jitterbug 2296 734 735 currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status); 736 if (U_FAILURE(status)) { 737 status = U_INVALID_FORMAT_ERROR; 738 return; 739 } 740 switch (ures_getType(currentBundle)) { 741 case URES_STRING: { 742 resStr = ures_getString(currentBundle, &resStrLen, &status); 743 break; 744 } 745 case URES_ARRAY: { 746 resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status); 747 ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status); 748 fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen); 749 break; 750 } 751 default: { 752 status = U_INVALID_FORMAT_ERROR; 753 ures_close(currentBundle); 754 return; 755 } 756 } 757 ures_close(currentBundle); 758 759 UnicodeString *tempus1 = new UnicodeString(TRUE, resStr, resStrLen); 760 // NULL pointer check 761 if (tempus1 == NULL) { 762 status = U_MEMORY_ALLOCATION_ERROR; 763 return; 764 } 765 timeDateArray[0].adoptString(tempus1); 766 767 currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status); 768 if (U_FAILURE(status)) { 769 status = U_INVALID_FORMAT_ERROR; 770 return; 771 } 772 switch (ures_getType(currentBundle)) { 773 case URES_STRING: { 774 resStr = ures_getString(currentBundle, &resStrLen, &status); 775 break; 776 } 777 case URES_ARRAY: { 778 resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status); 779 ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status); 780 fDateOverride.setTo(TRUE, ovrStr, ovrStrLen); 781 break; 782 } 783 default: { 784 status = U_INVALID_FORMAT_ERROR; 785 ures_close(currentBundle); 786 return; 787 } 788 } 789 ures_close(currentBundle); 790 791 UnicodeString *tempus2 = new UnicodeString(TRUE, resStr, resStrLen); 792 // Null pointer check 793 if (tempus2 == NULL) { 794 status = U_MEMORY_ALLOCATION_ERROR; 795 return; 796 } 797 timeDateArray[1].adoptString(tempus2); 798 799 int32_t glueIndex = kDateTime; 800 int32_t patternsSize = ures_getSize(dateTimePatterns); 801 if (patternsSize >= (kDateTimeOffset + kShort + 1)) { 802 // Get proper date time format 803 glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset)); 804 } 805 806 resStr = ures_getStringByIndex(dateTimePatterns, glueIndex, &resStrLen, &status); 807 MessageFormat::format(UnicodeString(TRUE, resStr, resStrLen), timeDateArray, 2, fPattern, status); 808 } 809 // if the pattern includes just time data or just date date, load the appropriate 810 // pattern string from the resources 811 // setTo() - see DateFormatSymbols::assignArray comments 812 else if (timeStyle != kNone) { 813 currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status); 814 if (U_FAILURE(status)) { 815 status = U_INVALID_FORMAT_ERROR; 816 return; 817 } 818 switch (ures_getType(currentBundle)) { 819 case URES_STRING: { 820 resStr = ures_getString(currentBundle, &resStrLen, &status); 821 break; 822 } 823 case URES_ARRAY: { 824 resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status); 825 ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status); 826 fDateOverride.setTo(TRUE, ovrStr, ovrStrLen); 827 break; 828 } 829 default: { 830 status = U_INVALID_FORMAT_ERROR; 831 ures_close(currentBundle); 832 return; 833 } 834 } 835 fPattern.setTo(TRUE, resStr, resStrLen); 836 ures_close(currentBundle); 837 } 838 else if (dateStyle != kNone) { 839 currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status); 840 if (U_FAILURE(status)) { 841 status = U_INVALID_FORMAT_ERROR; 842 return; 843 } 844 switch (ures_getType(currentBundle)) { 845 case URES_STRING: { 846 resStr = ures_getString(currentBundle, &resStrLen, &status); 847 break; 848 } 849 case URES_ARRAY: { 850 resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status); 851 ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status); 852 fDateOverride.setTo(TRUE, ovrStr, ovrStrLen); 853 break; 854 } 855 default: { 856 status = U_INVALID_FORMAT_ERROR; 857 ures_close(currentBundle); 858 return; 859 } 860 } 861 fPattern.setTo(TRUE, resStr, resStrLen); 862 ures_close(currentBundle); 863 } 864 865 // and if it includes _neither_, that's an error 866 else 867 status = U_INVALID_FORMAT_ERROR; 868 869 // finally, finish initializing by creating a Calendar and a NumberFormat 870 initialize(locale, status); 871 } 872 873 //---------------------------------------------------------------------- 874 875 Calendar* 876 SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status) 877 { 878 if(!U_FAILURE(status)) { 879 fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status); 880 } 881 return fCalendar; 882 } 883 884 void 885 SimpleDateFormat::initialize(const Locale& locale, 886 UErrorCode& status) 887 { 888 if (U_FAILURE(status)) return; 889 890 // We don't need to check that the row count is >= 1, since all 2d arrays have at 891 // least one row 892 fNumberFormat = NumberFormat::createInstance(locale, status); 893 if (fNumberFormat != NULL && U_SUCCESS(status)) 894 { 895 fixNumberFormatForDates(*fNumberFormat); 896 //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse 897 898 initNumberFormatters(locale,status); 899 900 } 901 else if (U_SUCCESS(status)) 902 { 903 status = U_MISSING_RESOURCE_ERROR; 904 } 905 } 906 907 /* Initialize the fields we use to disambiguate ambiguous years. Separate 908 * so we can call it from readObject(). 909 */ 910 void SimpleDateFormat::initializeDefaultCentury() 911 { 912 if(fCalendar) { 913 fHaveDefaultCentury = fCalendar->haveDefaultCentury(); 914 if(fHaveDefaultCentury) { 915 fDefaultCenturyStart = fCalendar->defaultCenturyStart(); 916 fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear(); 917 } else { 918 fDefaultCenturyStart = DBL_MIN; 919 fDefaultCenturyStartYear = -1; 920 } 921 } 922 } 923 924 /* 925 * Initialize the boolean attributes. Separate so we can call it from all constructors. 926 */ 927 void SimpleDateFormat::initializeBooleanAttributes() 928 { 929 UErrorCode status = U_ZERO_ERROR; 930 931 setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status); 932 setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 933 setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); 934 setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, true, status); 935 } 936 937 /* Define one-century window into which to disambiguate dates using 938 * two-digit years. Make public in JDK 1.2. 939 */ 940 void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status) 941 { 942 if(U_FAILURE(status)) { 943 return; 944 } 945 if(!fCalendar) { 946 status = U_ILLEGAL_ARGUMENT_ERROR; 947 return; 948 } 949 950 fCalendar->setTime(startDate, status); 951 if(U_SUCCESS(status)) { 952 fHaveDefaultCentury = TRUE; 953 fDefaultCenturyStart = startDate; 954 fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status); 955 } 956 } 957 958 //---------------------------------------------------------------------- 959 960 UnicodeString& 961 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const 962 { 963 UErrorCode status = U_ZERO_ERROR; 964 FieldPositionOnlyHandler handler(pos); 965 return _format(cal, appendTo, handler, status); 966 } 967 968 //---------------------------------------------------------------------- 969 970 UnicodeString& 971 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, 972 FieldPositionIterator* posIter, UErrorCode& status) const 973 { 974 FieldPositionIteratorHandler handler(posIter, status); 975 return _format(cal, appendTo, handler, status); 976 } 977 978 //---------------------------------------------------------------------- 979 980 UnicodeString& 981 SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, 982 FieldPositionHandler& handler, UErrorCode& status) const 983 { 984 if ( U_FAILURE(status) ) { 985 return appendTo; 986 } 987 Calendar* workCal = &cal; 988 Calendar* calClone = NULL; 989 if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) { 990 // Different calendar type 991 // We use the time and time zone from the input calendar, but 992 // do not use the input calendar for field calculation. 993 calClone = fCalendar->clone(); 994 if (calClone != NULL) { 995 UDate t = cal.getTime(status); 996 calClone->setTime(t, status); 997 calClone->setTimeZone(cal.getTimeZone()); 998 workCal = calClone; 999 } else { 1000 status = U_MEMORY_ALLOCATION_ERROR; 1001 return appendTo; 1002 } 1003 } 1004 1005 UBool inQuote = FALSE; 1006 UChar prevCh = 0; 1007 int32_t count = 0; 1008 int32_t fieldNum = 0; 1009 UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status); 1010 1011 // Create temporary cache of mutable number format objects. This way 1012 // subFormat won't have to clone the const NumberFormat for each field. 1013 // if several fields share the same NumberFormat, which will almost 1014 // always be the case, this is a big save. 1015 SimpleDateFormatMutableNFs mutableNFs; 1016 // loop through the pattern string character by character 1017 for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) { 1018 UChar ch = fPattern[i]; 1019 1020 // Use subFormat() to format a repeated pattern character 1021 // when a different pattern or non-pattern character is seen 1022 if (ch != prevCh && count > 0) { 1023 subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status); 1024 count = 0; 1025 } 1026 if (ch == QUOTE) { 1027 // Consecutive single quotes are a single quote literal, 1028 // either outside of quotes or between quotes 1029 if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) { 1030 appendTo += (UChar)QUOTE; 1031 ++i; 1032 } else { 1033 inQuote = ! inQuote; 1034 } 1035 } 1036 else if (!inQuote && isSyntaxChar(ch)) { 1037 // ch is a date-time pattern character to be interpreted 1038 // by subFormat(); count the number of times it is repeated 1039 prevCh = ch; 1040 ++count; 1041 } 1042 else { 1043 // Append quoted characters and unquoted non-pattern characters 1044 appendTo += ch; 1045 } 1046 } 1047 1048 // Format the last item in the pattern, if any 1049 if (count > 0) { 1050 subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status); 1051 } 1052 1053 if (calClone != NULL) { 1054 delete calClone; 1055 } 1056 1057 return appendTo; 1058 } 1059 1060 //---------------------------------------------------------------------- 1061 1062 /* Map calendar field into calendar field level. 1063 * the larger the level, the smaller the field unit. 1064 * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10, 1065 * UCAL_MONTH level is 20. 1066 * NOTE: if new fields adds in, the table needs to update. 1067 */ 1068 const int32_t 1069 SimpleDateFormat::fgCalendarFieldToLevel[] = 1070 { 1071 /*GyM*/ 0, 10, 20, 1072 /*wW*/ 20, 30, 1073 /*dDEF*/ 30, 20, 30, 30, 1074 /*ahHm*/ 40, 50, 50, 60, 1075 /*sS*/ 70, 80, 1076 /*z?Y*/ 0, 0, 10, 1077 /*eug*/ 30, 10, 0, 1078 /*A?.*/ 40, 0, 0 1079 }; 1080 1081 int32_t SimpleDateFormat::getLevelFromChar(UChar ch) { 1082 // Map date field LETTER into calendar field level. 1083 // the larger the level, the smaller the field unit. 1084 // NOTE: if new fields adds in, the table needs to update. 1085 static const int32_t mapCharToLevel[] = { 1086 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1087 // 1088 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1089 // ! " # $ % & ' ( ) * + , - . / 1090 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1091 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 1092 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, 1093 // @ A B C D E F G H I J K L M N O 1094 -1, 40, -1, -1, 20, 30, 30, 0, 50, -1, -1, 50, 20, 20, -1, 0, 1095 // P Q R S T U V W X Y Z [ \ ] ^ _ 1096 -1, 20, -1, 80, -1, 10, 0, 30, 0, 10, 0, -1, -1, -1, -1, -1, 1097 // ` a b c d e f g h i j k l m n o 1098 -1, 40, -1, 30, 30, 30, -1, 0, 50, -1, -1, 50, 0, 60, -1, -1, 1099 // p q r s t u v w x y z { | } ~ 1100 -1, 20, 10, 70, -1, 10, 0, 20, 0, 10, 0, -1, -1, -1, -1, -1 1101 }; 1102 1103 return ch < UPRV_LENGTHOF(mapCharToLevel) ? mapCharToLevel[ch] : -1; 1104 } 1105 1106 UBool SimpleDateFormat::isSyntaxChar(UChar ch) { 1107 static const UBool mapCharToIsSyntax[] = { 1108 // 1109 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 1110 // 1111 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 1112 // 1113 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 1114 // 1115 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 1116 // ! " # $ % & ' 1117 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 1118 // ( ) * + , - . / 1119 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 1120 // 0 1 2 3 4 5 6 7 1121 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 1122 // 8 9 : ; < = > ? 1123 FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, 1124 // @ A B C D E F G 1125 FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 1126 // H I J K L M N O 1127 TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 1128 // P Q R S T U V W 1129 TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 1130 // X Y Z [ \ ] ^ _ 1131 TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, 1132 // ` a b c d e f g 1133 FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 1134 // h i j k l m n o 1135 TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 1136 // p q r s t u v w 1137 TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 1138 // x y z { | } ~ 1139 TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE 1140 }; 1141 1142 return ch < UPRV_LENGTHOF(mapCharToIsSyntax) ? mapCharToIsSyntax[ch] : FALSE; 1143 } 1144 1145 // Map index into pattern character string to Calendar field number. 1146 const UCalendarDateFields 1147 SimpleDateFormat::fgPatternIndexToCalendarField[] = 1148 { 1149 /*GyM*/ UCAL_ERA, UCAL_YEAR, UCAL_MONTH, 1150 /*dkH*/ UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY, 1151 /*msS*/ UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND, 1152 /*EDF*/ UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH, 1153 /*wWa*/ UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM, 1154 /*hKz*/ UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET, 1155 /*Yeu*/ UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR, 1156 /*gAZ*/ UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET, 1157 /*v*/ UCAL_ZONE_OFFSET, 1158 /*c*/ UCAL_DOW_LOCAL, 1159 /*L*/ UCAL_MONTH, 1160 /*Q*/ UCAL_MONTH, 1161 /*q*/ UCAL_MONTH, 1162 /*V*/ UCAL_ZONE_OFFSET, 1163 /*U*/ UCAL_YEAR, 1164 /*O*/ UCAL_ZONE_OFFSET, 1165 /*Xx*/ UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET, 1166 /*r*/ UCAL_EXTENDED_YEAR, 1167 /*:*/ UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */ 1168 }; 1169 1170 // Map index into pattern character string to DateFormat field number 1171 const UDateFormatField 1172 SimpleDateFormat::fgPatternIndexToDateFormatField[] = { 1173 /*GyM*/ UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD, 1174 /*dkH*/ UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD, 1175 /*msS*/ UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD, 1176 /*EDF*/ UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD, 1177 /*wWa*/ UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD, 1178 /*hKz*/ UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD, 1179 /*Yeu*/ UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD, 1180 /*gAZ*/ UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD, 1181 /*v*/ UDAT_TIMEZONE_GENERIC_FIELD, 1182 /*c*/ UDAT_STANDALONE_DAY_FIELD, 1183 /*L*/ UDAT_STANDALONE_MONTH_FIELD, 1184 /*Q*/ UDAT_QUARTER_FIELD, 1185 /*q*/ UDAT_STANDALONE_QUARTER_FIELD, 1186 /*V*/ UDAT_TIMEZONE_SPECIAL_FIELD, 1187 /*U*/ UDAT_YEAR_NAME_FIELD, 1188 /*O*/ UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD, 1189 /*Xx*/ UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD, 1190 /*r*/ UDAT_RELATED_YEAR_FIELD, 1191 /*:*/ UDAT_TIME_SEPARATOR_FIELD, 1192 }; 1193 1194 //---------------------------------------------------------------------- 1195 1196 /** 1197 * Append symbols[value] to dst. Make sure the array index is not out 1198 * of bounds. 1199 */ 1200 static inline void 1201 _appendSymbol(UnicodeString& dst, 1202 int32_t value, 1203 const UnicodeString* symbols, 1204 int32_t symbolsCount) { 1205 U_ASSERT(0 <= value && value < symbolsCount); 1206 if (0 <= value && value < symbolsCount) { 1207 dst += symbols[value]; 1208 } 1209 } 1210 1211 static inline void 1212 _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount, 1213 const UnicodeString* monthPattern, UErrorCode& status) { 1214 U_ASSERT(0 <= value && value < symbolsCount); 1215 if (0 <= value && value < symbolsCount) { 1216 if (monthPattern == NULL) { 1217 dst += symbols[value]; 1218 } else { 1219 Formattable monthName((const UnicodeString&)(symbols[value])); 1220 MessageFormat::format(*monthPattern, &monthName, 1, dst, status); 1221 } 1222 } 1223 } 1224 1225 //---------------------------------------------------------------------- 1226 void 1227 SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) { 1228 if (U_FAILURE(status)) { 1229 return; 1230 } 1231 if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) { 1232 return; 1233 } 1234 umtx_lock(&LOCK); 1235 if (fSharedNumberFormatters == NULL) { 1236 fSharedNumberFormatters = allocSharedNumberFormatters(); 1237 if (fSharedNumberFormatters == NULL) { 1238 status = U_MEMORY_ALLOCATION_ERROR; 1239 } 1240 } 1241 umtx_unlock(&LOCK); 1242 1243 if (U_FAILURE(status)) { 1244 return; 1245 } 1246 1247 processOverrideString(locale,fDateOverride,kOvrStrDate,status); 1248 processOverrideString(locale,fTimeOverride,kOvrStrTime,status); 1249 } 1250 1251 void 1252 SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) { 1253 if (str.isBogus() || U_FAILURE(status)) { 1254 return; 1255 } 1256 1257 int32_t start = 0; 1258 int32_t len; 1259 UnicodeString nsName; 1260 UnicodeString ovrField; 1261 UBool moreToProcess = TRUE; 1262 NSOverride *overrideList = NULL; 1263 1264 while (moreToProcess) { 1265 int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start); 1266 if (delimiterPosition == -1) { 1267 moreToProcess = FALSE; 1268 len = str.length() - start; 1269 } else { 1270 len = delimiterPosition - start; 1271 } 1272 UnicodeString currentString(str,start,len); 1273 int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0); 1274 if (equalSignPosition == -1) { // Simple override string such as "hebrew" 1275 nsName.setTo(currentString); 1276 ovrField.setToBogus(); 1277 } else { // Field specific override string such as "y=hebrew" 1278 nsName.setTo(currentString,equalSignPosition+1); 1279 ovrField.setTo(currentString,0,1); // We just need the first character. 1280 } 1281 1282 int32_t nsNameHash = nsName.hashCode(); 1283 // See if the numbering system is in the override list, if not, then add it. 1284 NSOverride *cur = overrideList; 1285 const SharedNumberFormat *snf = NULL; 1286 UBool found = FALSE; 1287 while ( cur && !found ) { 1288 if ( cur->hash == nsNameHash ) { 1289 snf = cur->snf; 1290 found = TRUE; 1291 } 1292 cur = cur->next; 1293 } 1294 1295 if (!found) { 1296 LocalPointer<NSOverride> cur(new NSOverride); 1297 if (!cur.isNull()) { 1298 char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1299 uprv_strcpy(kw,"numbers="); 1300 nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV); 1301 1302 Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw); 1303 cur->hash = nsNameHash; 1304 cur->next = overrideList; 1305 SharedObject::copyPtr( 1306 createSharedNumberFormat(ovrLoc, status), cur->snf); 1307 if (U_FAILURE(status)) { 1308 if (overrideList) { 1309 overrideList->free(); 1310 } 1311 return; 1312 } 1313 snf = cur->snf; 1314 overrideList = cur.orphan(); 1315 } else { 1316 status = U_MEMORY_ALLOCATION_ERROR; 1317 if (overrideList) { 1318 overrideList->free(); 1319 } 1320 return; 1321 } 1322 } 1323 1324 // Now that we have an appropriate number formatter, fill in the appropriate spaces in the 1325 // number formatters table. 1326 if (ovrField.isBogus()) { 1327 switch (type) { 1328 case kOvrStrDate: 1329 case kOvrStrBoth: { 1330 for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) { 1331 SharedObject::copyPtr(snf, fSharedNumberFormatters[kDateFields[i]]); 1332 } 1333 if (type==kOvrStrDate) { 1334 break; 1335 } 1336 } 1337 case kOvrStrTime : { 1338 for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) { 1339 SharedObject::copyPtr(snf, fSharedNumberFormatters[kTimeFields[i]]); 1340 } 1341 break; 1342 } 1343 } 1344 } else { 1345 // if the pattern character is unrecognized, signal an error and bail out 1346 UDateFormatField patternCharIndex = 1347 DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0)); 1348 if (patternCharIndex == UDAT_FIELD_COUNT) { 1349 status = U_INVALID_FORMAT_ERROR; 1350 if (overrideList) { 1351 overrideList->free(); 1352 } 1353 return; 1354 } 1355 SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]); 1356 } 1357 1358 start = delimiterPosition + 1; 1359 } 1360 if (overrideList) { 1361 overrideList->free(); 1362 } 1363 } 1364 1365 //--------------------------------------------------------------------- 1366 void 1367 SimpleDateFormat::subFormat(UnicodeString &appendTo, 1368 UChar ch, 1369 int32_t count, 1370 UDisplayContext capitalizationContext, 1371 int32_t fieldNum, 1372 FieldPositionHandler& handler, 1373 Calendar& cal, 1374 SimpleDateFormatMutableNFs &mutableNFs, 1375 UErrorCode& status) const 1376 { 1377 if (U_FAILURE(status)) { 1378 return; 1379 } 1380 1381 // this function gets called by format() to produce the appropriate substitution 1382 // text for an individual pattern symbol (e.g., "HH" or "yyyy") 1383 1384 UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch); 1385 const int32_t maxIntCount = 10; 1386 int32_t beginOffset = appendTo.length(); 1387 NumberFormat *currentNumberFormat; 1388 DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther; 1389 1390 UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0); 1391 UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0); 1392 1393 // if the pattern character is unrecognized, signal an error and dump out 1394 if (patternCharIndex == UDAT_FIELD_COUNT) 1395 { 1396 if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored 1397 status = U_INVALID_FORMAT_ERROR; 1398 } 1399 return; 1400 } 1401 1402 UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; 1403 int32_t value = 0; 1404 // Don't get value unless it is useful 1405 if (field < UCAL_FIELD_COUNT) { 1406 value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status); 1407 } 1408 if (U_FAILURE(status)) { 1409 return; 1410 } 1411 1412 currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex)); 1413 if (currentNumberFormat == NULL) { 1414 status = U_MEMORY_ALLOCATION_ERROR; 1415 return; 1416 } 1417 UnicodeString hebr("hebr", 4, US_INV); 1418 1419 switch (patternCharIndex) { 1420 1421 // for any "G" symbol, write out the appropriate era string 1422 // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name 1423 case UDAT_ERA_FIELD: 1424 if (isChineseCalendar) { 1425 zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J 1426 } else { 1427 if (count == 5) { 1428 _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount); 1429 capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow; 1430 } else if (count == 4) { 1431 _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount); 1432 capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide; 1433 } else { 1434 _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount); 1435 capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev; 1436 } 1437 } 1438 break; 1439 1440 case UDAT_YEAR_NAME_FIELD: 1441 if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) { 1442 // the Calendar YEAR field runs 1 through 60 for cyclic years 1443 _appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount); 1444 break; 1445 } 1446 // else fall through to numeric year handling, do not break here 1447 1448 // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits 1449 // NEW: UTS#35: 1450 //Year y yy yyy yyyy yyyyy 1451 //AD 1 1 01 001 0001 00001 1452 //AD 12 12 12 012 0012 00012 1453 //AD 123 123 23 123 0123 00123 1454 //AD 1234 1234 34 1234 1234 01234 1455 //AD 12345 12345 45 12345 12345 12345 1456 case UDAT_YEAR_FIELD: 1457 case UDAT_YEAR_WOY_FIELD: 1458 if (fDateOverride.compare(hebr)==0 && value>HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value<HEBREW_CAL_CUR_MILLENIUM_END_YEAR) { 1459 value-=HEBREW_CAL_CUR_MILLENIUM_START_YEAR; 1460 } 1461 if(count == 2) 1462 zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2); 1463 else 1464 zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount); 1465 break; 1466 1467 // for "MMMM"/"LLLL", write out the whole month name, for "MMM"/"LLL", write out the month 1468 // abbreviation, for "M"/"L" or "MM"/"LL", write out the month as a number with the 1469 // appropriate number of digits 1470 // for "MMMMM"/"LLLLL", use the narrow form 1471 case UDAT_MONTH_FIELD: 1472 case UDAT_STANDALONE_MONTH_FIELD: 1473 if ( isHebrewCalendar ) { 1474 HebrewCalendar *hc = (HebrewCalendar*)&cal; 1475 if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 ) 1476 value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar. 1477 if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 ) 1478 value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7. 1479 } 1480 { 1481 int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)? 1482 cal.get(UCAL_IS_LEAP_MONTH, status): 0; 1483 // should consolidate the next section by using arrays of pointers & counts for the right symbols... 1484 if (count == 5) { 1485 if (patternCharIndex == UDAT_MONTH_FIELD) { 1486 _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount, 1487 (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): NULL, status); 1488 } else { 1489 _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount, 1490 (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): NULL, status); 1491 } 1492 capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow; 1493 } else if (count == 4) { 1494 if (patternCharIndex == UDAT_MONTH_FIELD) { 1495 _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount, 1496 (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): NULL, status); 1497 capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat; 1498 } else { 1499 _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, 1500 (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): NULL, status); 1501 capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone; 1502 } 1503 } else if (count == 3) { 1504 if (patternCharIndex == UDAT_MONTH_FIELD) { 1505 _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, 1506 (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): NULL, status); 1507 capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat; 1508 } else { 1509 _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, 1510 (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): NULL, status); 1511 capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone; 1512 } 1513 } else { 1514 UnicodeString monthNumber; 1515 zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount); 1516 _appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1, 1517 (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): NULL, status); 1518 } 1519 } 1520 break; 1521 1522 // for "k" and "kk", write out the hour, adjusting midnight to appear as "24" 1523 case UDAT_HOUR_OF_DAY1_FIELD: 1524 if (value == 0) 1525 zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount); 1526 else 1527 zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); 1528 break; 1529 1530 case UDAT_FRACTIONAL_SECOND_FIELD: 1531 // Fractional seconds left-justify 1532 { 1533 currentNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count); 1534 currentNumberFormat->setMaximumIntegerDigits(maxIntCount); 1535 if (count == 1) { 1536 value /= 100; 1537 } else if (count == 2) { 1538 value /= 10; 1539 } 1540 FieldPosition p(0); 1541 currentNumberFormat->format(value, appendTo, p); 1542 if (count > 3) { 1543 currentNumberFormat->setMinimumIntegerDigits(count - 3); 1544 currentNumberFormat->format((int32_t)0, appendTo, p); 1545 } 1546 } 1547 break; 1548 1549 // for "ee" or "e", use local numeric day-of-the-week 1550 // for "EEEEEE" or "eeeeee", write out the short day-of-the-week name 1551 // for "EEEEE" or "eeeee", write out the narrow day-of-the-week name 1552 // for "EEEE" or "eeee", write out the wide day-of-the-week name 1553 // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name 1554 case UDAT_DOW_LOCAL_FIELD: 1555 if ( count < 3 ) { 1556 zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); 1557 break; 1558 } 1559 // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week, 1560 // we want standard day-of-week, so first fix value to work for EEEEE-EEE. 1561 value = cal.get(UCAL_DAY_OF_WEEK, status); 1562 if (U_FAILURE(status)) { 1563 return; 1564 } 1565 // fall through, do not break here 1566 case UDAT_DAY_OF_WEEK_FIELD: 1567 if (count == 5) { 1568 _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays, 1569 fSymbols->fNarrowWeekdaysCount); 1570 capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow; 1571 } else if (count == 4) { 1572 _appendSymbol(appendTo, value, fSymbols->fWeekdays, 1573 fSymbols->fWeekdaysCount); 1574 capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat; 1575 } else if (count == 6) { 1576 _appendSymbol(appendTo, value, fSymbols->fShorterWeekdays, 1577 fSymbols->fShorterWeekdaysCount); 1578 capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat; 1579 } else { 1580 _appendSymbol(appendTo, value, fSymbols->fShortWeekdays, 1581 fSymbols->fShortWeekdaysCount); 1582 capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat; 1583 } 1584 break; 1585 1586 // for "ccc", write out the abbreviated day-of-the-week name 1587 // for "cccc", write out the wide day-of-the-week name 1588 // for "ccccc", use the narrow day-of-the-week name 1589 // for "ccccc", use the short day-of-the-week name 1590 case UDAT_STANDALONE_DAY_FIELD: 1591 if ( count < 3 ) { 1592 zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount); 1593 break; 1594 } 1595 // fall through to alpha DOW handling, but for that we don't want local day-of-week, 1596 // we want standard day-of-week, so first fix value. 1597 value = cal.get(UCAL_DAY_OF_WEEK, status); 1598 if (U_FAILURE(status)) { 1599 return; 1600 } 1601 if (count == 5) { 1602 _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays, 1603 fSymbols->fStandaloneNarrowWeekdaysCount); 1604 capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow; 1605 } else if (count == 4) { 1606 _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays, 1607 fSymbols->fStandaloneWeekdaysCount); 1608 capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone; 1609 } else if (count == 6) { 1610 _appendSymbol(appendTo, value, fSymbols->fStandaloneShorterWeekdays, 1611 fSymbols->fStandaloneShorterWeekdaysCount); 1612 capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone; 1613 } else { // count == 3 1614 _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays, 1615 fSymbols->fStandaloneShortWeekdaysCount); 1616 capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone; 1617 } 1618 break; 1619 1620 // for "a" symbol, write out the whole AM/PM string 1621 case UDAT_AM_PM_FIELD: 1622 if (count < 5) { 1623 _appendSymbol(appendTo, value, fSymbols->fAmPms, 1624 fSymbols->fAmPmsCount); 1625 } else { 1626 _appendSymbol(appendTo, value, fSymbols->fNarrowAmPms, 1627 fSymbols->fNarrowAmPmsCount); 1628 } 1629 break; 1630 1631 // for ":", write out the time separator string 1632 case UDAT_TIME_SEPARATOR_FIELD: 1633 { 1634 UnicodeString separator; 1635 appendTo += fSymbols->getTimeSeparatorString(separator); 1636 } 1637 break; 1638 1639 // for "h" and "hh", write out the hour, adjusting noon and midnight to show up 1640 // as "12" 1641 case UDAT_HOUR1_FIELD: 1642 if (value == 0) 1643 zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount); 1644 else 1645 zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); 1646 break; 1647 1648 case UDAT_TIMEZONE_FIELD: // 'z' 1649 case UDAT_TIMEZONE_RFC_FIELD: // 'Z' 1650 case UDAT_TIMEZONE_GENERIC_FIELD: // 'v' 1651 case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V' 1652 case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O' 1653 case UDAT_TIMEZONE_ISO_FIELD: // 'X' 1654 case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x' 1655 { 1656 UChar zsbuf[64]; 1657 UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf)); 1658 const TimeZone& tz = cal.getTimeZone(); 1659 UDate date = cal.getTime(status); 1660 if (U_SUCCESS(status)) { 1661 if (patternCharIndex == UDAT_TIMEZONE_FIELD) { 1662 if (count < 4) { 1663 // "z", "zz", "zzz" 1664 tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString); 1665 capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort; 1666 } else { 1667 // "zzzz" or longer 1668 tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString); 1669 capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong; 1670 } 1671 } 1672 else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) { 1673 if (count < 4) { 1674 // "Z" 1675 tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString); 1676 } else if (count == 5) { 1677 // "ZZZZZ" 1678 tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString); 1679 } else { 1680 // "ZZ", "ZZZ", "ZZZZ" 1681 tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString); 1682 } 1683 } 1684 else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) { 1685 if (count == 1) { 1686 // "v" 1687 tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString); 1688 capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort; 1689 } else if (count == 4) { 1690 // "vvvv" 1691 tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString); 1692 capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong; 1693 } 1694 } 1695 else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) { 1696 if (count == 1) { 1697 // "V" 1698 tzFormat()->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString); 1699 } else if (count == 2) { 1700 // "VV" 1701 tzFormat()->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString); 1702 } else if (count == 3) { 1703 // "VVV" 1704 tzFormat()->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString); 1705 } else if (count == 4) { 1706 // "VVVV" 1707 tzFormat()->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString); 1708 capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong; 1709 } 1710 } 1711 else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) { 1712 if (count == 1) { 1713 // "O" 1714 tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString); 1715 } else if (count == 4) { 1716 // "OOOO" 1717 tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString); 1718 } 1719 } 1720 else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) { 1721 if (count == 1) { 1722 // "X" 1723 tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString); 1724 } else if (count == 2) { 1725 // "XX" 1726 tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString); 1727 } else if (count == 3) { 1728 // "XXX" 1729 tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString); 1730 } else if (count == 4) { 1731 // "XXXX" 1732 tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString); 1733 } else if (count == 5) { 1734 // "XXXXX" 1735 tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString); 1736 } 1737 } 1738 else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) { 1739 if (count == 1) { 1740 // "x" 1741 tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString); 1742 } else if (count == 2) { 1743 // "xx" 1744 tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString); 1745 } else if (count == 3) { 1746 // "xxx" 1747 tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString); 1748 } else if (count == 4) { 1749 // "xxxx" 1750 tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString); 1751 } else if (count == 5) { 1752 // "xxxxx" 1753 tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString); 1754 } 1755 } 1756 else { 1757 U_ASSERT(FALSE); 1758 } 1759 } 1760 appendTo += zoneString; 1761 } 1762 break; 1763 1764 case UDAT_QUARTER_FIELD: 1765 if (count >= 4) 1766 _appendSymbol(appendTo, value/3, fSymbols->fQuarters, 1767 fSymbols->fQuartersCount); 1768 else if (count == 3) 1769 _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters, 1770 fSymbols->fShortQuartersCount); 1771 else 1772 zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount); 1773 break; 1774 1775 case UDAT_STANDALONE_QUARTER_FIELD: 1776 if (count >= 4) 1777 _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters, 1778 fSymbols->fStandaloneQuartersCount); 1779 else if (count == 3) 1780 _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters, 1781 fSymbols->fStandaloneShortQuartersCount); 1782 else 1783 zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount); 1784 break; 1785 1786 1787 // all of the other pattern symbols can be formatted as simple numbers with 1788 // appropriate zero padding 1789 default: 1790 zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); 1791 break; 1792 } 1793 #if !UCONFIG_NO_BREAK_ITERATION 1794 // if first field, check to see whether we need to and are able to titlecase it 1795 if (fieldNum == 0 && u_islower(appendTo.char32At(beginOffset)) && fCapitalizationBrkIter != NULL) { 1796 UBool titlecase = FALSE; 1797 switch (capitalizationContext) { 1798 case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE: 1799 titlecase = TRUE; 1800 break; 1801 case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU: 1802 titlecase = fSymbols->fCapitalization[capContextUsageType][0]; 1803 break; 1804 case UDISPCTX_CAPITALIZATION_FOR_STANDALONE: 1805 titlecase = fSymbols->fCapitalization[capContextUsageType][1]; 1806 break; 1807 default: 1808 // titlecase = FALSE; 1809 break; 1810 } 1811 if (titlecase) { 1812 UnicodeString firstField(appendTo, beginOffset); 1813 firstField.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT); 1814 appendTo.replaceBetween(beginOffset, appendTo.length(), firstField); 1815 } 1816 } 1817 #endif 1818 1819 handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length()); 1820 } 1821 1822 //---------------------------------------------------------------------- 1823 1824 void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) { 1825 fixNumberFormatForDates(*formatToAdopt); 1826 delete fNumberFormat; 1827 fNumberFormat = formatToAdopt; 1828 1829 // We successfully set the default number format. Now delete the overrides 1830 // (can't fail). 1831 if (fSharedNumberFormatters) { 1832 freeSharedNumberFormatters(fSharedNumberFormatters); 1833 fSharedNumberFormatters = NULL; 1834 } 1835 } 1836 1837 void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){ 1838 fixNumberFormatForDates(*formatToAdopt); 1839 LocalPointer<NumberFormat> fmt(formatToAdopt); 1840 if (U_FAILURE(status)) { 1841 return; 1842 } 1843 1844 // We must ensure fSharedNumberFormatters is allocated. 1845 if (fSharedNumberFormatters == NULL) { 1846 fSharedNumberFormatters = allocSharedNumberFormatters(); 1847 if (fSharedNumberFormatters == NULL) { 1848 status = U_MEMORY_ALLOCATION_ERROR; 1849 return; 1850 } 1851 } 1852 const SharedNumberFormat *newFormat = createSharedNumberFormat(fmt.orphan()); 1853 if (newFormat == NULL) { 1854 status = U_MEMORY_ALLOCATION_ERROR; 1855 return; 1856 } 1857 for (int i=0; i<fields.length(); i++) { 1858 UChar field = fields.charAt(i); 1859 // if the pattern character is unrecognized, signal an error and bail out 1860 UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(field); 1861 if (patternCharIndex == UDAT_FIELD_COUNT) { 1862 status = U_INVALID_FORMAT_ERROR; 1863 newFormat->deleteIfZeroRefCount(); 1864 return; 1865 } 1866 1867 // Set the number formatter in the table 1868 SharedObject::copyPtr( 1869 newFormat, fSharedNumberFormatters[patternCharIndex]); 1870 } 1871 newFormat->deleteIfZeroRefCount(); 1872 } 1873 1874 const NumberFormat * 1875 SimpleDateFormat::getNumberFormatForField(UChar field) const { 1876 UDateFormatField index = DateFormatSymbols::getPatternCharIndex(field); 1877 if (index == UDAT_FIELD_COUNT) { 1878 return NULL; 1879 } 1880 return getNumberFormatByIndex(index); 1881 } 1882 1883 //---------------------------------------------------------------------- 1884 void 1885 SimpleDateFormat::zeroPaddingNumber( 1886 NumberFormat *currentNumberFormat, 1887 UnicodeString &appendTo, 1888 int32_t value, int32_t minDigits, int32_t maxDigits) const 1889 { 1890 if (currentNumberFormat!=NULL) { 1891 FieldPosition pos(0); 1892 1893 currentNumberFormat->setMinimumIntegerDigits(minDigits); 1894 currentNumberFormat->setMaximumIntegerDigits(maxDigits); 1895 currentNumberFormat->format(value, appendTo, pos); // 3rd arg is there to speed up processing 1896 } 1897 } 1898 1899 //---------------------------------------------------------------------- 1900 1901 /** 1902 * Return true if the given format character, occuring count 1903 * times, represents a numeric field. 1904 */ 1905 UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) { 1906 return DateFormatSymbols::isNumericPatternChar(formatChar, count); 1907 } 1908 1909 UBool 1910 SimpleDateFormat::isAtNumericField(const UnicodeString &pattern, int32_t patternOffset) { 1911 if (patternOffset >= pattern.length()) { 1912 // not at any field 1913 return FALSE; 1914 } 1915 UChar ch = pattern.charAt(patternOffset); 1916 UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch); 1917 if (f == UDAT_FIELD_COUNT) { 1918 // not at any field 1919 return FALSE; 1920 } 1921 int32_t i = patternOffset; 1922 while (pattern.charAt(++i) == ch) {} 1923 return DateFormatSymbols::isNumericField(f, i - patternOffset); 1924 } 1925 1926 UBool 1927 SimpleDateFormat::isAfterNonNumericField(const UnicodeString &pattern, int32_t patternOffset) { 1928 if (patternOffset <= 0) { 1929 // not after any field 1930 return FALSE; 1931 } 1932 UChar ch = pattern.charAt(--patternOffset); 1933 UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch); 1934 if (f == UDAT_FIELD_COUNT) { 1935 // not after any field 1936 return FALSE; 1937 } 1938 int32_t i = patternOffset; 1939 while (pattern.charAt(--i) == ch) {} 1940 return !DateFormatSymbols::isNumericField(f, patternOffset - i); 1941 } 1942 1943 void 1944 SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const 1945 { 1946 UErrorCode status = U_ZERO_ERROR; 1947 int32_t pos = parsePos.getIndex(); 1948 if(parsePos.getIndex() < 0) { 1949 parsePos.setErrorIndex(0); 1950 return; 1951 } 1952 int32_t start = pos; 1953 1954 1955 UBool ambiguousYear[] = { FALSE }; 1956 int32_t saveHebrewMonth = -1; 1957 int32_t count = 0; 1958 UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; 1959 SimpleDateFormatMutableNFs mutableNFs; 1960 1961 // For parsing abutting numeric fields. 'abutPat' is the 1962 // offset into 'pattern' of the first of 2 or more abutting 1963 // numeric fields. 'abutStart' is the offset into 'text' 1964 // where parsing the fields begins. 'abutPass' starts off as 0 1965 // and increments each time we try to parse the fields. 1966 int32_t abutPat = -1; // If >=0, we are in a run of abutting numeric fields 1967 int32_t abutStart = 0; 1968 int32_t abutPass = 0; 1969 UBool inQuote = FALSE; 1970 1971 MessageFormat * numericLeapMonthFormatter = NULL; 1972 1973 Calendar* calClone = NULL; 1974 Calendar *workCal = &cal; 1975 if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) { 1976 // Different calendar type 1977 // We use the time/zone from the input calendar, but 1978 // do not use the input calendar for field calculation. 1979 calClone = fCalendar->clone(); 1980 if (calClone != NULL) { 1981 calClone->setTime(cal.getTime(status),status); 1982 if (U_FAILURE(status)) { 1983 goto ExitParse; 1984 } 1985 calClone->setTimeZone(cal.getTimeZone()); 1986 workCal = calClone; 1987 } else { 1988 status = U_MEMORY_ALLOCATION_ERROR; 1989 goto ExitParse; 1990 } 1991 } 1992 1993 if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) { 1994 numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status); 1995 if (numericLeapMonthFormatter == NULL) { 1996 status = U_MEMORY_ALLOCATION_ERROR; 1997 goto ExitParse; 1998 } else if (U_FAILURE(status)) { 1999 goto ExitParse; // this will delete numericLeapMonthFormatter 2000 } 2001 } 2002 2003 for (int32_t i=0; i<fPattern.length(); ++i) { 2004 UChar ch = fPattern.charAt(i); 2005 2006 // Handle alphabetic field characters. 2007 if (!inQuote && isSyntaxChar(ch)) { 2008 int32_t fieldPat = i; 2009 2010 // Count the length of this field specifier 2011 count = 1; 2012 while ((i+1)<fPattern.length() && 2013 fPattern.charAt(i+1) == ch) { 2014 ++count; 2015 ++i; 2016 } 2017 2018 if (isNumeric(ch, count)) { 2019 if (abutPat < 0) { 2020 // Determine if there is an abutting numeric field. 2021 // Record the start of a set of abutting numeric fields. 2022 if (isAtNumericField(fPattern, i + 1)) { 2023 abutPat = fieldPat; 2024 abutStart = pos; 2025 abutPass = 0; 2026 } 2027 } 2028 } else { 2029 abutPat = -1; // End of any abutting fields 2030 } 2031 2032 // Handle fields within a run of abutting numeric fields. Take 2033 // the pattern "HHmmss" as an example. We will try to parse 2034 // 2/2/2 characters of the input text, then if that fails, 2035 // 1/2/2. We only adjust the width of the leftmost field; the 2036 // others remain fixed. This allows "123456" => 12:34:56, but 2037 // "12345" => 1:23:45. Likewise, for the pattern "yyyyMMdd" we 2038 // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2. 2039 if (abutPat >= 0) { 2040 // If we are at the start of a run of abutting fields, then 2041 // shorten this field in each pass. If we can't shorten 2042 // this field any more, then the parse of this set of 2043 // abutting numeric fields has failed. 2044 if (fieldPat == abutPat) { 2045 count -= abutPass++; 2046 if (count == 0) { 2047 status = U_PARSE_ERROR; 2048 goto ExitParse; 2049 } 2050 } 2051 2052 pos = subParse(text, pos, ch, count, 2053 TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs); 2054 2055 // If the parse fails anywhere in the run, back up to the 2056 // start of the run and retry. 2057 if (pos < 0) { 2058 i = abutPat - 1; 2059 pos = abutStart; 2060 continue; 2061 } 2062 } 2063 2064 // Handle non-numeric fields and non-abutting numeric 2065 // fields. 2066 else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored 2067 int32_t s = subParse(text, pos, ch, count, 2068 FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs); 2069 2070 if (s == -pos-1) { 2071 // era not present, in special cases allow this to continue 2072 // from the position where the era was expected 2073 s = pos; 2074 2075 if (i+1 < fPattern.length()) { 2076 // move to next pattern character 2077 UChar ch = fPattern.charAt(i+1); 2078 2079 // check for whitespace 2080 if (PatternProps::isWhiteSpace(ch)) { 2081 i++; 2082 // Advance over run in pattern 2083 while ((i+1)<fPattern.length() && 2084 PatternProps::isWhiteSpace(fPattern.charAt(i+1))) { 2085 ++i; 2086 } 2087 } 2088 } 2089 } 2090 else if (s <= 0) { 2091 status = U_PARSE_ERROR; 2092 goto ExitParse; 2093 } 2094 pos = s; 2095 } 2096 } 2097 2098 // Handle literal pattern characters. These are any 2099 // quoted characters and non-alphabetic unquoted 2100 // characters. 2101 else { 2102 2103 abutPat = -1; // End of any abutting fields 2104 2105 if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status), isLenient())) { 2106 status = U_PARSE_ERROR; 2107 goto ExitParse; 2108 } 2109 } 2110 } 2111 2112 // Special hack for trailing "." after non-numeric field. 2113 if (text.charAt(pos) == 0x2e && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) { 2114 // only do if the last field is not numeric 2115 if (isAfterNonNumericField(fPattern, fPattern.length())) { 2116 pos++; // skip the extra "." 2117 } 2118 } 2119 2120 // At this point the fields of Calendar have been set. Calendar 2121 // will fill in default values for missing fields when the time 2122 // is computed. 2123 2124 parsePos.setIndex(pos); 2125 2126 // This part is a problem: When we call parsedDate.after, we compute the time. 2127 // Take the date April 3 2004 at 2:30 am. When this is first set up, the year 2128 // will be wrong if we're parsing a 2-digit year pattern. It will be 1904. 2129 // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day. 2:30 am 2130 // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am 2131 // on that day. It is therefore parsed out to fields as 3:30 am. Then we 2132 // add 100 years, and get April 3 2004 at 3:30 am. Note that April 3 2004 is 2133 // a Saturday, so it can have a 2:30 am -- and it should. [LIU] 2134 /* 2135 UDate parsedDate = calendar.getTime(); 2136 if( ambiguousYear[0] && !parsedDate.after(fDefaultCenturyStart) ) { 2137 calendar.add(Calendar.YEAR, 100); 2138 parsedDate = calendar.getTime(); 2139 } 2140 */ 2141 // Because of the above condition, save off the fields in case we need to readjust. 2142 // The procedure we use here is not particularly efficient, but there is no other 2143 // way to do this given the API restrictions present in Calendar. We minimize 2144 // inefficiency by only performing this computation when it might apply, that is, 2145 // when the two-digit year is equal to the start year, and thus might fall at the 2146 // front or the back of the default century. This only works because we adjust 2147 // the year correctly to start with in other cases -- see subParse(). 2148 if (ambiguousYear[0] || tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) // If this is true then the two-digit year == the default start year 2149 { 2150 // We need a copy of the fields, and we need to avoid triggering a call to 2151 // complete(), which will recalculate the fields. Since we can't access 2152 // the fields[] array in Calendar, we clone the entire object. This will 2153 // stop working if Calendar.clone() is ever rewritten to call complete(). 2154 Calendar *copy; 2155 if (ambiguousYear[0]) { 2156 copy = cal.clone(); 2157 // Check for failed cloning. 2158 if (copy == NULL) { 2159 status = U_MEMORY_ALLOCATION_ERROR; 2160 goto ExitParse; 2161 } 2162 UDate parsedDate = copy->getTime(status); 2163 // {sfb} check internalGetDefaultCenturyStart 2164 if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) { 2165 // We can't use add here because that does a complete() first. 2166 cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100); 2167 } 2168 delete copy; 2169 } 2170 2171 if (tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) { 2172 copy = cal.clone(); 2173 // Check for failed cloning. 2174 if (copy == NULL) { 2175 status = U_MEMORY_ALLOCATION_ERROR; 2176 goto ExitParse; 2177 } 2178 const TimeZone & tz = cal.getTimeZone(); 2179 BasicTimeZone *btz = NULL; 2180 2181 if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL 2182 || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL 2183 || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL 2184 || dynamic_cast<const VTimeZone *>(&tz) != NULL) { 2185 btz = (BasicTimeZone*)&tz; 2186 } 2187 2188 // Get local millis 2189 copy->set(UCAL_ZONE_OFFSET, 0); 2190 copy->set(UCAL_DST_OFFSET, 0); 2191 UDate localMillis = copy->getTime(status); 2192 2193 // Make sure parsed time zone type (Standard or Daylight) 2194 // matches the rule used by the parsed time zone. 2195 int32_t raw, dst; 2196 if (btz != NULL) { 2197 if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) { 2198 btz->getOffsetFromLocal(localMillis, 2199 BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status); 2200 } else { 2201 btz->getOffsetFromLocal(localMillis, 2202 BasicTimeZone::kDaylight, BasicTimeZone::kDaylight, raw, dst, status); 2203 } 2204 } else { 2205 // No good way to resolve ambiguous time at transition, 2206 // but following code work in most case. 2207 tz.getOffset(localMillis, TRUE, raw, dst, status); 2208 } 2209 2210 // Now, compare the results with parsed type, either standard or daylight saving time 2211 int32_t resolvedSavings = dst; 2212 if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) { 2213 if (dst != 0) { 2214 // Override DST_OFFSET = 0 in the result calendar 2215 resolvedSavings = 0; 2216 } 2217 } else { // tztype == TZTYPE_DST 2218 if (dst == 0) { 2219 if (btz != NULL) { 2220 UDate time = localMillis + raw; 2221 // We use the nearest daylight saving time rule. 2222 TimeZoneTransition beforeTrs, afterTrs; 2223 UDate beforeT = time, afterT = time; 2224 int32_t beforeSav = 0, afterSav = 0; 2225 UBool beforeTrsAvail, afterTrsAvail; 2226 2227 // Search for DST rule before or on the time 2228 while (TRUE) { 2229 beforeTrsAvail = btz->getPreviousTransition(beforeT, TRUE, beforeTrs); 2230 if (!beforeTrsAvail) { 2231 break; 2232 } 2233 beforeT = beforeTrs.getTime() - 1; 2234 beforeSav = beforeTrs.getFrom()->getDSTSavings(); 2235 if (beforeSav != 0) { 2236 break; 2237 } 2238 } 2239 2240 // Search for DST rule after the time 2241 while (TRUE) { 2242 afterTrsAvail = btz->getNextTransition(afterT, FALSE, afterTrs); 2243 if (!afterTrsAvail) { 2244 break; 2245 } 2246 afterT = afterTrs.getTime(); 2247 afterSav = afterTrs.getTo()->getDSTSavings(); 2248 if (afterSav != 0) { 2249 break; 2250 } 2251 } 2252 2253 if (beforeTrsAvail && afterTrsAvail) { 2254 if (time - beforeT > afterT - time) { 2255 resolvedSavings = afterSav; 2256 } else { 2257 resolvedSavings = beforeSav; 2258 } 2259 } else if (beforeTrsAvail && beforeSav != 0) { 2260 resolvedSavings = beforeSav; 2261 } else if (afterTrsAvail && afterSav != 0) { 2262 resolvedSavings = afterSav; 2263 } else { 2264 resolvedSavings = btz->getDSTSavings(); 2265 } 2266 } else { 2267 resolvedSavings = tz.getDSTSavings(); 2268 } 2269 if (resolvedSavings == 0) { 2270 // final fallback 2271 resolvedSavings = U_MILLIS_PER_HOUR; 2272 } 2273 } 2274 } 2275 cal.set(UCAL_ZONE_OFFSET, raw); 2276 cal.set(UCAL_DST_OFFSET, resolvedSavings); 2277 delete copy; 2278 } 2279 } 2280 ExitParse: 2281 // Set the parsed result if local calendar is used 2282 // instead of the input calendar 2283 if (U_SUCCESS(status) && workCal != &cal) { 2284 cal.setTimeZone(workCal->getTimeZone()); 2285 cal.setTime(workCal->getTime(status), status); 2286 } 2287 2288 if (numericLeapMonthFormatter != NULL) { 2289 delete numericLeapMonthFormatter; 2290 } 2291 if (calClone != NULL) { 2292 delete calClone; 2293 } 2294 2295 // If any Calendar calls failed, we pretend that we 2296 // couldn't parse the string, when in reality this isn't quite accurate-- 2297 // we did parse it; the Calendar calls just failed. 2298 if (U_FAILURE(status)) { 2299 parsePos.setErrorIndex(pos); 2300 parsePos.setIndex(start); 2301 } 2302 } 2303 2304 //---------------------------------------------------------------------- 2305 2306 static int32_t 2307 matchStringWithOptionalDot(const UnicodeString &text, 2308 int32_t index, 2309 const UnicodeString &data); 2310 2311 int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text, 2312 int32_t start, 2313 UCalendarDateFields field, 2314 const UnicodeString* data, 2315 int32_t dataCount, 2316 Calendar& cal) const 2317 { 2318 int32_t i = 0; 2319 int32_t count = dataCount; 2320 2321 // There may be multiple strings in the data[] array which begin with 2322 // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech). 2323 // We keep track of the longest match, and return that. Note that this 2324 // unfortunately requires us to test all array elements. 2325 int32_t bestMatchLength = 0, bestMatch = -1; 2326 UnicodeString bestMatchName; 2327 2328 for (; i < count; ++i) { 2329 int32_t matchLength = 0; 2330 if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) { 2331 bestMatchLength = matchLength; 2332 bestMatch = i; 2333 } 2334 } 2335 2336 if (bestMatch >= 0) { 2337 cal.set(field, bestMatch * 3); 2338 return start + bestMatchLength; 2339 } 2340 2341 return -start; 2342 } 2343 2344 //---------------------------------------------------------------------- 2345 UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern, 2346 int32_t &patternOffset, 2347 const UnicodeString &text, 2348 int32_t &textOffset, 2349 UBool whitespaceLenient, 2350 UBool partialMatchLenient, 2351 UBool oldLeniency) 2352 { 2353 UBool inQuote = FALSE; 2354 UnicodeString literal; 2355 int32_t i = patternOffset; 2356 2357 // scan pattern looking for contiguous literal characters 2358 for ( ; i < pattern.length(); i += 1) { 2359 UChar ch = pattern.charAt(i); 2360 2361 if (!inQuote && isSyntaxChar(ch)) { 2362 break; 2363 } 2364 2365 if (ch == QUOTE) { 2366 // Match a quote literal ('') inside OR outside of quotes 2367 if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) { 2368 i += 1; 2369 } else { 2370 inQuote = !inQuote; 2371 continue; 2372 } 2373 } 2374 2375 literal += ch; 2376 } 2377 2378 // at this point, literal contains the literal text 2379 // and i is the index of the next non-literal pattern character. 2380 int32_t p; 2381 int32_t t = textOffset; 2382 2383 if (whitespaceLenient) { 2384 // trim leading, trailing whitespace from 2385 // the literal text 2386 literal.trim(); 2387 2388 // ignore any leading whitespace in the text 2389 while (t < text.length() && u_isWhitespace(text.charAt(t))) { 2390 t += 1; 2391 } 2392 } 2393 2394 for (p = 0; p < literal.length() && t < text.length();) { 2395 UBool needWhitespace = FALSE; 2396 2397 while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) { 2398 needWhitespace = TRUE; 2399 p += 1; 2400 } 2401 2402 if (needWhitespace) { 2403 int32_t tStart = t; 2404 2405 while (t < text.length()) { 2406 UChar tch = text.charAt(t); 2407 2408 if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) { 2409 break; 2410 } 2411 2412 t += 1; 2413 } 2414 2415 // TODO: should we require internal spaces 2416 // in lenient mode? (There won't be any 2417 // leading or trailing spaces) 2418 if (!whitespaceLenient && t == tStart) { 2419 // didn't find matching whitespace: 2420 // an error in strict mode 2421 return FALSE; 2422 } 2423 2424 // In strict mode, this run of whitespace 2425 // may have been at the end. 2426 if (p >= literal.length()) { 2427 break; 2428 } 2429 } 2430 if (t >= text.length() || literal.charAt(p) != text.charAt(t)) { 2431 // Ran out of text, or found a non-matching character: 2432 // OK in lenient mode, an error in strict mode. 2433 if (whitespaceLenient) { 2434 if (t == textOffset && text.charAt(t) == 0x2e && 2435 isAfterNonNumericField(pattern, patternOffset)) { 2436 // Lenient mode and the literal input text begins with a "." and 2437 // we are after a non-numeric field: We skip the "." 2438 ++t; 2439 continue; // Do not update p. 2440 } 2441 // if it is actual whitespace and we're whitespace lenient it's OK 2442 2443 UChar wsc = text.charAt(t); 2444 if(PatternProps::isWhiteSpace(wsc)) { 2445 // Lenient mode and it's just whitespace we skip it 2446 ++t; 2447 continue; // Do not update p. 2448 } 2449 } 2450 // hack around oldleniency being a bit of a catch-all bucket and we're just adding support specifically for paritial matches 2451 if(partialMatchLenient && oldLeniency) { 2452 break; 2453 } 2454 2455 return FALSE; 2456 } 2457 ++p; 2458 ++t; 2459 } 2460 2461 // At this point if we're in strict mode we have a complete match. 2462 // If we're in lenient mode we may have a partial match, or no 2463 // match at all. 2464 if (p <= 0) { 2465 // no match. Pretend it matched a run of whitespace 2466 // and ignorables in the text. 2467 const UnicodeSet *ignorables = NULL; 2468 UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(pattern.charAt(i)); 2469 if (patternCharIndex != UDAT_FIELD_COUNT) { 2470 ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex); 2471 } 2472 2473 for (t = textOffset; t < text.length(); t += 1) { 2474 UChar ch = text.charAt(t); 2475 2476 if (ignorables == NULL || !ignorables->contains(ch)) { 2477 break; 2478 } 2479 } 2480 } 2481 2482 // if we get here, we've got a complete match. 2483 patternOffset = i - 1; 2484 textOffset = t; 2485 2486 return TRUE; 2487 } 2488 2489 //---------------------------------------------------------------------- 2490 2491 int32_t SimpleDateFormat::matchString(const UnicodeString& text, 2492 int32_t start, 2493 UCalendarDateFields field, 2494 const UnicodeString* data, 2495 int32_t dataCount, 2496 const UnicodeString* monthPattern, 2497 Calendar& cal) const 2498 { 2499 int32_t i = 0; 2500 int32_t count = dataCount; 2501 2502 if (field == UCAL_DAY_OF_WEEK) i = 1; 2503 2504 // There may be multiple strings in the data[] array which begin with 2505 // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech). 2506 // We keep track of the longest match, and return that. Note that this 2507 // unfortunately requires us to test all array elements. 2508 int32_t bestMatchLength = 0, bestMatch = -1; 2509 UnicodeString bestMatchName; 2510 int32_t isLeapMonth = 0; 2511 2512 for (; i < count; ++i) { 2513 int32_t matchLen = 0; 2514 if ((matchLen = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) { 2515 bestMatch = i; 2516 bestMatchLength = matchLen; 2517 } 2518 2519 if (monthPattern != NULL) { 2520 UErrorCode status = U_ZERO_ERROR; 2521 UnicodeString leapMonthName; 2522 Formattable monthName((const UnicodeString&)(data[i])); 2523 MessageFormat::format(*monthPattern, &monthName, 1, leapMonthName, status); 2524 if (U_SUCCESS(status)) { 2525 if ((matchLen = matchStringWithOptionalDot(text, start, leapMonthName)) > bestMatchLength) { 2526 bestMatch = i; 2527 bestMatchLength = matchLen; 2528 isLeapMonth = 1; 2529 } 2530 } 2531 } 2532 } 2533 2534 if (bestMatch >= 0) { 2535 if (field < UCAL_FIELD_COUNT) { 2536 // Adjustment for Hebrew Calendar month Adar II 2537 if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) { 2538 cal.set(field,6); 2539 } else { 2540 if (field == UCAL_YEAR) { 2541 bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60 2542 } 2543 cal.set(field, bestMatch); 2544 } 2545 if (monthPattern != NULL) { 2546 cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth); 2547 } 2548 } 2549 2550 return start + bestMatchLength; 2551 } 2552 2553 return -start; 2554 } 2555 2556 static int32_t 2557 matchStringWithOptionalDot(const UnicodeString &text, 2558 int32_t index, 2559 const UnicodeString &data) { 2560 UErrorCode sts = U_ZERO_ERROR; 2561 int32_t matchLenText = 0; 2562 int32_t matchLenData = 0; 2563 2564 u_caseInsensitivePrefixMatch(text.getBuffer() + index, text.length() - index, 2565 data.getBuffer(), data.length(), 2566 0 /* default case option */, 2567 &matchLenText, &matchLenData, 2568 &sts); 2569 U_ASSERT (U_SUCCESS(sts)); 2570 2571 if (matchLenData == data.length() /* normal match */ 2572 || (data.charAt(data.length() - 1) == 0x2e 2573 && matchLenData == data.length() - 1 /* match without trailing dot */)) { 2574 return matchLenText; 2575 } 2576 2577 return 0; 2578 } 2579 2580 //---------------------------------------------------------------------- 2581 2582 void 2583 SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status) 2584 { 2585 parseAmbiguousDatesAsAfter(d, status); 2586 } 2587 2588 /** 2589 * Private member function that converts the parsed date strings into 2590 * timeFields. Returns -start (for ParsePosition) if failed. 2591 */ 2592 int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count, 2593 UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal, 2594 int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs) const 2595 { 2596 Formattable number; 2597 int32_t value = 0; 2598 int32_t i; 2599 int32_t ps = 0; 2600 UErrorCode status = U_ZERO_ERROR; 2601 ParsePosition pos(0); 2602 UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch); 2603 NumberFormat *currentNumberFormat; 2604 UnicodeString temp; 2605 UBool gotNumber = FALSE; 2606 2607 #if defined (U_DEBUG_CAL) 2608 //fprintf(stderr, "%s:%d - [%c] st=%d \n", __FILE__, __LINE__, (char) ch, start); 2609 #endif 2610 2611 if (patternCharIndex == UDAT_FIELD_COUNT) { 2612 return -start; 2613 } 2614 2615 currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex)); 2616 if (currentNumberFormat == NULL) { 2617 return -start; 2618 } 2619 UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; // UCAL_FIELD_COUNT if irrelevant 2620 UnicodeString hebr("hebr", 4, US_INV); 2621 2622 if (numericLeapMonthFormatter != NULL) { 2623 numericLeapMonthFormatter->setFormats((const Format **)¤tNumberFormat, 1); 2624 } 2625 UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0); 2626 2627 // If there are any spaces here, skip over them. If we hit the end 2628 // of the string, then fail. 2629 for (;;) { 2630 if (start >= text.length()) { 2631 return -start; 2632 } 2633 UChar32 c = text.char32At(start); 2634 if (!u_isUWhiteSpace(c) /*||*/ && !PatternProps::isWhiteSpace(c)) { 2635 break; 2636 } 2637 start += U16_LENGTH(c); 2638 } 2639 pos.setIndex(start); 2640 2641 // We handle a few special cases here where we need to parse 2642 // a number value. We handle further, more generic cases below. We need 2643 // to handle some of them here because some fields require extra processing on 2644 // the parsed value. 2645 if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD || // k 2646 patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD || // H 2647 patternCharIndex == UDAT_HOUR1_FIELD || // h 2648 patternCharIndex == UDAT_HOUR0_FIELD || // K 2649 (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) || // e 2650 (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) || // c 2651 (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) || // M 2652 (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) || // L 2653 (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) || // Q 2654 (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || // q 2655 patternCharIndex == UDAT_YEAR_FIELD || // y 2656 patternCharIndex == UDAT_YEAR_WOY_FIELD || // Y 2657 patternCharIndex == UDAT_YEAR_NAME_FIELD || // U (falls back to numeric) 2658 (patternCharIndex == UDAT_ERA_FIELD && isChineseCalendar) || // G 2659 patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD) // S 2660 { 2661 int32_t parseStart = pos.getIndex(); 2662 // It would be good to unify this with the obeyCount logic below, 2663 // but that's going to be difficult. 2664 const UnicodeString* src; 2665 2666 UBool parsedNumericLeapMonth = FALSE; 2667 if (numericLeapMonthFormatter != NULL && (patternCharIndex == UDAT_MONTH_FIELD || patternCharIndex == UDAT_STANDALONE_MONTH_FIELD)) { 2668 int32_t argCount; 2669 Formattable * args = numericLeapMonthFormatter->parse(text, pos, argCount); 2670 if (args != NULL && argCount == 1 && pos.getIndex() > parseStart && args[0].isNumeric()) { 2671 parsedNumericLeapMonth = TRUE; 2672 number.setLong(args[0].getLong()); 2673 cal.set(UCAL_IS_LEAP_MONTH, 1); 2674 delete[] args; 2675 } else { 2676 pos.setIndex(parseStart); 2677 cal.set(UCAL_IS_LEAP_MONTH, 0); 2678 } 2679 } 2680 2681 if (!parsedNumericLeapMonth) { 2682 if (obeyCount) { 2683 if ((start+count) > text.length()) { 2684 return -start; 2685 } 2686 2687 text.extractBetween(0, start + count, temp); 2688 src = &temp; 2689 } else { 2690 src = &text; 2691 } 2692 2693 parseInt(*src, number, pos, allowNegative,currentNumberFormat); 2694 } 2695 2696 int32_t txtLoc = pos.getIndex(); 2697 2698 if (txtLoc > parseStart) { 2699 value = number.getLong(); 2700 gotNumber = TRUE; 2701 2702 // suffix processing 2703 if (value < 0 ) { 2704 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE); 2705 if (txtLoc != pos.getIndex()) { 2706 value *= -1; 2707 } 2708 } 2709 else { 2710 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE); 2711 } 2712 2713 if (!getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) { 2714 // Check the range of the value 2715 int32_t bias = gFieldRangeBias[patternCharIndex]; 2716 if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) { 2717 return -start; 2718 } 2719 } 2720 2721 pos.setIndex(txtLoc); 2722 } 2723 } 2724 2725 // Make sure that we got a number if 2726 // we want one, and didn't get one 2727 // if we don't want one. 2728 switch (patternCharIndex) { 2729 case UDAT_HOUR_OF_DAY1_FIELD: 2730 case UDAT_HOUR_OF_DAY0_FIELD: 2731 case UDAT_HOUR1_FIELD: 2732 case UDAT_HOUR0_FIELD: 2733 // special range check for hours: 2734 if (value < 0 || value > 24) { 2735 return -start; 2736 } 2737 2738 // fall through to gotNumber check 2739 2740 case UDAT_YEAR_FIELD: 2741 case UDAT_YEAR_WOY_FIELD: 2742 case UDAT_FRACTIONAL_SECOND_FIELD: 2743 // these must be a number 2744 if (! gotNumber) { 2745 return -start; 2746 } 2747 2748 break; 2749 2750 default: 2751 // we check the rest of the fields below. 2752 break; 2753 } 2754 2755 switch (patternCharIndex) { 2756 case UDAT_ERA_FIELD: 2757 if (isChineseCalendar) { 2758 if (!gotNumber) { 2759 return -start; 2760 } 2761 cal.set(UCAL_ERA, value); 2762 return pos.getIndex(); 2763 } 2764 if (count == 5) { 2765 ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, NULL, cal); 2766 } else if (count == 4) { 2767 ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, NULL, cal); 2768 } else { 2769 ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, NULL, cal); 2770 } 2771 2772 // check return position, if it equals -start, then matchString error 2773 // special case the return code so we don't necessarily fail out until we 2774 // verify no year information also 2775 if (ps == -start) 2776 ps--; 2777 2778 return ps; 2779 2780 case UDAT_YEAR_FIELD: 2781 // If there are 3 or more YEAR pattern characters, this indicates 2782 // that the year value is to be treated literally, without any 2783 // two-digit year adjustments (e.g., from "01" to 2001). Otherwise 2784 // we made adjustments to place the 2-digit year in the proper 2785 // century, for parsed strings from "00" to "99". Any other string 2786 // is treated literally: "2250", "-1", "1", "002". 2787 if (fDateOverride.compare(hebr)==0 && value < 1000) { 2788 value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR; 2789 } else if ((pos.getIndex() - start) == 2 && !isChineseCalendar 2790 && u_isdigit(text.charAt(start)) 2791 && u_isdigit(text.charAt(start+1))) 2792 { 2793 // only adjust year for patterns less than 3. 2794 if(count < 3) { 2795 // Assume for example that the defaultCenturyStart is 6/18/1903. 2796 // This means that two-digit years will be forced into the range 2797 // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02 2798 // correspond to 2000, 2001, and 2002. Years 04, 05, etc. correspond 2799 // to 1904, 1905, etc. If the year is 03, then it is 2003 if the 2800 // other fields specify a date before 6/18, or 1903 if they specify a 2801 // date afterwards. As a result, 03 is an ambiguous year. All other 2802 // two-digit years are unambiguous. 2803 if(fHaveDefaultCentury) { // check if this formatter even has a pivot year 2804 int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100; 2805 ambiguousYear[0] = (value == ambiguousTwoDigitYear); 2806 value += (fDefaultCenturyStartYear/100)*100 + 2807 (value < ambiguousTwoDigitYear ? 100 : 0); 2808 } 2809 } 2810 } 2811 cal.set(UCAL_YEAR, value); 2812 2813 // Delayed checking for adjustment of Hebrew month numbers in non-leap years. 2814 if (saveHebrewMonth >= 0) { 2815 HebrewCalendar *hc = (HebrewCalendar*)&cal; 2816 if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) { 2817 cal.set(UCAL_MONTH,saveHebrewMonth); 2818 } else { 2819 cal.set(UCAL_MONTH,saveHebrewMonth-1); 2820 } 2821 saveHebrewMonth = -1; 2822 } 2823 return pos.getIndex(); 2824 2825 case UDAT_YEAR_WOY_FIELD: 2826 // Comment is the same as for UDAT_Year_FIELDs - look above 2827 if (fDateOverride.compare(hebr)==0 && value < 1000) { 2828 value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR; 2829 } else if ((pos.getIndex() - start) == 2 2830 && u_isdigit(text.charAt(start)) 2831 && u_isdigit(text.charAt(start+1)) 2832 && fHaveDefaultCentury ) 2833 { 2834 int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100; 2835 ambiguousYear[0] = (value == ambiguousTwoDigitYear); 2836 value += (fDefaultCenturyStartYear/100)*100 + 2837 (value < ambiguousTwoDigitYear ? 100 : 0); 2838 } 2839 cal.set(UCAL_YEAR_WOY, value); 2840 return pos.getIndex(); 2841 2842 case UDAT_YEAR_NAME_FIELD: 2843 if (fSymbols->fShortYearNames != NULL) { 2844 int32_t newStart = matchString(text, start, UCAL_YEAR, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount, NULL, cal); 2845 if (newStart > 0) { 2846 return newStart; 2847 } 2848 } 2849 if (gotNumber && (getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC,status) || value > fSymbols->fShortYearNamesCount)) { 2850 cal.set(UCAL_YEAR, value); 2851 return pos.getIndex(); 2852 } 2853 return -start; 2854 2855 case UDAT_MONTH_FIELD: 2856 case UDAT_STANDALONE_MONTH_FIELD: 2857 if (gotNumber) // i.e., M or MM. 2858 { 2859 // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether 2860 // or not it was a leap year. We may or may not yet know what year it is, so might have to delay checking until 2861 // the year is parsed. 2862 if (!strcmp(cal.getType(),"hebrew")) { 2863 HebrewCalendar *hc = (HebrewCalendar*)&cal; 2864 if (cal.isSet(UCAL_YEAR)) { 2865 UErrorCode status = U_ZERO_ERROR; 2866 if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) { 2867 cal.set(UCAL_MONTH, value); 2868 } else { 2869 cal.set(UCAL_MONTH, value - 1); 2870 } 2871 } else { 2872 saveHebrewMonth = value; 2873 } 2874 } else { 2875 // Don't want to parse the month if it is a string 2876 // while pattern uses numeric style: M/MM, L/LL 2877 // [We computed 'value' above.] 2878 cal.set(UCAL_MONTH, value - 1); 2879 } 2880 return pos.getIndex(); 2881 } else { 2882 // count >= 3 // i.e., MMM/MMMM, LLL/LLLL 2883 // Want to be able to parse both short and long forms. 2884 // Try count == 4 first: 2885 UnicodeString * wideMonthPat = NULL; 2886 UnicodeString * shortMonthPat = NULL; 2887 if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) { 2888 if (patternCharIndex==UDAT_MONTH_FIELD) { 2889 wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]; 2890 shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]; 2891 } else { 2892 wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]; 2893 shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]; 2894 } 2895 } 2896 int32_t newStart = 0; 2897 if (patternCharIndex==UDAT_MONTH_FIELD) { 2898 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { 2899 newStart = matchString(text, start, UCAL_MONTH, fSymbols->fMonths, fSymbols->fMonthsCount, wideMonthPat, cal); // try MMMM 2900 if (newStart > 0) { 2901 return newStart; 2902 } 2903 } 2904 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { 2905 newStart = matchString(text, start, UCAL_MONTH, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, shortMonthPat, cal); // try MMM 2906 } 2907 } else { 2908 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { 2909 newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, wideMonthPat, cal); // try LLLL 2910 if (newStart > 0) { 2911 return newStart; 2912 } 2913 } 2914 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { 2915 newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, shortMonthPat, cal); // try LLL 2916 } 2917 } 2918 if (newStart > 0 || !getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) // currently we do not try to parse MMMMM/LLLLL: #8860 2919 return newStart; 2920 // else we allowing parsing as number, below 2921 } 2922 break; 2923 2924 case UDAT_HOUR_OF_DAY1_FIELD: 2925 // [We computed 'value' above.] 2926 if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1) 2927 value = 0; 2928 2929 // fall through to set field 2930 2931 case UDAT_HOUR_OF_DAY0_FIELD: 2932 cal.set(UCAL_HOUR_OF_DAY, value); 2933 return pos.getIndex(); 2934 2935 case UDAT_FRACTIONAL_SECOND_FIELD: 2936 // Fractional seconds left-justify 2937 i = pos.getIndex() - start; 2938 if (i < 3) { 2939 while (i < 3) { 2940 value *= 10; 2941 i++; 2942 } 2943 } else { 2944 int32_t a = 1; 2945 while (i > 3) { 2946 a *= 10; 2947 i--; 2948 } 2949 value /= a; 2950 } 2951 cal.set(UCAL_MILLISECOND, value); 2952 return pos.getIndex(); 2953 2954 case UDAT_DOW_LOCAL_FIELD: 2955 if (gotNumber) // i.e., e or ee 2956 { 2957 // [We computed 'value' above.] 2958 cal.set(UCAL_DOW_LOCAL, value); 2959 return pos.getIndex(); 2960 } 2961 // else for eee-eeeee fall through to handling of EEE-EEEEE 2962 // fall through, do not break here 2963 case UDAT_DAY_OF_WEEK_FIELD: 2964 { 2965 // Want to be able to parse both short and long forms. 2966 // Try count == 4 (EEEE) wide first: 2967 int32_t newStart = 0; 2968 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { 2969 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 2970 fSymbols->fWeekdays, fSymbols->fWeekdaysCount, NULL, cal)) > 0) 2971 return newStart; 2972 } 2973 // EEEE wide failed, now try EEE abbreviated 2974 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { 2975 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 2976 fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, NULL, cal)) > 0) 2977 return newStart; 2978 } 2979 // EEE abbreviated failed, now try EEEEEE short 2980 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) { 2981 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 2982 fSymbols->fShorterWeekdays, fSymbols->fShorterWeekdaysCount, NULL, cal)) > 0) 2983 return newStart; 2984 } 2985 // EEEEEE short failed, now try EEEEE narrow 2986 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) { 2987 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 2988 fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, NULL, cal)) > 0) 2989 return newStart; 2990 } 2991 if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status) || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD) 2992 return newStart; 2993 // else we allowing parsing as number, below 2994 } 2995 break; 2996 2997 case UDAT_STANDALONE_DAY_FIELD: 2998 { 2999 if (gotNumber) // c or cc 3000 { 3001 // [We computed 'value' above.] 3002 cal.set(UCAL_DOW_LOCAL, value); 3003 return pos.getIndex(); 3004 } 3005 // Want to be able to parse both short and long forms. 3006 // Try count == 4 (cccc) first: 3007 int32_t newStart = 0; 3008 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { 3009 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 3010 fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, NULL, cal)) > 0) 3011 return newStart; 3012 } 3013 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { 3014 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 3015 fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, NULL, cal)) > 0) 3016 return newStart; 3017 } 3018 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) { 3019 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 3020 fSymbols->fStandaloneShorterWeekdays, fSymbols->fStandaloneShorterWeekdaysCount, NULL, cal)) > 0) 3021 return newStart; 3022 } 3023 if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) 3024 return newStart; 3025 // else we allowing parsing as number, below 3026 } 3027 break; 3028 3029 case UDAT_AM_PM_FIELD: 3030 { 3031 // optionally try both wide/abbrev and narrow forms 3032 int32_t newStart = 0; 3033 // try wide/abbrev 3034 if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count < 5 ) { 3035 if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal)) > 0) { 3036 return newStart; 3037 } 3038 } 3039 // try narrow 3040 if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count >= 5 ) { 3041 if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fNarrowAmPms, fSymbols->fNarrowAmPmsCount, NULL, cal)) > 0) { 3042 return newStart; 3043 } 3044 } 3045 // no matches for given options 3046 return -start; 3047 } 3048 3049 case UDAT_HOUR1_FIELD: 3050 // [We computed 'value' above.] 3051 if (value == cal.getLeastMaximum(UCAL_HOUR)+1) 3052 value = 0; 3053 3054 // fall through to set field 3055 3056 case UDAT_HOUR0_FIELD: 3057 cal.set(UCAL_HOUR, value); 3058 return pos.getIndex(); 3059 3060 case UDAT_QUARTER_FIELD: 3061 if (gotNumber) // i.e., Q or QQ. 3062 { 3063 // Don't want to parse the month if it is a string 3064 // while pattern uses numeric style: Q or QQ. 3065 // [We computed 'value' above.] 3066 cal.set(UCAL_MONTH, (value - 1) * 3); 3067 return pos.getIndex(); 3068 } else { 3069 // count >= 3 // i.e., QQQ or QQQQ 3070 // Want to be able to parse both short and long forms. 3071 // Try count == 4 first: 3072 int32_t newStart = 0; 3073 3074 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { 3075 if ((newStart = matchQuarterString(text, start, UCAL_MONTH, 3076 fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0) 3077 return newStart; 3078 } 3079 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { 3080 if ((newStart = matchQuarterString(text, start, UCAL_MONTH, 3081 fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0) 3082 return newStart; 3083 } 3084 if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) 3085 return newStart; 3086 // else we allowing parsing as number, below 3087 if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)) 3088 return -start; 3089 } 3090 break; 3091 3092 case UDAT_STANDALONE_QUARTER_FIELD: 3093 if (gotNumber) // i.e., q or qq. 3094 { 3095 // Don't want to parse the month if it is a string 3096 // while pattern uses numeric style: q or q. 3097 // [We computed 'value' above.] 3098 cal.set(UCAL_MONTH, (value - 1) * 3); 3099 return pos.getIndex(); 3100 } else { 3101 // count >= 3 // i.e., qqq or qqqq 3102 // Want to be able to parse both short and long forms. 3103 // Try count == 4 first: 3104 int32_t newStart = 0; 3105 3106 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) { 3107 if ((newStart = matchQuarterString(text, start, UCAL_MONTH, 3108 fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0) 3109 return newStart; 3110 } 3111 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) { 3112 if ((newStart = matchQuarterString(text, start, UCAL_MONTH, 3113 fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0) 3114 return newStart; 3115 } 3116 if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) 3117 return newStart; 3118 // else we allowing parsing as number, below 3119 if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)) 3120 return -start; 3121 } 3122 break; 3123 3124 case UDAT_TIMEZONE_FIELD: // 'z' 3125 { 3126 UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG; 3127 TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); 3128 if (tz != NULL) { 3129 cal.adoptTimeZone(tz); 3130 return pos.getIndex(); 3131 } 3132 } 3133 break; 3134 case UDAT_TIMEZONE_RFC_FIELD: // 'Z' 3135 { 3136 UTimeZoneFormatStyle style = (count < 4) ? 3137 UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT); 3138 TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); 3139 if (tz != NULL) { 3140 cal.adoptTimeZone(tz); 3141 return pos.getIndex(); 3142 } 3143 return -start; 3144 } 3145 case UDAT_TIMEZONE_GENERIC_FIELD: // 'v' 3146 { 3147 UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG; 3148 TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); 3149 if (tz != NULL) { 3150 cal.adoptTimeZone(tz); 3151 return pos.getIndex(); 3152 } 3153 return -start; 3154 } 3155 case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V' 3156 { 3157 UTimeZoneFormatStyle style; 3158 switch (count) { 3159 case 1: 3160 style = UTZFMT_STYLE_ZONE_ID_SHORT; 3161 break; 3162 case 2: 3163 style = UTZFMT_STYLE_ZONE_ID; 3164 break; 3165 case 3: 3166 style = UTZFMT_STYLE_EXEMPLAR_LOCATION; 3167 break; 3168 default: 3169 style = UTZFMT_STYLE_GENERIC_LOCATION; 3170 break; 3171 } 3172 TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); 3173 if (tz != NULL) { 3174 cal.adoptTimeZone(tz); 3175 return pos.getIndex(); 3176 } 3177 return -start; 3178 } 3179 case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O' 3180 { 3181 UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT; 3182 TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); 3183 if (tz != NULL) { 3184 cal.adoptTimeZone(tz); 3185 return pos.getIndex(); 3186 } 3187 return -start; 3188 } 3189 case UDAT_TIMEZONE_ISO_FIELD: // 'X' 3190 { 3191 UTimeZoneFormatStyle style; 3192 switch (count) { 3193 case 1: 3194 style = UTZFMT_STYLE_ISO_BASIC_SHORT; 3195 break; 3196 case 2: 3197 style = UTZFMT_STYLE_ISO_BASIC_FIXED; 3198 break; 3199 case 3: 3200 style = UTZFMT_STYLE_ISO_EXTENDED_FIXED; 3201 break; 3202 case 4: 3203 style = UTZFMT_STYLE_ISO_BASIC_FULL; 3204 break; 3205 default: 3206 style = UTZFMT_STYLE_ISO_EXTENDED_FULL; 3207 break; 3208 } 3209 TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); 3210 if (tz != NULL) { 3211 cal.adoptTimeZone(tz); 3212 return pos.getIndex(); 3213 } 3214 return -start; 3215 } 3216 case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x' 3217 { 3218 UTimeZoneFormatStyle style; 3219 switch (count) { 3220 case 1: 3221 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT; 3222 break; 3223 case 2: 3224 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED; 3225 break; 3226 case 3: 3227 style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED; 3228 break; 3229 case 4: 3230 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL; 3231 break; 3232 default: 3233 style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL; 3234 break; 3235 } 3236 TimeZone *tz = tzFormat()->parse(style, text, pos, tzTimeType); 3237 if (tz != NULL) { 3238 cal.adoptTimeZone(tz); 3239 return pos.getIndex(); 3240 } 3241 return -start; 3242 } 3243 case UDAT_TIME_SEPARATOR_FIELD: // ':' 3244 { 3245 static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR; 3246 static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR; 3247 3248 // Try matching a time separator. 3249 int32_t count = 1; 3250 UnicodeString data[3]; 3251 fSymbols->getTimeSeparatorString(data[0]); 3252 3253 // Add the default, if different from the locale. 3254 if (data[0].compare(&def_sep, 1) != 0) { 3255 data[count++].setTo(def_sep); 3256 } 3257 3258 // If lenient, add also the alternate, if different from the locale. 3259 if (isLenient() && data[0].compare(&alt_sep, 1) != 0) { 3260 data[count++].setTo(alt_sep); 3261 } 3262 3263 return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count, NULL, cal); 3264 } 3265 3266 default: 3267 // Handle "generic" fields 3268 // this is now handled below, outside the switch block 3269 break; 3270 } 3271 // Handle "generic" fields: 3272 // switch default case now handled here (outside switch block) to allow 3273 // parsing of some string fields as digits for lenient case 3274 3275 int32_t parseStart = pos.getIndex(); 3276 const UnicodeString* src; 3277 if (obeyCount) { 3278 if ((start+count) > text.length()) { 3279 return -start; 3280 } 3281 text.extractBetween(0, start + count, temp); 3282 src = &temp; 3283 } else { 3284 src = &text; 3285 } 3286 parseInt(*src, number, pos, allowNegative,currentNumberFormat); 3287 if (pos.getIndex() != parseStart) { 3288 int32_t value = number.getLong(); 3289 3290 // Don't need suffix processing here (as in number processing at the beginning of the function); 3291 // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes. 3292 3293 if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) { 3294 // Check the range of the value 3295 int32_t bias = gFieldRangeBias[patternCharIndex]; 3296 if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) { 3297 return -start; 3298 } 3299 } 3300 3301 // For the following, need to repeat some of the "if (gotNumber)" code above: 3302 // UDAT_[STANDALONE_]MONTH_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_STANDALONE_DAY_FIELD, 3303 // UDAT_[STANDALONE_]QUARTER_FIELD 3304 switch (patternCharIndex) { 3305 case UDAT_MONTH_FIELD: 3306 // See notes under UDAT_MONTH_FIELD case above 3307 if (!strcmp(cal.getType(),"hebrew")) { 3308 HebrewCalendar *hc = (HebrewCalendar*)&cal; 3309 if (cal.isSet(UCAL_YEAR)) { 3310 UErrorCode status = U_ZERO_ERROR; 3311 if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) { 3312 cal.set(UCAL_MONTH, value); 3313 } else { 3314 cal.set(UCAL_MONTH, value - 1); 3315 } 3316 } else { 3317 saveHebrewMonth = value; 3318 } 3319 } else { 3320 cal.set(UCAL_MONTH, value - 1); 3321 } 3322 break; 3323 case UDAT_STANDALONE_MONTH_FIELD: 3324 cal.set(UCAL_MONTH, value - 1); 3325 break; 3326 case UDAT_DOW_LOCAL_FIELD: 3327 case UDAT_STANDALONE_DAY_FIELD: 3328 cal.set(UCAL_DOW_LOCAL, value); 3329 break; 3330 case UDAT_QUARTER_FIELD: 3331 case UDAT_STANDALONE_QUARTER_FIELD: 3332 cal.set(UCAL_MONTH, (value - 1) * 3); 3333 break; 3334 case UDAT_RELATED_YEAR_FIELD: 3335 cal.setRelatedYear(value); 3336 break; 3337 default: 3338 cal.set(field, value); 3339 break; 3340 } 3341 return pos.getIndex(); 3342 } 3343 return -start; 3344 } 3345 3346 /** 3347 * Parse an integer using fNumberFormat. This method is semantically 3348 * const, but actually may modify fNumberFormat. 3349 */ 3350 void SimpleDateFormat::parseInt(const UnicodeString& text, 3351 Formattable& number, 3352 ParsePosition& pos, 3353 UBool allowNegative, 3354 NumberFormat *fmt) const { 3355 parseInt(text, number, -1, pos, allowNegative,fmt); 3356 } 3357 3358 /** 3359 * Parse an integer using fNumberFormat up to maxDigits. 3360 */ 3361 void SimpleDateFormat::parseInt(const UnicodeString& text, 3362 Formattable& number, 3363 int32_t maxDigits, 3364 ParsePosition& pos, 3365 UBool allowNegative, 3366 NumberFormat *fmt) const { 3367 UnicodeString oldPrefix; 3368 DecimalFormat* df = NULL; 3369 if (!allowNegative && (df = dynamic_cast<DecimalFormat*>(fmt)) != NULL) { 3370 df->getNegativePrefix(oldPrefix); 3371 df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1)); 3372 } 3373 int32_t oldPos = pos.getIndex(); 3374 fmt->parse(text, number, pos); 3375 if (df != NULL) { 3376 df->setNegativePrefix(oldPrefix); 3377 } 3378 3379 if (maxDigits > 0) { 3380 // adjust the result to fit into 3381 // the maxDigits and move the position back 3382 int32_t nDigits = pos.getIndex() - oldPos; 3383 if (nDigits > maxDigits) { 3384 int32_t val = number.getLong(); 3385 nDigits -= maxDigits; 3386 while (nDigits > 0) { 3387 val /= 10; 3388 nDigits--; 3389 } 3390 pos.setIndex(oldPos + maxDigits); 3391 number.setLong(val); 3392 } 3393 } 3394 } 3395 3396 //---------------------------------------------------------------------- 3397 3398 void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern, 3399 UnicodeString& translatedPattern, 3400 const UnicodeString& from, 3401 const UnicodeString& to, 3402 UErrorCode& status) 3403 { 3404 // run through the pattern and convert any pattern symbols from the version 3405 // in "from" to the corresponding character ion "to". This code takes 3406 // quoted strings into account (it doesn't try to translate them), and it signals 3407 // an error if a particular "pattern character" doesn't appear in "from". 3408 // Depending on the values of "from" and "to" this can convert from generic 3409 // to localized patterns or localized to generic. 3410 if (U_FAILURE(status)) { 3411 return; 3412 } 3413 3414 translatedPattern.remove(); 3415 UBool inQuote = FALSE; 3416 for (int32_t i = 0; i < originalPattern.length(); ++i) { 3417 UChar c = originalPattern[i]; 3418 if (inQuote) { 3419 if (c == QUOTE) { 3420 inQuote = FALSE; 3421 } 3422 } else { 3423 if (c == QUOTE) { 3424 inQuote = TRUE; 3425 } else if (isSyntaxChar(c)) { 3426 int32_t ci = from.indexOf(c); 3427 if (ci == -1) { 3428 status = U_INVALID_FORMAT_ERROR; 3429 return; 3430 } 3431 c = to[ci]; 3432 } 3433 } 3434 translatedPattern += c; 3435 } 3436 if (inQuote) { 3437 status = U_INVALID_FORMAT_ERROR; 3438 return; 3439 } 3440 } 3441 3442 //---------------------------------------------------------------------- 3443 3444 UnicodeString& 3445 SimpleDateFormat::toPattern(UnicodeString& result) const 3446 { 3447 result = fPattern; 3448 return result; 3449 } 3450 3451 //---------------------------------------------------------------------- 3452 3453 UnicodeString& 3454 SimpleDateFormat::toLocalizedPattern(UnicodeString& result, 3455 UErrorCode& status) const 3456 { 3457 translatePattern(fPattern, result, 3458 UnicodeString(DateFormatSymbols::getPatternUChars()), 3459 fSymbols->fLocalPatternChars, status); 3460 return result; 3461 } 3462 3463 //---------------------------------------------------------------------- 3464 3465 void 3466 SimpleDateFormat::applyPattern(const UnicodeString& pattern) 3467 { 3468 fPattern = pattern; 3469 } 3470 3471 //---------------------------------------------------------------------- 3472 3473 void 3474 SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern, 3475 UErrorCode &status) 3476 { 3477 translatePattern(pattern, fPattern, 3478 fSymbols->fLocalPatternChars, 3479 UnicodeString(DateFormatSymbols::getPatternUChars()), status); 3480 } 3481 3482 //---------------------------------------------------------------------- 3483 3484 const DateFormatSymbols* 3485 SimpleDateFormat::getDateFormatSymbols() const 3486 { 3487 return fSymbols; 3488 } 3489 3490 //---------------------------------------------------------------------- 3491 3492 void 3493 SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols) 3494 { 3495 delete fSymbols; 3496 fSymbols = newFormatSymbols; 3497 } 3498 3499 //---------------------------------------------------------------------- 3500 void 3501 SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols) 3502 { 3503 delete fSymbols; 3504 fSymbols = new DateFormatSymbols(newFormatSymbols); 3505 } 3506 3507 //---------------------------------------------------------------------- 3508 const TimeZoneFormat* 3509 SimpleDateFormat::getTimeZoneFormat(void) const { 3510 return (const TimeZoneFormat*)tzFormat(); 3511 } 3512 3513 //---------------------------------------------------------------------- 3514 void 3515 SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt) 3516 { 3517 delete fTimeZoneFormat; 3518 fTimeZoneFormat = timeZoneFormatToAdopt; 3519 } 3520 3521 //---------------------------------------------------------------------- 3522 void 3523 SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat) 3524 { 3525 delete fTimeZoneFormat; 3526 fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat); 3527 } 3528 3529 //---------------------------------------------------------------------- 3530 3531 3532 void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt) 3533 { 3534 UErrorCode status = U_ZERO_ERROR; 3535 Locale calLocale(fLocale); 3536 calLocale.setKeywordValue("calendar", calendarToAdopt->getType(), status); 3537 DateFormatSymbols *newSymbols = 3538 DateFormatSymbols::createForLocale(calLocale, status); 3539 if (U_FAILURE(status)) { 3540 return; 3541 } 3542 DateFormat::adoptCalendar(calendarToAdopt); 3543 delete fSymbols; 3544 fSymbols = newSymbols; 3545 initializeDefaultCentury(); // we need a new century (possibly) 3546 } 3547 3548 3549 //---------------------------------------------------------------------- 3550 3551 3552 // override the DateFormat implementation in order to 3553 // lazily initialize fCapitalizationBrkIter 3554 void 3555 SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status) 3556 { 3557 DateFormat::setContext(value, status); 3558 #if !UCONFIG_NO_BREAK_ITERATION 3559 if (U_SUCCESS(status)) { 3560 if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || 3561 value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) { 3562 UErrorCode status = U_ZERO_ERROR; 3563 fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status); 3564 if (U_FAILURE(status)) { 3565 delete fCapitalizationBrkIter; 3566 fCapitalizationBrkIter = NULL; 3567 } 3568 } 3569 } 3570 #endif 3571 } 3572 3573 3574 //---------------------------------------------------------------------- 3575 3576 3577 UBool 3578 SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const { 3579 return isFieldUnitIgnored(fPattern, field); 3580 } 3581 3582 3583 UBool 3584 SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern, 3585 UCalendarDateFields field) { 3586 int32_t fieldLevel = fgCalendarFieldToLevel[field]; 3587 int32_t level; 3588 UChar ch; 3589 UBool inQuote = FALSE; 3590 UChar prevCh = 0; 3591 int32_t count = 0; 3592 3593 for (int32_t i = 0; i < pattern.length(); ++i) { 3594 ch = pattern[i]; 3595 if (ch != prevCh && count > 0) { 3596 level = getLevelFromChar(prevCh); 3597 // the larger the level, the smaller the field unit. 3598 if (fieldLevel <= level) { 3599 return FALSE; 3600 } 3601 count = 0; 3602 } 3603 if (ch == QUOTE) { 3604 if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) { 3605 ++i; 3606 } else { 3607 inQuote = ! inQuote; 3608 } 3609 } 3610 else if (!inQuote && isSyntaxChar(ch)) { 3611 prevCh = ch; 3612 ++count; 3613 } 3614 } 3615 if (count > 0) { 3616 // last item 3617 level = getLevelFromChar(prevCh); 3618 if (fieldLevel <= level) { 3619 return FALSE; 3620 } 3621 } 3622 return TRUE; 3623 } 3624 3625 //---------------------------------------------------------------------- 3626 3627 const Locale& 3628 SimpleDateFormat::getSmpFmtLocale(void) const { 3629 return fLocale; 3630 } 3631 3632 //---------------------------------------------------------------------- 3633 3634 int32_t 3635 SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start, 3636 int32_t patLoc, UBool isNegative) const { 3637 // local variables 3638 UnicodeString suf; 3639 int32_t patternMatch; 3640 int32_t textPreMatch; 3641 int32_t textPostMatch; 3642 3643 // check that we are still in range 3644 if ( (start > text.length()) || 3645 (start < 0) || 3646 (patLoc < 0) || 3647 (patLoc > fPattern.length())) { 3648 // out of range, don't advance location in text 3649 return start; 3650 } 3651 3652 // get the suffix 3653 DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat); 3654 if (decfmt != NULL) { 3655 if (isNegative) { 3656 suf = decfmt->getNegativeSuffix(suf); 3657 } 3658 else { 3659 suf = decfmt->getPositiveSuffix(suf); 3660 } 3661 } 3662 3663 // check for suffix 3664 if (suf.length() <= 0) { 3665 return start; 3666 } 3667 3668 // check suffix will be encountered in the pattern 3669 patternMatch = compareSimpleAffix(suf,fPattern,patLoc); 3670 3671 // check if a suffix will be encountered in the text 3672 textPreMatch = compareSimpleAffix(suf,text,start); 3673 3674 // check if a suffix was encountered in the text 3675 textPostMatch = compareSimpleAffix(suf,text,start-suf.length()); 3676 3677 // check for suffix match 3678 if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) { 3679 return start; 3680 } 3681 else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) { 3682 return start - suf.length(); 3683 } 3684 3685 // should not get here 3686 return start; 3687 } 3688 3689 //---------------------------------------------------------------------- 3690 3691 int32_t 3692 SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix, 3693 const UnicodeString& input, 3694 int32_t pos) const { 3695 int32_t start = pos; 3696 for (int32_t i=0; i<affix.length(); ) { 3697 UChar32 c = affix.char32At(i); 3698 int32_t len = U16_LENGTH(c); 3699 if (PatternProps::isWhiteSpace(c)) { 3700 // We may have a pattern like: \u200F \u0020 3701 // and input text like: \u200F \u0020 3702 // Note that U+200F and U+0020 are Pattern_White_Space but only 3703 // U+0020 is UWhiteSpace. So we have to first do a direct 3704 // match of the run of Pattern_White_Space in the pattern, 3705 // then match any extra characters. 3706 UBool literalMatch = FALSE; 3707 while (pos < input.length() && 3708 input.char32At(pos) == c) { 3709 literalMatch = TRUE; 3710 i += len; 3711 pos += len; 3712 if (i == affix.length()) { 3713 break; 3714 } 3715 c = affix.char32At(i); 3716 len = U16_LENGTH(c); 3717 if (!PatternProps::isWhiteSpace(c)) { 3718 break; 3719 } 3720 } 3721 3722 // Advance over run in pattern 3723 i = skipPatternWhiteSpace(affix, i); 3724 3725 // Advance over run in input text 3726 // Must see at least one white space char in input, 3727 // unless we've already matched some characters literally. 3728 int32_t s = pos; 3729 pos = skipUWhiteSpace(input, pos); 3730 if (pos == s && !literalMatch) { 3731 return -1; 3732 } 3733 3734 // If we skip UWhiteSpace in the input text, we need to skip it in the pattern. 3735 // Otherwise, the previous lines may have skipped over text (such as U+00A0) that 3736 // is also in the affix. 3737 i = skipUWhiteSpace(affix, i); 3738 } else { 3739 if (pos < input.length() && 3740 input.char32At(pos) == c) { 3741 i += len; 3742 pos += len; 3743 } else { 3744 return -1; 3745 } 3746 } 3747 } 3748 return pos - start; 3749 } 3750 3751 //---------------------------------------------------------------------- 3752 3753 int32_t 3754 SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const { 3755 const UChar* s = text.getBuffer(); 3756 return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s); 3757 } 3758 3759 //---------------------------------------------------------------------- 3760 3761 int32_t 3762 SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const { 3763 while (pos < text.length()) { 3764 UChar32 c = text.char32At(pos); 3765 if (!u_isUWhiteSpace(c)) { 3766 break; 3767 } 3768 pos += U16_LENGTH(c); 3769 } 3770 return pos; 3771 } 3772 3773 //---------------------------------------------------------------------- 3774 3775 // Lazy TimeZoneFormat instantiation, semantically const. 3776 TimeZoneFormat * 3777 SimpleDateFormat::tzFormat() const { 3778 if (fTimeZoneFormat == NULL) { 3779 umtx_lock(&LOCK); 3780 { 3781 if (fTimeZoneFormat == NULL) { 3782 UErrorCode status = U_ZERO_ERROR; 3783 TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status); 3784 if (U_FAILURE(status)) { 3785 return NULL; 3786 } 3787 3788 const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt; 3789 } 3790 } 3791 umtx_unlock(&LOCK); 3792 } 3793 return fTimeZoneFormat; 3794 } 3795 3796 U_NAMESPACE_END 3797 3798 #endif /* #if !UCONFIG_NO_FORMATTING */ 3799 3800 //eof 3801