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