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