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