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