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