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