1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/smpdtfmt.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3554 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* Copyright (C) 1997-2013, International Business Machines Corporation and * 1.7 +* others. All Rights Reserved. * 1.8 +******************************************************************************* 1.9 +* 1.10 +* File SMPDTFMT.CPP 1.11 +* 1.12 +* Modification History: 1.13 +* 1.14 +* Date Name Description 1.15 +* 02/19/97 aliu Converted from java. 1.16 +* 03/31/97 aliu Modified extensively to work with 50 locales. 1.17 +* 04/01/97 aliu Added support for centuries. 1.18 +* 07/09/97 helena Made ParsePosition into a class. 1.19 +* 07/21/98 stephen Added initializeDefaultCentury. 1.20 +* Removed getZoneIndex (added in DateFormatSymbols) 1.21 +* Removed subParseLong 1.22 +* Removed chk 1.23 +* 02/22/99 stephen Removed character literals for EBCDIC safety 1.24 +* 10/14/99 aliu Updated 2-digit year parsing so that only "00" thru 1.25 +* "99" are recognized. {j28 4182066} 1.26 +* 11/15/99 weiv Added support for week of year/day of week format 1.27 +******************************************************************************** 1.28 +*/ 1.29 + 1.30 +#define ZID_KEY_MAX 128 1.31 + 1.32 +#include "unicode/utypes.h" 1.33 + 1.34 +#if !UCONFIG_NO_FORMATTING 1.35 + 1.36 +#include "unicode/smpdtfmt.h" 1.37 +#include "unicode/dtfmtsym.h" 1.38 +#include "unicode/ures.h" 1.39 +#include "unicode/msgfmt.h" 1.40 +#include "unicode/calendar.h" 1.41 +#include "unicode/gregocal.h" 1.42 +#include "unicode/timezone.h" 1.43 +#include "unicode/decimfmt.h" 1.44 +#include "unicode/dcfmtsym.h" 1.45 +#include "unicode/uchar.h" 1.46 +#include "unicode/uniset.h" 1.47 +#include "unicode/ustring.h" 1.48 +#include "unicode/basictz.h" 1.49 +#include "unicode/simpletz.h" 1.50 +#include "unicode/rbtz.h" 1.51 +#include "unicode/tzfmt.h" 1.52 +#include "unicode/utf16.h" 1.53 +#include "unicode/vtzone.h" 1.54 +#include "unicode/udisplaycontext.h" 1.55 +#include "olsontz.h" 1.56 +#include "patternprops.h" 1.57 +#include "fphdlimp.h" 1.58 +#include "gregoimp.h" 1.59 +#include "hebrwcal.h" 1.60 +#include "cstring.h" 1.61 +#include "uassert.h" 1.62 +#include "cmemory.h" 1.63 +#include "umutex.h" 1.64 +#include <float.h> 1.65 +#include "smpdtfst.h" 1.66 + 1.67 +#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL) 1.68 +#include <stdio.h> 1.69 +#endif 1.70 + 1.71 +// ***************************************************************************** 1.72 +// class SimpleDateFormat 1.73 +// ***************************************************************************** 1.74 + 1.75 +U_NAMESPACE_BEGIN 1.76 + 1.77 +static const UChar PATTERN_CHAR_BASE = 0x40; 1.78 + 1.79 +/** 1.80 + * Last-resort string to use for "GMT" when constructing time zone strings. 1.81 + */ 1.82 +// For time zones that have no names, use strings GMT+minutes and 1.83 +// GMT-minutes. For instance, in France the time zone is GMT+60. 1.84 +// Also accepted are GMT+H:MM or GMT-H:MM. 1.85 +// Currently not being used 1.86 +//static const UChar gGmt[] = {0x0047, 0x004D, 0x0054, 0x0000}; // "GMT" 1.87 +//static const UChar gGmtPlus[] = {0x0047, 0x004D, 0x0054, 0x002B, 0x0000}; // "GMT+" 1.88 +//static const UChar gGmtMinus[] = {0x0047, 0x004D, 0x0054, 0x002D, 0x0000}; // "GMT-" 1.89 +//static const UChar gDefGmtPat[] = {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */ 1.90 +//static const UChar gDefGmtNegHmsPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* -HH:mm:ss */ 1.91 +//static const UChar gDefGmtNegHmPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* -HH:mm */ 1.92 +//static const UChar gDefGmtPosHmsPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* +HH:mm:ss */ 1.93 +//static const UChar gDefGmtPosHmPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* +HH:mm */ 1.94 +//static const UChar gUt[] = {0x0055, 0x0054, 0x0000}; // "UT" 1.95 +//static const UChar gUtc[] = {0x0055, 0x0054, 0x0043, 0x0000}; // "UT" 1.96 + 1.97 +typedef enum GmtPatSize { 1.98 + kGmtLen = 3, 1.99 + kGmtPatLen = 6, 1.100 + kNegHmsLen = 9, 1.101 + kNegHmLen = 6, 1.102 + kPosHmsLen = 9, 1.103 + kPosHmLen = 6, 1.104 + kUtLen = 2, 1.105 + kUtcLen = 3 1.106 +} GmtPatSize; 1.107 + 1.108 +// Stuff needed for numbering system overrides 1.109 + 1.110 +typedef enum OvrStrType { 1.111 + kOvrStrDate = 0, 1.112 + kOvrStrTime = 1, 1.113 + kOvrStrBoth = 2 1.114 +} OvrStrType; 1.115 + 1.116 +static const UDateFormatField kDateFields[] = { 1.117 + UDAT_YEAR_FIELD, 1.118 + UDAT_MONTH_FIELD, 1.119 + UDAT_DATE_FIELD, 1.120 + UDAT_DAY_OF_YEAR_FIELD, 1.121 + UDAT_DAY_OF_WEEK_IN_MONTH_FIELD, 1.122 + UDAT_WEEK_OF_YEAR_FIELD, 1.123 + UDAT_WEEK_OF_MONTH_FIELD, 1.124 + UDAT_YEAR_WOY_FIELD, 1.125 + UDAT_EXTENDED_YEAR_FIELD, 1.126 + UDAT_JULIAN_DAY_FIELD, 1.127 + UDAT_STANDALONE_DAY_FIELD, 1.128 + UDAT_STANDALONE_MONTH_FIELD, 1.129 + UDAT_QUARTER_FIELD, 1.130 + UDAT_STANDALONE_QUARTER_FIELD, 1.131 + UDAT_YEAR_NAME_FIELD }; 1.132 +static const int8_t kDateFieldsCount = 15; 1.133 + 1.134 +static const UDateFormatField kTimeFields[] = { 1.135 + UDAT_HOUR_OF_DAY1_FIELD, 1.136 + UDAT_HOUR_OF_DAY0_FIELD, 1.137 + UDAT_MINUTE_FIELD, 1.138 + UDAT_SECOND_FIELD, 1.139 + UDAT_FRACTIONAL_SECOND_FIELD, 1.140 + UDAT_HOUR1_FIELD, 1.141 + UDAT_HOUR0_FIELD, 1.142 + UDAT_MILLISECONDS_IN_DAY_FIELD, 1.143 + UDAT_TIMEZONE_RFC_FIELD, 1.144 + UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD }; 1.145 +static const int8_t kTimeFieldsCount = 10; 1.146 + 1.147 + 1.148 +// This is a pattern-of-last-resort used when we can't load a usable pattern out 1.149 +// of a resource. 1.150 +static const UChar gDefaultPattern[] = 1.151 +{ 1.152 + 0x79, 0x79, 0x79, 0x79, 0x4D, 0x4D, 0x64, 0x64, 0x20, 0x68, 0x68, 0x3A, 0x6D, 0x6D, 0x20, 0x61, 0 1.153 +}; /* "yyyyMMdd hh:mm a" */ 1.154 + 1.155 +// This prefix is designed to NEVER MATCH real text, in order to 1.156 +// suppress the parsing of negative numbers. Adjust as needed (if 1.157 +// this becomes valid Unicode). 1.158 +static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0}; 1.159 + 1.160 +/** 1.161 + * These are the tags we expect to see in normal resource bundle files associated 1.162 + * with a locale. 1.163 + */ 1.164 +static const char gDateTimePatternsTag[]="DateTimePatterns"; 1.165 + 1.166 +//static const UChar gEtcUTC[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x54, 0x43, 0x00}; // "Etc/UTC" 1.167 +static const UChar QUOTE = 0x27; // Single quote 1.168 + 1.169 +/* 1.170 + * The field range check bias for each UDateFormatField. 1.171 + * The bias is added to the minimum and maximum values 1.172 + * before they are compared to the parsed number. 1.173 + * For example, the calendar stores zero-based month numbers 1.174 + * but the parsed month numbers start at 1, so the bias is 1. 1.175 + * 1.176 + * A value of -1 means that the value is not checked. 1.177 + */ 1.178 +static const int32_t gFieldRangeBias[] = { 1.179 + -1, // 'G' - UDAT_ERA_FIELD 1.180 + -1, // 'y' - UDAT_YEAR_FIELD 1.181 + 1, // 'M' - UDAT_MONTH_FIELD 1.182 + 0, // 'd' - UDAT_DATE_FIELD 1.183 + -1, // 'k' - UDAT_HOUR_OF_DAY1_FIELD 1.184 + -1, // 'H' - UDAT_HOUR_OF_DAY0_FIELD 1.185 + 0, // 'm' - UDAT_MINUTE_FIELD 1.186 + 0, // 's' - UDAT_SEOND_FIELD 1.187 + -1, // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?) 1.188 + -1, // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?) 1.189 + -1, // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?) 1.190 + -1, // 'F' - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD (1-5?) 1.191 + -1, // 'w' - UDAT_WEEK_OF_YEAR_FIELD (1-52?) 1.192 + -1, // 'W' - UDAT_WEEK_OF_MONTH_FIELD (1-5?) 1.193 + -1, // 'a' - UDAT_AM_PM_FIELD 1.194 + -1, // 'h' - UDAT_HOUR1_FIELD 1.195 + -1, // 'K' - UDAT_HOUR0_FIELD 1.196 + -1, // 'z' - UDAT_TIMEZONE_FIELD 1.197 + -1, // 'Y' - UDAT_YEAR_WOY_FIELD 1.198 + -1, // 'e' - UDAT_DOW_LOCAL_FIELD 1.199 + -1, // 'u' - UDAT_EXTENDED_YEAR_FIELD 1.200 + -1, // 'g' - UDAT_JULIAN_DAY_FIELD 1.201 + -1, // 'A' - UDAT_MILLISECONDS_IN_DAY_FIELD 1.202 + -1, // 'Z' - UDAT_TIMEZONE_RFC_FIELD 1.203 + -1, // 'v' - UDAT_TIMEZONE_GENERIC_FIELD 1.204 + 0, // 'c' - UDAT_STANDALONE_DAY_FIELD 1.205 + 1, // 'L' - UDAT_STANDALONE_MONTH_FIELD 1.206 + -1, // 'Q' - UDAT_QUARTER_FIELD (1-4?) 1.207 + -1, // 'q' - UDAT_STANDALONE_QUARTER_FIELD 1.208 + -1 // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD 1.209 + -1, // 'U' - UDAT_YEAR_NAME_FIELD 1.210 + -1, // 'O' - UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD 1.211 + -1, // 'X' - UDAT_TIMEZONE_ISO_FIELD 1.212 + -1, // 'x' - UDAT_TIMEZONE_ISO_LOCAL_FIELD 1.213 +}; 1.214 + 1.215 +// When calendar uses hebr numbering (i.e. he@calendar=hebrew), 1.216 +// offset the years within the current millenium down to 1-999 1.217 +static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000; 1.218 +static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000; 1.219 + 1.220 +static UMutex LOCK = U_MUTEX_INITIALIZER; 1.221 + 1.222 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat) 1.223 + 1.224 +//---------------------------------------------------------------------- 1.225 + 1.226 +SimpleDateFormat::~SimpleDateFormat() 1.227 +{ 1.228 + delete fSymbols; 1.229 + if (fNumberFormatters) { 1.230 + uprv_free(fNumberFormatters); 1.231 + } 1.232 + if (fTimeZoneFormat) { 1.233 + delete fTimeZoneFormat; 1.234 + } 1.235 + 1.236 + while (fOverrideList) { 1.237 + NSOverride *cur = fOverrideList; 1.238 + fOverrideList = cur->next; 1.239 + delete cur->nf; 1.240 + uprv_free(cur); 1.241 + } 1.242 +} 1.243 + 1.244 +//---------------------------------------------------------------------- 1.245 + 1.246 +SimpleDateFormat::SimpleDateFormat(UErrorCode& status) 1.247 + : fLocale(Locale::getDefault()), 1.248 + fSymbols(NULL), 1.249 + fTimeZoneFormat(NULL), 1.250 + fNumberFormatters(NULL), 1.251 + fOverrideList(NULL), 1.252 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.253 +{ 1.254 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.255 + construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status); 1.256 + initializeDefaultCentury(); 1.257 +} 1.258 + 1.259 +//---------------------------------------------------------------------- 1.260 + 1.261 +SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 1.262 + UErrorCode &status) 1.263 +: fPattern(pattern), 1.264 + fLocale(Locale::getDefault()), 1.265 + fSymbols(NULL), 1.266 + fTimeZoneFormat(NULL), 1.267 + fNumberFormatters(NULL), 1.268 + fOverrideList(NULL), 1.269 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.270 +{ 1.271 + fDateOverride.setToBogus(); 1.272 + fTimeOverride.setToBogus(); 1.273 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.274 + initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); 1.275 + initialize(fLocale, status); 1.276 + initializeDefaultCentury(); 1.277 + 1.278 +} 1.279 +//---------------------------------------------------------------------- 1.280 + 1.281 +SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 1.282 + const UnicodeString& override, 1.283 + UErrorCode &status) 1.284 +: fPattern(pattern), 1.285 + fLocale(Locale::getDefault()), 1.286 + fSymbols(NULL), 1.287 + fTimeZoneFormat(NULL), 1.288 + fNumberFormatters(NULL), 1.289 + fOverrideList(NULL), 1.290 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.291 +{ 1.292 + fDateOverride.setTo(override); 1.293 + fTimeOverride.setToBogus(); 1.294 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.295 + initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); 1.296 + initialize(fLocale, status); 1.297 + initializeDefaultCentury(); 1.298 + 1.299 + processOverrideString(fLocale,override,kOvrStrBoth,status); 1.300 + 1.301 +} 1.302 + 1.303 +//---------------------------------------------------------------------- 1.304 + 1.305 +SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 1.306 + const Locale& locale, 1.307 + UErrorCode& status) 1.308 +: fPattern(pattern), 1.309 + fLocale(locale), 1.310 + fTimeZoneFormat(NULL), 1.311 + fNumberFormatters(NULL), 1.312 + fOverrideList(NULL), 1.313 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.314 +{ 1.315 + 1.316 + fDateOverride.setToBogus(); 1.317 + fTimeOverride.setToBogus(); 1.318 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.319 + 1.320 + initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); 1.321 + initialize(fLocale, status); 1.322 + initializeDefaultCentury(); 1.323 +} 1.324 + 1.325 +//---------------------------------------------------------------------- 1.326 + 1.327 +SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 1.328 + const UnicodeString& override, 1.329 + const Locale& locale, 1.330 + UErrorCode& status) 1.331 +: fPattern(pattern), 1.332 + fLocale(locale), 1.333 + fTimeZoneFormat(NULL), 1.334 + fNumberFormatters(NULL), 1.335 + fOverrideList(NULL), 1.336 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.337 +{ 1.338 + 1.339 + fDateOverride.setTo(override); 1.340 + fTimeOverride.setToBogus(); 1.341 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.342 + 1.343 + initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); 1.344 + initialize(fLocale, status); 1.345 + initializeDefaultCentury(); 1.346 + 1.347 + processOverrideString(locale,override,kOvrStrBoth,status); 1.348 + 1.349 +} 1.350 + 1.351 +//---------------------------------------------------------------------- 1.352 + 1.353 +SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 1.354 + DateFormatSymbols* symbolsToAdopt, 1.355 + UErrorCode& status) 1.356 +: fPattern(pattern), 1.357 + fLocale(Locale::getDefault()), 1.358 + fSymbols(symbolsToAdopt), 1.359 + fTimeZoneFormat(NULL), 1.360 + fNumberFormatters(NULL), 1.361 + fOverrideList(NULL), 1.362 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.363 +{ 1.364 + 1.365 + fDateOverride.setToBogus(); 1.366 + fTimeOverride.setToBogus(); 1.367 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.368 + 1.369 + initializeCalendar(NULL,fLocale,status); 1.370 + initialize(fLocale, status); 1.371 + initializeDefaultCentury(); 1.372 +} 1.373 + 1.374 +//---------------------------------------------------------------------- 1.375 + 1.376 +SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, 1.377 + const DateFormatSymbols& symbols, 1.378 + UErrorCode& status) 1.379 +: fPattern(pattern), 1.380 + fLocale(Locale::getDefault()), 1.381 + fSymbols(new DateFormatSymbols(symbols)), 1.382 + fTimeZoneFormat(NULL), 1.383 + fNumberFormatters(NULL), 1.384 + fOverrideList(NULL), 1.385 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.386 +{ 1.387 + 1.388 + fDateOverride.setToBogus(); 1.389 + fTimeOverride.setToBogus(); 1.390 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.391 + 1.392 + initializeCalendar(NULL, fLocale, status); 1.393 + initialize(fLocale, status); 1.394 + initializeDefaultCentury(); 1.395 +} 1.396 + 1.397 +//---------------------------------------------------------------------- 1.398 + 1.399 +// Not for public consumption; used by DateFormat 1.400 +SimpleDateFormat::SimpleDateFormat(EStyle timeStyle, 1.401 + EStyle dateStyle, 1.402 + const Locale& locale, 1.403 + UErrorCode& status) 1.404 +: fLocale(locale), 1.405 + fSymbols(NULL), 1.406 + fTimeZoneFormat(NULL), 1.407 + fNumberFormatters(NULL), 1.408 + fOverrideList(NULL), 1.409 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.410 +{ 1.411 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.412 + construct(timeStyle, dateStyle, fLocale, status); 1.413 + if(U_SUCCESS(status)) { 1.414 + initializeDefaultCentury(); 1.415 + } 1.416 +} 1.417 + 1.418 +//---------------------------------------------------------------------- 1.419 + 1.420 +/** 1.421 + * Not for public consumption; used by DateFormat. This constructor 1.422 + * never fails. If the resource data is not available, it uses the 1.423 + * the last resort symbols. 1.424 + */ 1.425 +SimpleDateFormat::SimpleDateFormat(const Locale& locale, 1.426 + UErrorCode& status) 1.427 +: fPattern(gDefaultPattern), 1.428 + fLocale(locale), 1.429 + fSymbols(NULL), 1.430 + fTimeZoneFormat(NULL), 1.431 + fNumberFormatters(NULL), 1.432 + fOverrideList(NULL), 1.433 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.434 +{ 1.435 + if (U_FAILURE(status)) return; 1.436 + initializeSymbols(fLocale, initializeCalendar(NULL, fLocale, status),status); 1.437 + if (U_FAILURE(status)) 1.438 + { 1.439 + status = U_ZERO_ERROR; 1.440 + delete fSymbols; 1.441 + // This constructor doesn't fail; it uses last resort data 1.442 + fSymbols = new DateFormatSymbols(status); 1.443 + /* test for NULL */ 1.444 + if (fSymbols == 0) { 1.445 + status = U_MEMORY_ALLOCATION_ERROR; 1.446 + return; 1.447 + } 1.448 + } 1.449 + 1.450 + fDateOverride.setToBogus(); 1.451 + fTimeOverride.setToBogus(); 1.452 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.453 + 1.454 + initialize(fLocale, status); 1.455 + if(U_SUCCESS(status)) { 1.456 + initializeDefaultCentury(); 1.457 + } 1.458 +} 1.459 + 1.460 +//---------------------------------------------------------------------- 1.461 + 1.462 +SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other) 1.463 +: DateFormat(other), 1.464 + fLocale(other.fLocale), 1.465 + fSymbols(NULL), 1.466 + fTimeZoneFormat(NULL), 1.467 + fNumberFormatters(NULL), 1.468 + fOverrideList(NULL), 1.469 + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 1.470 +{ 1.471 + UErrorCode status = U_ZERO_ERROR; 1.472 + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); 1.473 + *this = other; 1.474 +} 1.475 + 1.476 +//---------------------------------------------------------------------- 1.477 + 1.478 +SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other) 1.479 +{ 1.480 + if (this == &other) { 1.481 + return *this; 1.482 + } 1.483 + DateFormat::operator=(other); 1.484 + 1.485 + delete fSymbols; 1.486 + fSymbols = NULL; 1.487 + 1.488 + if (other.fSymbols) 1.489 + fSymbols = new DateFormatSymbols(*other.fSymbols); 1.490 + 1.491 + fDefaultCenturyStart = other.fDefaultCenturyStart; 1.492 + fDefaultCenturyStartYear = other.fDefaultCenturyStartYear; 1.493 + fHaveDefaultCentury = other.fHaveDefaultCentury; 1.494 + 1.495 + fPattern = other.fPattern; 1.496 + 1.497 + // TimeZoneFormat in ICU4C only depends on a locale for now 1.498 + if (fLocale != other.fLocale) { 1.499 + delete fTimeZoneFormat; 1.500 + fTimeZoneFormat = NULL; // forces lazy instantiation with the other locale 1.501 + fLocale = other.fLocale; 1.502 + } 1.503 + 1.504 + fCapitalizationContext = other.fCapitalizationContext; 1.505 + 1.506 + return *this; 1.507 +} 1.508 + 1.509 +//---------------------------------------------------------------------- 1.510 + 1.511 +Format* 1.512 +SimpleDateFormat::clone() const 1.513 +{ 1.514 + return new SimpleDateFormat(*this); 1.515 +} 1.516 + 1.517 +//---------------------------------------------------------------------- 1.518 + 1.519 +UBool 1.520 +SimpleDateFormat::operator==(const Format& other) const 1.521 +{ 1.522 + if (DateFormat::operator==(other)) { 1.523 + // DateFormat::operator== guarantees following cast is safe 1.524 + SimpleDateFormat* that = (SimpleDateFormat*)&other; 1.525 + return (fPattern == that->fPattern && 1.526 + fSymbols != NULL && // Check for pathological object 1.527 + that->fSymbols != NULL && // Check for pathological object 1.528 + *fSymbols == *that->fSymbols && 1.529 + fHaveDefaultCentury == that->fHaveDefaultCentury && 1.530 + fDefaultCenturyStart == that->fDefaultCenturyStart && 1.531 + fCapitalizationContext == that->fCapitalizationContext); 1.532 + } 1.533 + return FALSE; 1.534 +} 1.535 + 1.536 +//---------------------------------------------------------------------- 1.537 + 1.538 +void SimpleDateFormat::construct(EStyle timeStyle, 1.539 + EStyle dateStyle, 1.540 + const Locale& locale, 1.541 + UErrorCode& status) 1.542 +{ 1.543 + // called by several constructors to load pattern data from the resources 1.544 + if (U_FAILURE(status)) return; 1.545 + 1.546 + // We will need the calendar to know what type of symbols to load. 1.547 + initializeCalendar(NULL, locale, status); 1.548 + if (U_FAILURE(status)) return; 1.549 + 1.550 + CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status); 1.551 + UResourceBundle *dateTimePatterns = calData.getByKey(gDateTimePatternsTag, status); 1.552 + UResourceBundle *currentBundle; 1.553 + 1.554 + if (U_FAILURE(status)) return; 1.555 + 1.556 + if (ures_getSize(dateTimePatterns) <= kDateTime) 1.557 + { 1.558 + status = U_INVALID_FORMAT_ERROR; 1.559 + return; 1.560 + } 1.561 + 1.562 + setLocaleIDs(ures_getLocaleByType(dateTimePatterns, ULOC_VALID_LOCALE, &status), 1.563 + ures_getLocaleByType(dateTimePatterns, ULOC_ACTUAL_LOCALE, &status)); 1.564 + 1.565 + // create a symbols object from the locale 1.566 + initializeSymbols(locale,fCalendar, status); 1.567 + if (U_FAILURE(status)) return; 1.568 + /* test for NULL */ 1.569 + if (fSymbols == 0) { 1.570 + status = U_MEMORY_ALLOCATION_ERROR; 1.571 + return; 1.572 + } 1.573 + 1.574 + const UChar *resStr,*ovrStr; 1.575 + int32_t resStrLen,ovrStrLen = 0; 1.576 + fDateOverride.setToBogus(); 1.577 + fTimeOverride.setToBogus(); 1.578 + 1.579 + // if the pattern should include both date and time information, use the date/time 1.580 + // pattern string as a guide to tell use how to glue together the appropriate date 1.581 + // and time pattern strings. The actual gluing-together is handled by a convenience 1.582 + // method on MessageFormat. 1.583 + if ((timeStyle != kNone) && (dateStyle != kNone)) 1.584 + { 1.585 + Formattable timeDateArray[2]; 1.586 + 1.587 + // use Formattable::adoptString() so that we can use fastCopyFrom() 1.588 + // instead of Formattable::setString()'s unaware, safe, deep string clone 1.589 + // see Jitterbug 2296 1.590 + 1.591 + currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status); 1.592 + if (U_FAILURE(status)) { 1.593 + status = U_INVALID_FORMAT_ERROR; 1.594 + return; 1.595 + } 1.596 + switch (ures_getType(currentBundle)) { 1.597 + case URES_STRING: { 1.598 + resStr = ures_getString(currentBundle, &resStrLen, &status); 1.599 + break; 1.600 + } 1.601 + case URES_ARRAY: { 1.602 + resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status); 1.603 + ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status); 1.604 + fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen); 1.605 + break; 1.606 + } 1.607 + default: { 1.608 + status = U_INVALID_FORMAT_ERROR; 1.609 + ures_close(currentBundle); 1.610 + return; 1.611 + } 1.612 + } 1.613 + ures_close(currentBundle); 1.614 + 1.615 + UnicodeString *tempus1 = new UnicodeString(TRUE, resStr, resStrLen); 1.616 + // NULL pointer check 1.617 + if (tempus1 == NULL) { 1.618 + status = U_MEMORY_ALLOCATION_ERROR; 1.619 + return; 1.620 + } 1.621 + timeDateArray[0].adoptString(tempus1); 1.622 + 1.623 + currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status); 1.624 + if (U_FAILURE(status)) { 1.625 + status = U_INVALID_FORMAT_ERROR; 1.626 + return; 1.627 + } 1.628 + switch (ures_getType(currentBundle)) { 1.629 + case URES_STRING: { 1.630 + resStr = ures_getString(currentBundle, &resStrLen, &status); 1.631 + break; 1.632 + } 1.633 + case URES_ARRAY: { 1.634 + resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status); 1.635 + ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status); 1.636 + fDateOverride.setTo(TRUE, ovrStr, ovrStrLen); 1.637 + break; 1.638 + } 1.639 + default: { 1.640 + status = U_INVALID_FORMAT_ERROR; 1.641 + ures_close(currentBundle); 1.642 + return; 1.643 + } 1.644 + } 1.645 + ures_close(currentBundle); 1.646 + 1.647 + UnicodeString *tempus2 = new UnicodeString(TRUE, resStr, resStrLen); 1.648 + // Null pointer check 1.649 + if (tempus2 == NULL) { 1.650 + status = U_MEMORY_ALLOCATION_ERROR; 1.651 + return; 1.652 + } 1.653 + timeDateArray[1].adoptString(tempus2); 1.654 + 1.655 + int32_t glueIndex = kDateTime; 1.656 + int32_t patternsSize = ures_getSize(dateTimePatterns); 1.657 + if (patternsSize >= (kDateTimeOffset + kShort + 1)) { 1.658 + // Get proper date time format 1.659 + glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset)); 1.660 + } 1.661 + 1.662 + resStr = ures_getStringByIndex(dateTimePatterns, glueIndex, &resStrLen, &status); 1.663 + MessageFormat::format(UnicodeString(TRUE, resStr, resStrLen), timeDateArray, 2, fPattern, status); 1.664 + } 1.665 + // if the pattern includes just time data or just date date, load the appropriate 1.666 + // pattern string from the resources 1.667 + // setTo() - see DateFormatSymbols::assignArray comments 1.668 + else if (timeStyle != kNone) { 1.669 + currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status); 1.670 + if (U_FAILURE(status)) { 1.671 + status = U_INVALID_FORMAT_ERROR; 1.672 + return; 1.673 + } 1.674 + switch (ures_getType(currentBundle)) { 1.675 + case URES_STRING: { 1.676 + resStr = ures_getString(currentBundle, &resStrLen, &status); 1.677 + break; 1.678 + } 1.679 + case URES_ARRAY: { 1.680 + resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status); 1.681 + ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status); 1.682 + fDateOverride.setTo(TRUE, ovrStr, ovrStrLen); 1.683 + break; 1.684 + } 1.685 + default: { 1.686 + status = U_INVALID_FORMAT_ERROR; 1.687 + ures_close(currentBundle); 1.688 + return; 1.689 + } 1.690 + } 1.691 + fPattern.setTo(TRUE, resStr, resStrLen); 1.692 + ures_close(currentBundle); 1.693 + } 1.694 + else if (dateStyle != kNone) { 1.695 + currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status); 1.696 + if (U_FAILURE(status)) { 1.697 + status = U_INVALID_FORMAT_ERROR; 1.698 + return; 1.699 + } 1.700 + switch (ures_getType(currentBundle)) { 1.701 + case URES_STRING: { 1.702 + resStr = ures_getString(currentBundle, &resStrLen, &status); 1.703 + break; 1.704 + } 1.705 + case URES_ARRAY: { 1.706 + resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status); 1.707 + ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status); 1.708 + fDateOverride.setTo(TRUE, ovrStr, ovrStrLen); 1.709 + break; 1.710 + } 1.711 + default: { 1.712 + status = U_INVALID_FORMAT_ERROR; 1.713 + ures_close(currentBundle); 1.714 + return; 1.715 + } 1.716 + } 1.717 + fPattern.setTo(TRUE, resStr, resStrLen); 1.718 + ures_close(currentBundle); 1.719 + } 1.720 + 1.721 + // and if it includes _neither_, that's an error 1.722 + else 1.723 + status = U_INVALID_FORMAT_ERROR; 1.724 + 1.725 + // finally, finish initializing by creating a Calendar and a NumberFormat 1.726 + initialize(locale, status); 1.727 +} 1.728 + 1.729 +//---------------------------------------------------------------------- 1.730 + 1.731 +Calendar* 1.732 +SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status) 1.733 +{ 1.734 + if(!U_FAILURE(status)) { 1.735 + fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status); 1.736 + } 1.737 + if (U_SUCCESS(status) && fCalendar == NULL) { 1.738 + status = U_MEMORY_ALLOCATION_ERROR; 1.739 + } 1.740 + return fCalendar; 1.741 +} 1.742 + 1.743 +void 1.744 +SimpleDateFormat::initializeSymbols(const Locale& locale, Calendar* calendar, UErrorCode& status) 1.745 +{ 1.746 + if(U_FAILURE(status)) { 1.747 + fSymbols = NULL; 1.748 + } else { 1.749 + // pass in calendar type - use NULL (default) if no calendar set (or err). 1.750 + fSymbols = new DateFormatSymbols(locale, calendar?calendar->getType() :NULL , status); 1.751 + // Null pointer check 1.752 + if (fSymbols == NULL) { 1.753 + status = U_MEMORY_ALLOCATION_ERROR; 1.754 + return; 1.755 + } 1.756 + } 1.757 +} 1.758 + 1.759 +void 1.760 +SimpleDateFormat::initialize(const Locale& locale, 1.761 + UErrorCode& status) 1.762 +{ 1.763 + if (U_FAILURE(status)) return; 1.764 + 1.765 + // We don't need to check that the row count is >= 1, since all 2d arrays have at 1.766 + // least one row 1.767 + fNumberFormat = NumberFormat::createInstance(locale, status); 1.768 + if (fNumberFormat != NULL && U_SUCCESS(status)) 1.769 + { 1.770 + // no matter what the locale's default number format looked like, we want 1.771 + // to modify it so that it doesn't use thousands separators, doesn't always 1.772 + // show the decimal point, and recognizes integers only when parsing 1.773 + 1.774 + fNumberFormat->setGroupingUsed(FALSE); 1.775 + DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat); 1.776 + if (decfmt != NULL) { 1.777 + decfmt->setDecimalSeparatorAlwaysShown(FALSE); 1.778 + } 1.779 + fNumberFormat->setParseIntegerOnly(TRUE); 1.780 + fNumberFormat->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00" 1.781 + 1.782 + //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse 1.783 + 1.784 + initNumberFormatters(locale,status); 1.785 + 1.786 + } 1.787 + else if (U_SUCCESS(status)) 1.788 + { 1.789 + status = U_MISSING_RESOURCE_ERROR; 1.790 + } 1.791 +} 1.792 + 1.793 +/* Initialize the fields we use to disambiguate ambiguous years. Separate 1.794 + * so we can call it from readObject(). 1.795 + */ 1.796 +void SimpleDateFormat::initializeDefaultCentury() 1.797 +{ 1.798 + if(fCalendar) { 1.799 + fHaveDefaultCentury = fCalendar->haveDefaultCentury(); 1.800 + if(fHaveDefaultCentury) { 1.801 + fDefaultCenturyStart = fCalendar->defaultCenturyStart(); 1.802 + fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear(); 1.803 + } else { 1.804 + fDefaultCenturyStart = DBL_MIN; 1.805 + fDefaultCenturyStartYear = -1; 1.806 + } 1.807 + } 1.808 +} 1.809 + 1.810 +/* Define one-century window into which to disambiguate dates using 1.811 + * two-digit years. Make public in JDK 1.2. 1.812 + */ 1.813 +void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status) 1.814 +{ 1.815 + if(U_FAILURE(status)) { 1.816 + return; 1.817 + } 1.818 + if(!fCalendar) { 1.819 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.820 + return; 1.821 + } 1.822 + 1.823 + fCalendar->setTime(startDate, status); 1.824 + if(U_SUCCESS(status)) { 1.825 + fHaveDefaultCentury = TRUE; 1.826 + fDefaultCenturyStart = startDate; 1.827 + fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status); 1.828 + } 1.829 +} 1.830 + 1.831 +//---------------------------------------------------------------------- 1.832 + 1.833 +UnicodeString& 1.834 +SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const 1.835 +{ 1.836 + UErrorCode status = U_ZERO_ERROR; 1.837 + FieldPositionOnlyHandler handler(pos); 1.838 + return _format(cal, appendTo, handler, status); 1.839 +} 1.840 + 1.841 +//---------------------------------------------------------------------- 1.842 + 1.843 +UnicodeString& 1.844 +SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, 1.845 + FieldPositionIterator* posIter, UErrorCode& status) const 1.846 +{ 1.847 + FieldPositionIteratorHandler handler(posIter, status); 1.848 + return _format(cal, appendTo, handler, status); 1.849 +} 1.850 + 1.851 +//---------------------------------------------------------------------- 1.852 + 1.853 +UnicodeString& 1.854 +SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, 1.855 + FieldPositionHandler& handler, UErrorCode& status) const 1.856 +{ 1.857 + if ( U_FAILURE(status) ) { 1.858 + return appendTo; 1.859 + } 1.860 + Calendar* workCal = &cal; 1.861 + Calendar* calClone = NULL; 1.862 + if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) { 1.863 + // Different calendar type 1.864 + // We use the time and time zone from the input calendar, but 1.865 + // do not use the input calendar for field calculation. 1.866 + calClone = fCalendar->clone(); 1.867 + if (calClone != NULL) { 1.868 + UDate t = cal.getTime(status); 1.869 + calClone->setTime(t, status); 1.870 + calClone->setTimeZone(cal.getTimeZone()); 1.871 + workCal = calClone; 1.872 + } else { 1.873 + status = U_MEMORY_ALLOCATION_ERROR; 1.874 + return appendTo; 1.875 + } 1.876 + } 1.877 + 1.878 + UBool inQuote = FALSE; 1.879 + UChar prevCh = 0; 1.880 + int32_t count = 0; 1.881 + int32_t fieldNum = 0; 1.882 + 1.883 + // loop through the pattern string character by character 1.884 + for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) { 1.885 + UChar ch = fPattern[i]; 1.886 + 1.887 + // Use subFormat() to format a repeated pattern character 1.888 + // when a different pattern or non-pattern character is seen 1.889 + if (ch != prevCh && count > 0) { 1.890 + subFormat(appendTo, prevCh, count, fCapitalizationContext, fieldNum++, handler, *workCal, status); 1.891 + count = 0; 1.892 + } 1.893 + if (ch == QUOTE) { 1.894 + // Consecutive single quotes are a single quote literal, 1.895 + // either outside of quotes or between quotes 1.896 + if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) { 1.897 + appendTo += (UChar)QUOTE; 1.898 + ++i; 1.899 + } else { 1.900 + inQuote = ! inQuote; 1.901 + } 1.902 + } 1.903 + else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/) 1.904 + || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) { 1.905 + // ch is a date-time pattern character to be interpreted 1.906 + // by subFormat(); count the number of times it is repeated 1.907 + prevCh = ch; 1.908 + ++count; 1.909 + } 1.910 + else { 1.911 + // Append quoted characters and unquoted non-pattern characters 1.912 + appendTo += ch; 1.913 + } 1.914 + } 1.915 + 1.916 + // Format the last item in the pattern, if any 1.917 + if (count > 0) { 1.918 + subFormat(appendTo, prevCh, count, fCapitalizationContext, fieldNum++, handler, *workCal, status); 1.919 + } 1.920 + 1.921 + if (calClone != NULL) { 1.922 + delete calClone; 1.923 + } 1.924 + 1.925 + return appendTo; 1.926 +} 1.927 + 1.928 +//---------------------------------------------------------------------- 1.929 + 1.930 +/* Map calendar field into calendar field level. 1.931 + * the larger the level, the smaller the field unit. 1.932 + * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10, 1.933 + * UCAL_MONTH level is 20. 1.934 + * NOTE: if new fields adds in, the table needs to update. 1.935 + */ 1.936 +const int32_t 1.937 +SimpleDateFormat::fgCalendarFieldToLevel[] = 1.938 +{ 1.939 + /*GyM*/ 0, 10, 20, 1.940 + /*wW*/ 20, 30, 1.941 + /*dDEF*/ 30, 20, 30, 30, 1.942 + /*ahHm*/ 40, 50, 50, 60, 1.943 + /*sS..*/ 70, 80, 1.944 + /*z?Y*/ 0, 0, 10, 1.945 + /*eug*/ 30, 10, 0, 1.946 + /*A*/ 40 1.947 +}; 1.948 + 1.949 + 1.950 +/* Map calendar field LETTER into calendar field level. 1.951 + * the larger the level, the smaller the field unit. 1.952 + * NOTE: if new fields adds in, the table needs to update. 1.953 + */ 1.954 +const int32_t 1.955 +SimpleDateFormat::fgPatternCharToLevel[] = { 1.956 + // A B C D E F G H I J K L M N O 1.957 + -1, 40, -1, -1, 20, 30, 30, 0, 50, -1, -1, 50, 20, 20, -1, 0, 1.958 + // P Q R S T U V W X Y Z 1.959 + -1, 20, -1, 80, -1, 10, 0, 30, 0, 10, 0, -1, -1, -1, -1, -1, 1.960 + // a b c d e f g h i j k l m n o 1.961 + -1, 40, -1, 30, 30, 30, -1, 0, 50, -1, -1, 50, -1, 60, -1, -1, 1.962 + // p q r s t u v w x y z 1.963 + -1, 20, -1, 70, -1, 10, 0, 20, 0, 10, 0, -1, -1, -1, -1, -1 1.964 +}; 1.965 + 1.966 + 1.967 +// Map index into pattern character string to Calendar field number. 1.968 +const UCalendarDateFields 1.969 +SimpleDateFormat::fgPatternIndexToCalendarField[] = 1.970 +{ 1.971 + /*GyM*/ UCAL_ERA, UCAL_YEAR, UCAL_MONTH, 1.972 + /*dkH*/ UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY, 1.973 + /*msS*/ UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND, 1.974 + /*EDF*/ UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH, 1.975 + /*wWa*/ UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM, 1.976 + /*hKz*/ UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET, 1.977 + /*Yeu*/ UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR, 1.978 + /*gAZ*/ UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET, 1.979 + /*v*/ UCAL_ZONE_OFFSET, 1.980 + /*c*/ UCAL_DOW_LOCAL, 1.981 + /*L*/ UCAL_MONTH, 1.982 + /*Q*/ UCAL_MONTH, 1.983 + /*q*/ UCAL_MONTH, 1.984 + /*V*/ UCAL_ZONE_OFFSET, 1.985 + /*U*/ UCAL_YEAR, 1.986 + /*O*/ UCAL_ZONE_OFFSET, 1.987 + /*Xx*/ UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET, 1.988 +}; 1.989 + 1.990 +// Map index into pattern character string to DateFormat field number 1.991 +const UDateFormatField 1.992 +SimpleDateFormat::fgPatternIndexToDateFormatField[] = { 1.993 + /*GyM*/ UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD, 1.994 + /*dkH*/ UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD, 1.995 + /*msS*/ UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD, 1.996 + /*EDF*/ UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD, 1.997 + /*wWa*/ UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD, 1.998 + /*hKz*/ UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD, 1.999 + /*Yeu*/ UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD, 1.1000 + /*gAZ*/ UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD, 1.1001 + /*v*/ UDAT_TIMEZONE_GENERIC_FIELD, 1.1002 + /*c*/ UDAT_STANDALONE_DAY_FIELD, 1.1003 + /*L*/ UDAT_STANDALONE_MONTH_FIELD, 1.1004 + /*Q*/ UDAT_QUARTER_FIELD, 1.1005 + /*q*/ UDAT_STANDALONE_QUARTER_FIELD, 1.1006 + /*V*/ UDAT_TIMEZONE_SPECIAL_FIELD, 1.1007 + /*U*/ UDAT_YEAR_NAME_FIELD, 1.1008 + /*O*/ UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD, 1.1009 + /*Xx*/ UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD, 1.1010 +}; 1.1011 + 1.1012 +//---------------------------------------------------------------------- 1.1013 + 1.1014 +/** 1.1015 + * Append symbols[value] to dst. Make sure the array index is not out 1.1016 + * of bounds. 1.1017 + */ 1.1018 +static inline void 1.1019 +_appendSymbol(UnicodeString& dst, 1.1020 + int32_t value, 1.1021 + const UnicodeString* symbols, 1.1022 + int32_t symbolsCount) { 1.1023 + U_ASSERT(0 <= value && value < symbolsCount); 1.1024 + if (0 <= value && value < symbolsCount) { 1.1025 + dst += symbols[value]; 1.1026 + } 1.1027 +} 1.1028 + 1.1029 +static inline void 1.1030 +_appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount, 1.1031 + const UnicodeString* monthPattern, UErrorCode& status) { 1.1032 + U_ASSERT(0 <= value && value < symbolsCount); 1.1033 + if (0 <= value && value < symbolsCount) { 1.1034 + if (monthPattern == NULL) { 1.1035 + dst += symbols[value]; 1.1036 + } else { 1.1037 + Formattable monthName((const UnicodeString&)(symbols[value])); 1.1038 + MessageFormat::format(*monthPattern, &monthName, 1, dst, status); 1.1039 + } 1.1040 + } 1.1041 +} 1.1042 + 1.1043 +//---------------------------------------------------------------------- 1.1044 +void 1.1045 +SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) { 1.1046 + if (U_FAILURE(status)) { 1.1047 + return; 1.1048 + } 1.1049 + if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) { 1.1050 + return; 1.1051 + } 1.1052 + umtx_lock(&LOCK); 1.1053 + if (fNumberFormatters == NULL) { 1.1054 + fNumberFormatters = (NumberFormat**)uprv_malloc(UDAT_FIELD_COUNT * sizeof(NumberFormat*)); 1.1055 + if (fNumberFormatters) { 1.1056 + for (int32_t i = 0; i < UDAT_FIELD_COUNT; i++) { 1.1057 + fNumberFormatters[i] = fNumberFormat; 1.1058 + } 1.1059 + } else { 1.1060 + status = U_MEMORY_ALLOCATION_ERROR; 1.1061 + } 1.1062 + } 1.1063 + umtx_unlock(&LOCK); 1.1064 + 1.1065 + processOverrideString(locale,fDateOverride,kOvrStrDate,status); 1.1066 + processOverrideString(locale,fTimeOverride,kOvrStrTime,status); 1.1067 + 1.1068 +} 1.1069 + 1.1070 +void 1.1071 +SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) { 1.1072 + if (str.isBogus()) { 1.1073 + return; 1.1074 + } 1.1075 + int32_t start = 0; 1.1076 + int32_t len; 1.1077 + UnicodeString nsName; 1.1078 + UnicodeString ovrField; 1.1079 + UBool moreToProcess = TRUE; 1.1080 + 1.1081 + while (moreToProcess) { 1.1082 + int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start); 1.1083 + if (delimiterPosition == -1) { 1.1084 + moreToProcess = FALSE; 1.1085 + len = str.length() - start; 1.1086 + } else { 1.1087 + len = delimiterPosition - start; 1.1088 + } 1.1089 + UnicodeString currentString(str,start,len); 1.1090 + int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0); 1.1091 + if (equalSignPosition == -1) { // Simple override string such as "hebrew" 1.1092 + nsName.setTo(currentString); 1.1093 + ovrField.setToBogus(); 1.1094 + } else { // Field specific override string such as "y=hebrew" 1.1095 + nsName.setTo(currentString,equalSignPosition+1); 1.1096 + ovrField.setTo(currentString,0,1); // We just need the first character. 1.1097 + } 1.1098 + 1.1099 + int32_t nsNameHash = nsName.hashCode(); 1.1100 + // See if the numbering system is in the override list, if not, then add it. 1.1101 + NSOverride *cur = fOverrideList; 1.1102 + NumberFormat *nf = NULL; 1.1103 + UBool found = FALSE; 1.1104 + while ( cur && !found ) { 1.1105 + if ( cur->hash == nsNameHash ) { 1.1106 + nf = cur->nf; 1.1107 + found = TRUE; 1.1108 + } 1.1109 + cur = cur->next; 1.1110 + } 1.1111 + 1.1112 + if (!found) { 1.1113 + cur = (NSOverride *)uprv_malloc(sizeof(NSOverride)); 1.1114 + if (cur) { 1.1115 + char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY]; 1.1116 + uprv_strcpy(kw,"numbers="); 1.1117 + nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV); 1.1118 + 1.1119 + Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw); 1.1120 + nf = NumberFormat::createInstance(ovrLoc,status); 1.1121 + 1.1122 + // no matter what the locale's default number format looked like, we want 1.1123 + // to modify it so that it doesn't use thousands separators, doesn't always 1.1124 + // show the decimal point, and recognizes integers only when parsing 1.1125 + 1.1126 + if (U_SUCCESS(status)) { 1.1127 + nf->setGroupingUsed(FALSE); 1.1128 + DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(nf); 1.1129 + if (decfmt != NULL) { 1.1130 + decfmt->setDecimalSeparatorAlwaysShown(FALSE); 1.1131 + } 1.1132 + nf->setParseIntegerOnly(TRUE); 1.1133 + nf->setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00" 1.1134 + 1.1135 + cur->nf = nf; 1.1136 + cur->hash = nsNameHash; 1.1137 + cur->next = fOverrideList; 1.1138 + fOverrideList = cur; 1.1139 + } 1.1140 + else { 1.1141 + // clean up before returning 1.1142 + if (cur != NULL) { 1.1143 + uprv_free(cur); 1.1144 + } 1.1145 + return; 1.1146 + } 1.1147 + 1.1148 + } else { 1.1149 + status = U_MEMORY_ALLOCATION_ERROR; 1.1150 + return; 1.1151 + } 1.1152 + } 1.1153 + 1.1154 + // Now that we have an appropriate number formatter, fill in the appropriate spaces in the 1.1155 + // number formatters table. 1.1156 + 1.1157 + if (ovrField.isBogus()) { 1.1158 + switch (type) { 1.1159 + case kOvrStrDate: 1.1160 + case kOvrStrBoth: { 1.1161 + for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) { 1.1162 + fNumberFormatters[kDateFields[i]] = nf; 1.1163 + } 1.1164 + if (type==kOvrStrDate) { 1.1165 + break; 1.1166 + } 1.1167 + } 1.1168 + case kOvrStrTime : { 1.1169 + for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) { 1.1170 + fNumberFormatters[kTimeFields[i]] = nf; 1.1171 + } 1.1172 + break; 1.1173 + } 1.1174 + } 1.1175 + } else { 1.1176 + // if the pattern character is unrecognized, signal an error and bail out 1.1177 + UDateFormatField patternCharIndex = 1.1178 + DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0)); 1.1179 + if (patternCharIndex == UDAT_FIELD_COUNT) { 1.1180 + status = U_INVALID_FORMAT_ERROR; 1.1181 + return; 1.1182 + } 1.1183 + 1.1184 + // Set the number formatter in the table 1.1185 + fNumberFormatters[patternCharIndex] = nf; 1.1186 + } 1.1187 + 1.1188 + start = delimiterPosition + 1; 1.1189 + } 1.1190 +} 1.1191 + 1.1192 +//--------------------------------------------------------------------- 1.1193 +void 1.1194 +SimpleDateFormat::subFormat(UnicodeString &appendTo, 1.1195 + UChar ch, 1.1196 + int32_t count, 1.1197 + UDisplayContext capitalizationContext, 1.1198 + int32_t fieldNum, 1.1199 + FieldPositionHandler& handler, 1.1200 + Calendar& cal, 1.1201 + UErrorCode& status) const 1.1202 +{ 1.1203 + if (U_FAILURE(status)) { 1.1204 + return; 1.1205 + } 1.1206 + 1.1207 + // this function gets called by format() to produce the appropriate substitution 1.1208 + // text for an individual pattern symbol (e.g., "HH" or "yyyy") 1.1209 + 1.1210 + UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch); 1.1211 + const int32_t maxIntCount = 10; 1.1212 + int32_t beginOffset = appendTo.length(); 1.1213 + NumberFormat *currentNumberFormat; 1.1214 + DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther; 1.1215 + 1.1216 + UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0); 1.1217 + UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0); 1.1218 + 1.1219 + // if the pattern character is unrecognized, signal an error and dump out 1.1220 + if (patternCharIndex == UDAT_FIELD_COUNT) 1.1221 + { 1.1222 + if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored 1.1223 + status = U_INVALID_FORMAT_ERROR; 1.1224 + } 1.1225 + return; 1.1226 + } 1.1227 + 1.1228 + UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; 1.1229 + int32_t value = cal.get(field, status); 1.1230 + if (U_FAILURE(status)) { 1.1231 + return; 1.1232 + } 1.1233 + 1.1234 + currentNumberFormat = getNumberFormatByIndex(patternCharIndex); 1.1235 + UnicodeString hebr("hebr", 4, US_INV); 1.1236 + 1.1237 + switch (patternCharIndex) { 1.1238 + 1.1239 + // for any "G" symbol, write out the appropriate era string 1.1240 + // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name 1.1241 + case UDAT_ERA_FIELD: 1.1242 + if (isChineseCalendar) { 1.1243 + zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J 1.1244 + } else { 1.1245 + if (count == 5) { 1.1246 + _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount); 1.1247 + capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow; 1.1248 + } else if (count == 4) { 1.1249 + _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount); 1.1250 + capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide; 1.1251 + } else { 1.1252 + _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount); 1.1253 + capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev; 1.1254 + } 1.1255 + } 1.1256 + break; 1.1257 + 1.1258 + case UDAT_YEAR_NAME_FIELD: 1.1259 + if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) { 1.1260 + // the Calendar YEAR field runs 1 through 60 for cyclic years 1.1261 + _appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount); 1.1262 + break; 1.1263 + } 1.1264 + // else fall through to numeric year handling, do not break here 1.1265 + 1.1266 + // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits 1.1267 + // NEW: UTS#35: 1.1268 +//Year y yy yyy yyyy yyyyy 1.1269 +//AD 1 1 01 001 0001 00001 1.1270 +//AD 12 12 12 012 0012 00012 1.1271 +//AD 123 123 23 123 0123 00123 1.1272 +//AD 1234 1234 34 1234 1234 01234 1.1273 +//AD 12345 12345 45 12345 12345 12345 1.1274 + case UDAT_YEAR_FIELD: 1.1275 + case UDAT_YEAR_WOY_FIELD: 1.1276 + if (fDateOverride.compare(hebr)==0 && value>HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value<HEBREW_CAL_CUR_MILLENIUM_END_YEAR) { 1.1277 + value-=HEBREW_CAL_CUR_MILLENIUM_START_YEAR; 1.1278 + } 1.1279 + if(count == 2) 1.1280 + zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2); 1.1281 + else 1.1282 + zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount); 1.1283 + break; 1.1284 + 1.1285 + // for "MMMM"/"LLLL", write out the whole month name, for "MMM"/"LLL", write out the month 1.1286 + // abbreviation, for "M"/"L" or "MM"/"LL", write out the month as a number with the 1.1287 + // appropriate number of digits 1.1288 + // for "MMMMM"/"LLLLL", use the narrow form 1.1289 + case UDAT_MONTH_FIELD: 1.1290 + case UDAT_STANDALONE_MONTH_FIELD: 1.1291 + if ( isHebrewCalendar ) { 1.1292 + HebrewCalendar *hc = (HebrewCalendar*)&cal; 1.1293 + if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 ) 1.1294 + value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar. 1.1295 + if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 ) 1.1296 + value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7. 1.1297 + } 1.1298 + { 1.1299 + int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)? 1.1300 + cal.get(UCAL_IS_LEAP_MONTH, status): 0; 1.1301 + // should consolidate the next section by using arrays of pointers & counts for the right symbols... 1.1302 + if (count == 5) { 1.1303 + if (patternCharIndex == UDAT_MONTH_FIELD) { 1.1304 + _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount, 1.1305 + (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): NULL, status); 1.1306 + } else { 1.1307 + _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount, 1.1308 + (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): NULL, status); 1.1309 + } 1.1310 + capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow; 1.1311 + } else if (count == 4) { 1.1312 + if (patternCharIndex == UDAT_MONTH_FIELD) { 1.1313 + _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount, 1.1314 + (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): NULL, status); 1.1315 + capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat; 1.1316 + } else { 1.1317 + _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, 1.1318 + (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): NULL, status); 1.1319 + capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone; 1.1320 + } 1.1321 + } else if (count == 3) { 1.1322 + if (patternCharIndex == UDAT_MONTH_FIELD) { 1.1323 + _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, 1.1324 + (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): NULL, status); 1.1325 + capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat; 1.1326 + } else { 1.1327 + _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, 1.1328 + (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): NULL, status); 1.1329 + capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone; 1.1330 + } 1.1331 + } else { 1.1332 + UnicodeString monthNumber; 1.1333 + zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount); 1.1334 + _appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1, 1.1335 + (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): NULL, status); 1.1336 + } 1.1337 + } 1.1338 + break; 1.1339 + 1.1340 + // for "k" and "kk", write out the hour, adjusting midnight to appear as "24" 1.1341 + case UDAT_HOUR_OF_DAY1_FIELD: 1.1342 + if (value == 0) 1.1343 + zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount); 1.1344 + else 1.1345 + zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); 1.1346 + break; 1.1347 + 1.1348 + case UDAT_FRACTIONAL_SECOND_FIELD: 1.1349 + // Fractional seconds left-justify 1.1350 + { 1.1351 + currentNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count); 1.1352 + currentNumberFormat->setMaximumIntegerDigits(maxIntCount); 1.1353 + if (count == 1) { 1.1354 + value /= 100; 1.1355 + } else if (count == 2) { 1.1356 + value /= 10; 1.1357 + } 1.1358 + FieldPosition p(0); 1.1359 + currentNumberFormat->format(value, appendTo, p); 1.1360 + if (count > 3) { 1.1361 + currentNumberFormat->setMinimumIntegerDigits(count - 3); 1.1362 + currentNumberFormat->format((int32_t)0, appendTo, p); 1.1363 + } 1.1364 + } 1.1365 + break; 1.1366 + 1.1367 + // for "ee" or "e", use local numeric day-of-the-week 1.1368 + // for "EEEEEE" or "eeeeee", write out the short day-of-the-week name 1.1369 + // for "EEEEE" or "eeeee", write out the narrow day-of-the-week name 1.1370 + // for "EEEE" or "eeee", write out the wide day-of-the-week name 1.1371 + // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name 1.1372 + case UDAT_DOW_LOCAL_FIELD: 1.1373 + if ( count < 3 ) { 1.1374 + zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); 1.1375 + break; 1.1376 + } 1.1377 + // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week, 1.1378 + // we want standard day-of-week, so first fix value to work for EEEEE-EEE. 1.1379 + value = cal.get(UCAL_DAY_OF_WEEK, status); 1.1380 + if (U_FAILURE(status)) { 1.1381 + return; 1.1382 + } 1.1383 + // fall through, do not break here 1.1384 + case UDAT_DAY_OF_WEEK_FIELD: 1.1385 + if (count == 5) { 1.1386 + _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays, 1.1387 + fSymbols->fNarrowWeekdaysCount); 1.1388 + capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow; 1.1389 + } else if (count == 4) { 1.1390 + _appendSymbol(appendTo, value, fSymbols->fWeekdays, 1.1391 + fSymbols->fWeekdaysCount); 1.1392 + capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat; 1.1393 + } else if (count == 6) { 1.1394 + _appendSymbol(appendTo, value, fSymbols->fShorterWeekdays, 1.1395 + fSymbols->fShorterWeekdaysCount); 1.1396 + capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat; 1.1397 + } else { 1.1398 + _appendSymbol(appendTo, value, fSymbols->fShortWeekdays, 1.1399 + fSymbols->fShortWeekdaysCount); 1.1400 + capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat; 1.1401 + } 1.1402 + break; 1.1403 + 1.1404 + // for "ccc", write out the abbreviated day-of-the-week name 1.1405 + // for "cccc", write out the wide day-of-the-week name 1.1406 + // for "ccccc", use the narrow day-of-the-week name 1.1407 + // for "ccccc", use the short day-of-the-week name 1.1408 + case UDAT_STANDALONE_DAY_FIELD: 1.1409 + if ( count < 3 ) { 1.1410 + zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount); 1.1411 + break; 1.1412 + } 1.1413 + // fall through to alpha DOW handling, but for that we don't want local day-of-week, 1.1414 + // we want standard day-of-week, so first fix value. 1.1415 + value = cal.get(UCAL_DAY_OF_WEEK, status); 1.1416 + if (U_FAILURE(status)) { 1.1417 + return; 1.1418 + } 1.1419 + if (count == 5) { 1.1420 + _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays, 1.1421 + fSymbols->fStandaloneNarrowWeekdaysCount); 1.1422 + capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow; 1.1423 + } else if (count == 4) { 1.1424 + _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays, 1.1425 + fSymbols->fStandaloneWeekdaysCount); 1.1426 + capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone; 1.1427 + } else if (count == 6) { 1.1428 + _appendSymbol(appendTo, value, fSymbols->fStandaloneShorterWeekdays, 1.1429 + fSymbols->fStandaloneShorterWeekdaysCount); 1.1430 + capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone; 1.1431 + } else { // count == 3 1.1432 + _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays, 1.1433 + fSymbols->fStandaloneShortWeekdaysCount); 1.1434 + capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone; 1.1435 + } 1.1436 + break; 1.1437 + 1.1438 + // for and "a" symbol, write out the whole AM/PM string 1.1439 + case UDAT_AM_PM_FIELD: 1.1440 + _appendSymbol(appendTo, value, fSymbols->fAmPms, 1.1441 + fSymbols->fAmPmsCount); 1.1442 + break; 1.1443 + 1.1444 + // for "h" and "hh", write out the hour, adjusting noon and midnight to show up 1.1445 + // as "12" 1.1446 + case UDAT_HOUR1_FIELD: 1.1447 + if (value == 0) 1.1448 + zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount); 1.1449 + else 1.1450 + zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); 1.1451 + break; 1.1452 + 1.1453 + case UDAT_TIMEZONE_FIELD: // 'z' 1.1454 + case UDAT_TIMEZONE_RFC_FIELD: // 'Z' 1.1455 + case UDAT_TIMEZONE_GENERIC_FIELD: // 'v' 1.1456 + case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V' 1.1457 + case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O' 1.1458 + case UDAT_TIMEZONE_ISO_FIELD: // 'X' 1.1459 + case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x' 1.1460 + { 1.1461 + UnicodeString zoneString; 1.1462 + const TimeZone& tz = cal.getTimeZone(); 1.1463 + UDate date = cal.getTime(status); 1.1464 + if (U_SUCCESS(status)) { 1.1465 + if (patternCharIndex == UDAT_TIMEZONE_FIELD) { 1.1466 + if (count < 4) { 1.1467 + // "z", "zz", "zzz" 1.1468 + tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString); 1.1469 + capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort; 1.1470 + } else { 1.1471 + // "zzzz" or longer 1.1472 + tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString); 1.1473 + capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong; 1.1474 + } 1.1475 + } 1.1476 + else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) { 1.1477 + if (count < 4) { 1.1478 + // "Z" 1.1479 + tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString); 1.1480 + } else if (count == 5) { 1.1481 + // "ZZZZZ" 1.1482 + tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString); 1.1483 + } else { 1.1484 + // "ZZ", "ZZZ", "ZZZZ" 1.1485 + tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString); 1.1486 + } 1.1487 + } 1.1488 + else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) { 1.1489 + if (count == 1) { 1.1490 + // "v" 1.1491 + tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString); 1.1492 + capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort; 1.1493 + } else if (count == 4) { 1.1494 + // "vvvv" 1.1495 + tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString); 1.1496 + capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong; 1.1497 + } 1.1498 + } 1.1499 + else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) { 1.1500 + if (count == 1) { 1.1501 + // "V" 1.1502 + tzFormat()->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString); 1.1503 + } else if (count == 2) { 1.1504 + // "VV" 1.1505 + tzFormat()->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString); 1.1506 + } else if (count == 3) { 1.1507 + // "VVV" 1.1508 + tzFormat()->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString); 1.1509 + } else if (count == 4) { 1.1510 + // "VVVV" 1.1511 + tzFormat()->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString); 1.1512 + capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong; 1.1513 + } 1.1514 + } 1.1515 + else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) { 1.1516 + if (count == 1) { 1.1517 + // "O" 1.1518 + tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString); 1.1519 + } else if (count == 4) { 1.1520 + // "OOOO" 1.1521 + tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString); 1.1522 + } 1.1523 + } 1.1524 + else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) { 1.1525 + if (count == 1) { 1.1526 + // "X" 1.1527 + tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString); 1.1528 + } else if (count == 2) { 1.1529 + // "XX" 1.1530 + tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString); 1.1531 + } else if (count == 3) { 1.1532 + // "XXX" 1.1533 + tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString); 1.1534 + } else if (count == 4) { 1.1535 + // "XXXX" 1.1536 + tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString); 1.1537 + } else if (count == 5) { 1.1538 + // "XXXXX" 1.1539 + tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString); 1.1540 + } 1.1541 + } 1.1542 + else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) { 1.1543 + if (count == 1) { 1.1544 + // "x" 1.1545 + tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString); 1.1546 + } else if (count == 2) { 1.1547 + // "xx" 1.1548 + tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString); 1.1549 + } else if (count == 3) { 1.1550 + // "xxx" 1.1551 + tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString); 1.1552 + } else if (count == 4) { 1.1553 + // "xxxx" 1.1554 + tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString); 1.1555 + } else if (count == 5) { 1.1556 + // "xxxxx" 1.1557 + tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString); 1.1558 + } 1.1559 + } 1.1560 + else { 1.1561 + U_ASSERT(FALSE); 1.1562 + } 1.1563 + } 1.1564 + appendTo += zoneString; 1.1565 + } 1.1566 + break; 1.1567 + 1.1568 + case UDAT_QUARTER_FIELD: 1.1569 + if (count >= 4) 1.1570 + _appendSymbol(appendTo, value/3, fSymbols->fQuarters, 1.1571 + fSymbols->fQuartersCount); 1.1572 + else if (count == 3) 1.1573 + _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters, 1.1574 + fSymbols->fShortQuartersCount); 1.1575 + else 1.1576 + zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount); 1.1577 + break; 1.1578 + 1.1579 + case UDAT_STANDALONE_QUARTER_FIELD: 1.1580 + if (count >= 4) 1.1581 + _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters, 1.1582 + fSymbols->fStandaloneQuartersCount); 1.1583 + else if (count == 3) 1.1584 + _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters, 1.1585 + fSymbols->fStandaloneShortQuartersCount); 1.1586 + else 1.1587 + zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount); 1.1588 + break; 1.1589 + 1.1590 + 1.1591 + // all of the other pattern symbols can be formatted as simple numbers with 1.1592 + // appropriate zero padding 1.1593 + default: 1.1594 + zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); 1.1595 + break; 1.1596 + } 1.1597 +#if !UCONFIG_NO_BREAK_ITERATION 1.1598 + if (fieldNum == 0) { 1.1599 + // first field, check to see whether we need to titlecase it 1.1600 + UBool titlecase = FALSE; 1.1601 + switch (capitalizationContext) { 1.1602 + case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE: 1.1603 + titlecase = TRUE; 1.1604 + break; 1.1605 + case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU: 1.1606 + titlecase = fSymbols->fCapitalization[capContextUsageType][0]; 1.1607 + break; 1.1608 + case UDISPCTX_CAPITALIZATION_FOR_STANDALONE: 1.1609 + titlecase = fSymbols->fCapitalization[capContextUsageType][1]; 1.1610 + break; 1.1611 + default: 1.1612 + // titlecase = FALSE; 1.1613 + break; 1.1614 + } 1.1615 + if (titlecase) { 1.1616 + UnicodeString firstField(appendTo, beginOffset); 1.1617 + firstField.toTitle(NULL, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT); 1.1618 + appendTo.replaceBetween(beginOffset, appendTo.length(), firstField); 1.1619 + } 1.1620 + } 1.1621 +#endif 1.1622 + 1.1623 + handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length()); 1.1624 +} 1.1625 + 1.1626 +//---------------------------------------------------------------------- 1.1627 + 1.1628 +NumberFormat * 1.1629 +SimpleDateFormat::getNumberFormatByIndex(UDateFormatField index) const { 1.1630 + if (fNumberFormatters != NULL) { 1.1631 + return fNumberFormatters[index]; 1.1632 + } else { 1.1633 + return fNumberFormat; 1.1634 + } 1.1635 +} 1.1636 + 1.1637 +//---------------------------------------------------------------------- 1.1638 +void 1.1639 +SimpleDateFormat::zeroPaddingNumber(NumberFormat *currentNumberFormat,UnicodeString &appendTo, 1.1640 + int32_t value, int32_t minDigits, int32_t maxDigits) const 1.1641 +{ 1.1642 + if (currentNumberFormat!=NULL) { 1.1643 + FieldPosition pos(0); 1.1644 + 1.1645 + currentNumberFormat->setMinimumIntegerDigits(minDigits); 1.1646 + currentNumberFormat->setMaximumIntegerDigits(maxDigits); 1.1647 + currentNumberFormat->format(value, appendTo, pos); // 3rd arg is there to speed up processing 1.1648 + } 1.1649 +} 1.1650 + 1.1651 +//---------------------------------------------------------------------- 1.1652 + 1.1653 +/** 1.1654 + * Return true if the given format character, occuring count 1.1655 + * times, represents a numeric field. 1.1656 + */ 1.1657 +UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) { 1.1658 + return DateFormatSymbols::isNumericPatternChar(formatChar, count); 1.1659 +} 1.1660 + 1.1661 +UBool 1.1662 +SimpleDateFormat::isAtNumericField(const UnicodeString &pattern, int32_t patternOffset) { 1.1663 + if (patternOffset >= pattern.length()) { 1.1664 + // not at any field 1.1665 + return FALSE; 1.1666 + } 1.1667 + UChar ch = pattern.charAt(patternOffset); 1.1668 + UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch); 1.1669 + if (f == UDAT_FIELD_COUNT) { 1.1670 + // not at any field 1.1671 + return FALSE; 1.1672 + } 1.1673 + int32_t i = patternOffset; 1.1674 + while (pattern.charAt(++i) == ch) {} 1.1675 + return DateFormatSymbols::isNumericField(f, i - patternOffset); 1.1676 +} 1.1677 + 1.1678 +UBool 1.1679 +SimpleDateFormat::isAfterNonNumericField(const UnicodeString &pattern, int32_t patternOffset) { 1.1680 + if (patternOffset <= 0) { 1.1681 + // not after any field 1.1682 + return FALSE; 1.1683 + } 1.1684 + UChar ch = pattern.charAt(--patternOffset); 1.1685 + UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch); 1.1686 + if (f == UDAT_FIELD_COUNT) { 1.1687 + // not after any field 1.1688 + return FALSE; 1.1689 + } 1.1690 + int32_t i = patternOffset; 1.1691 + while (pattern.charAt(--i) == ch) {} 1.1692 + return !DateFormatSymbols::isNumericField(f, patternOffset - i); 1.1693 +} 1.1694 + 1.1695 +void 1.1696 +SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const 1.1697 +{ 1.1698 + UErrorCode status = U_ZERO_ERROR; 1.1699 + int32_t pos = parsePos.getIndex(); 1.1700 + int32_t start = pos; 1.1701 + 1.1702 + UBool ambiguousYear[] = { FALSE }; 1.1703 + int32_t saveHebrewMonth = -1; 1.1704 + int32_t count = 0; 1.1705 + 1.1706 + // hack, reset tztype, cast away const 1.1707 + ((SimpleDateFormat*)this)->tztype = UTZFMT_TIME_TYPE_UNKNOWN; 1.1708 + 1.1709 + // For parsing abutting numeric fields. 'abutPat' is the 1.1710 + // offset into 'pattern' of the first of 2 or more abutting 1.1711 + // numeric fields. 'abutStart' is the offset into 'text' 1.1712 + // where parsing the fields begins. 'abutPass' starts off as 0 1.1713 + // and increments each time we try to parse the fields. 1.1714 + int32_t abutPat = -1; // If >=0, we are in a run of abutting numeric fields 1.1715 + int32_t abutStart = 0; 1.1716 + int32_t abutPass = 0; 1.1717 + UBool inQuote = FALSE; 1.1718 + 1.1719 + MessageFormat * numericLeapMonthFormatter = NULL; 1.1720 + 1.1721 + Calendar* calClone = NULL; 1.1722 + Calendar *workCal = &cal; 1.1723 + if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) { 1.1724 + // Different calendar type 1.1725 + // We use the time/zone from the input calendar, but 1.1726 + // do not use the input calendar for field calculation. 1.1727 + calClone = fCalendar->clone(); 1.1728 + if (calClone != NULL) { 1.1729 + calClone->setTime(cal.getTime(status),status); 1.1730 + if (U_FAILURE(status)) { 1.1731 + goto ExitParse; 1.1732 + } 1.1733 + calClone->setTimeZone(cal.getTimeZone()); 1.1734 + workCal = calClone; 1.1735 + } else { 1.1736 + status = U_MEMORY_ALLOCATION_ERROR; 1.1737 + goto ExitParse; 1.1738 + } 1.1739 + } 1.1740 + 1.1741 + if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) { 1.1742 + numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status); 1.1743 + if (numericLeapMonthFormatter == NULL) { 1.1744 + status = U_MEMORY_ALLOCATION_ERROR; 1.1745 + goto ExitParse; 1.1746 + } else if (U_FAILURE(status)) { 1.1747 + goto ExitParse; // this will delete numericLeapMonthFormatter 1.1748 + } 1.1749 + } 1.1750 + 1.1751 + for (int32_t i=0; i<fPattern.length(); ++i) { 1.1752 + UChar ch = fPattern.charAt(i); 1.1753 + 1.1754 + // Handle alphabetic field characters. 1.1755 + if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // [A-Za-z] 1.1756 + int32_t fieldPat = i; 1.1757 + 1.1758 + // Count the length of this field specifier 1.1759 + count = 1; 1.1760 + while ((i+1)<fPattern.length() && 1.1761 + fPattern.charAt(i+1) == ch) { 1.1762 + ++count; 1.1763 + ++i; 1.1764 + } 1.1765 + 1.1766 + if (isNumeric(ch, count)) { 1.1767 + if (abutPat < 0) { 1.1768 + // Determine if there is an abutting numeric field. 1.1769 + // Record the start of a set of abutting numeric fields. 1.1770 + if (isAtNumericField(fPattern, i + 1)) { 1.1771 + abutPat = fieldPat; 1.1772 + abutStart = pos; 1.1773 + abutPass = 0; 1.1774 + } 1.1775 + } 1.1776 + } else { 1.1777 + abutPat = -1; // End of any abutting fields 1.1778 + } 1.1779 + 1.1780 + // Handle fields within a run of abutting numeric fields. Take 1.1781 + // the pattern "HHmmss" as an example. We will try to parse 1.1782 + // 2/2/2 characters of the input text, then if that fails, 1.1783 + // 1/2/2. We only adjust the width of the leftmost field; the 1.1784 + // others remain fixed. This allows "123456" => 12:34:56, but 1.1785 + // "12345" => 1:23:45. Likewise, for the pattern "yyyyMMdd" we 1.1786 + // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2. 1.1787 + if (abutPat >= 0) { 1.1788 + // If we are at the start of a run of abutting fields, then 1.1789 + // shorten this field in each pass. If we can't shorten 1.1790 + // this field any more, then the parse of this set of 1.1791 + // abutting numeric fields has failed. 1.1792 + if (fieldPat == abutPat) { 1.1793 + count -= abutPass++; 1.1794 + if (count == 0) { 1.1795 + status = U_PARSE_ERROR; 1.1796 + goto ExitParse; 1.1797 + } 1.1798 + } 1.1799 + 1.1800 + pos = subParse(text, pos, ch, count, 1.1801 + TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter); 1.1802 + 1.1803 + // If the parse fails anywhere in the run, back up to the 1.1804 + // start of the run and retry. 1.1805 + if (pos < 0) { 1.1806 + i = abutPat - 1; 1.1807 + pos = abutStart; 1.1808 + continue; 1.1809 + } 1.1810 + } 1.1811 + 1.1812 + // Handle non-numeric fields and non-abutting numeric 1.1813 + // fields. 1.1814 + else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored 1.1815 + int32_t s = subParse(text, pos, ch, count, 1.1816 + FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter); 1.1817 + 1.1818 + if (s == -pos-1) { 1.1819 + // era not present, in special cases allow this to continue 1.1820 + // from the position where the era was expected 1.1821 + s = pos; 1.1822 + 1.1823 + if (i+1 < fPattern.length()) { 1.1824 + // move to next pattern character 1.1825 + UChar ch = fPattern.charAt(i+1); 1.1826 + 1.1827 + // check for whitespace 1.1828 + if (PatternProps::isWhiteSpace(ch)) { 1.1829 + i++; 1.1830 + // Advance over run in pattern 1.1831 + while ((i+1)<fPattern.length() && 1.1832 + PatternProps::isWhiteSpace(fPattern.charAt(i+1))) { 1.1833 + ++i; 1.1834 + } 1.1835 + } 1.1836 + } 1.1837 + } 1.1838 + else if (s <= 0) { 1.1839 + status = U_PARSE_ERROR; 1.1840 + goto ExitParse; 1.1841 + } 1.1842 + pos = s; 1.1843 + } 1.1844 + } 1.1845 + 1.1846 + // Handle literal pattern characters. These are any 1.1847 + // quoted characters and non-alphabetic unquoted 1.1848 + // characters. 1.1849 + else { 1.1850 + 1.1851 + abutPat = -1; // End of any abutting fields 1.1852 + 1.1853 + if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status))) { 1.1854 + status = U_PARSE_ERROR; 1.1855 + goto ExitParse; 1.1856 + } 1.1857 + } 1.1858 + } 1.1859 + 1.1860 + // Special hack for trailing "." after non-numeric field. 1.1861 + if (text.charAt(pos) == 0x2e && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) { 1.1862 + // only do if the last field is not numeric 1.1863 + if (isAfterNonNumericField(fPattern, fPattern.length())) { 1.1864 + pos++; // skip the extra "." 1.1865 + } 1.1866 + } 1.1867 + 1.1868 + // At this point the fields of Calendar have been set. Calendar 1.1869 + // will fill in default values for missing fields when the time 1.1870 + // is computed. 1.1871 + 1.1872 + parsePos.setIndex(pos); 1.1873 + 1.1874 + // This part is a problem: When we call parsedDate.after, we compute the time. 1.1875 + // Take the date April 3 2004 at 2:30 am. When this is first set up, the year 1.1876 + // will be wrong if we're parsing a 2-digit year pattern. It will be 1904. 1.1877 + // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day. 2:30 am 1.1878 + // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am 1.1879 + // on that day. It is therefore parsed out to fields as 3:30 am. Then we 1.1880 + // add 100 years, and get April 3 2004 at 3:30 am. Note that April 3 2004 is 1.1881 + // a Saturday, so it can have a 2:30 am -- and it should. [LIU] 1.1882 + /* 1.1883 + UDate parsedDate = calendar.getTime(); 1.1884 + if( ambiguousYear[0] && !parsedDate.after(fDefaultCenturyStart) ) { 1.1885 + calendar.add(Calendar.YEAR, 100); 1.1886 + parsedDate = calendar.getTime(); 1.1887 + } 1.1888 + */ 1.1889 + // Because of the above condition, save off the fields in case we need to readjust. 1.1890 + // The procedure we use here is not particularly efficient, but there is no other 1.1891 + // way to do this given the API restrictions present in Calendar. We minimize 1.1892 + // inefficiency by only performing this computation when it might apply, that is, 1.1893 + // when the two-digit year is equal to the start year, and thus might fall at the 1.1894 + // front or the back of the default century. This only works because we adjust 1.1895 + // the year correctly to start with in other cases -- see subParse(). 1.1896 + if (ambiguousYear[0] || tztype != UTZFMT_TIME_TYPE_UNKNOWN) // If this is true then the two-digit year == the default start year 1.1897 + { 1.1898 + // We need a copy of the fields, and we need to avoid triggering a call to 1.1899 + // complete(), which will recalculate the fields. Since we can't access 1.1900 + // the fields[] array in Calendar, we clone the entire object. This will 1.1901 + // stop working if Calendar.clone() is ever rewritten to call complete(). 1.1902 + Calendar *copy; 1.1903 + if (ambiguousYear[0]) { 1.1904 + copy = cal.clone(); 1.1905 + // Check for failed cloning. 1.1906 + if (copy == NULL) { 1.1907 + status = U_MEMORY_ALLOCATION_ERROR; 1.1908 + goto ExitParse; 1.1909 + } 1.1910 + UDate parsedDate = copy->getTime(status); 1.1911 + // {sfb} check internalGetDefaultCenturyStart 1.1912 + if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) { 1.1913 + // We can't use add here because that does a complete() first. 1.1914 + cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100); 1.1915 + } 1.1916 + delete copy; 1.1917 + } 1.1918 + 1.1919 + if (tztype != UTZFMT_TIME_TYPE_UNKNOWN) { 1.1920 + copy = cal.clone(); 1.1921 + // Check for failed cloning. 1.1922 + if (copy == NULL) { 1.1923 + status = U_MEMORY_ALLOCATION_ERROR; 1.1924 + goto ExitParse; 1.1925 + } 1.1926 + const TimeZone & tz = cal.getTimeZone(); 1.1927 + BasicTimeZone *btz = NULL; 1.1928 + 1.1929 + if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL 1.1930 + || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL 1.1931 + || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL 1.1932 + || dynamic_cast<const VTimeZone *>(&tz) != NULL) { 1.1933 + btz = (BasicTimeZone*)&tz; 1.1934 + } 1.1935 + 1.1936 + // Get local millis 1.1937 + copy->set(UCAL_ZONE_OFFSET, 0); 1.1938 + copy->set(UCAL_DST_OFFSET, 0); 1.1939 + UDate localMillis = copy->getTime(status); 1.1940 + 1.1941 + // Make sure parsed time zone type (Standard or Daylight) 1.1942 + // matches the rule used by the parsed time zone. 1.1943 + int32_t raw, dst; 1.1944 + if (btz != NULL) { 1.1945 + if (tztype == UTZFMT_TIME_TYPE_STANDARD) { 1.1946 + btz->getOffsetFromLocal(localMillis, 1.1947 + BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status); 1.1948 + } else { 1.1949 + btz->getOffsetFromLocal(localMillis, 1.1950 + BasicTimeZone::kDaylight, BasicTimeZone::kDaylight, raw, dst, status); 1.1951 + } 1.1952 + } else { 1.1953 + // No good way to resolve ambiguous time at transition, 1.1954 + // but following code work in most case. 1.1955 + tz.getOffset(localMillis, TRUE, raw, dst, status); 1.1956 + } 1.1957 + 1.1958 + // Now, compare the results with parsed type, either standard or daylight saving time 1.1959 + int32_t resolvedSavings = dst; 1.1960 + if (tztype == UTZFMT_TIME_TYPE_STANDARD) { 1.1961 + if (dst != 0) { 1.1962 + // Override DST_OFFSET = 0 in the result calendar 1.1963 + resolvedSavings = 0; 1.1964 + } 1.1965 + } else { // tztype == TZTYPE_DST 1.1966 + if (dst == 0) { 1.1967 + if (btz != NULL) { 1.1968 + UDate time = localMillis + raw; 1.1969 + // We use the nearest daylight saving time rule. 1.1970 + TimeZoneTransition beforeTrs, afterTrs; 1.1971 + UDate beforeT = time, afterT = time; 1.1972 + int32_t beforeSav = 0, afterSav = 0; 1.1973 + UBool beforeTrsAvail, afterTrsAvail; 1.1974 + 1.1975 + // Search for DST rule before or on the time 1.1976 + while (TRUE) { 1.1977 + beforeTrsAvail = btz->getPreviousTransition(beforeT, TRUE, beforeTrs); 1.1978 + if (!beforeTrsAvail) { 1.1979 + break; 1.1980 + } 1.1981 + beforeT = beforeTrs.getTime() - 1; 1.1982 + beforeSav = beforeTrs.getFrom()->getDSTSavings(); 1.1983 + if (beforeSav != 0) { 1.1984 + break; 1.1985 + } 1.1986 + } 1.1987 + 1.1988 + // Search for DST rule after the time 1.1989 + while (TRUE) { 1.1990 + afterTrsAvail = btz->getNextTransition(afterT, FALSE, afterTrs); 1.1991 + if (!afterTrsAvail) { 1.1992 + break; 1.1993 + } 1.1994 + afterT = afterTrs.getTime(); 1.1995 + afterSav = afterTrs.getTo()->getDSTSavings(); 1.1996 + if (afterSav != 0) { 1.1997 + break; 1.1998 + } 1.1999 + } 1.2000 + 1.2001 + if (beforeTrsAvail && afterTrsAvail) { 1.2002 + if (time - beforeT > afterT - time) { 1.2003 + resolvedSavings = afterSav; 1.2004 + } else { 1.2005 + resolvedSavings = beforeSav; 1.2006 + } 1.2007 + } else if (beforeTrsAvail && beforeSav != 0) { 1.2008 + resolvedSavings = beforeSav; 1.2009 + } else if (afterTrsAvail && afterSav != 0) { 1.2010 + resolvedSavings = afterSav; 1.2011 + } else { 1.2012 + resolvedSavings = btz->getDSTSavings(); 1.2013 + } 1.2014 + } else { 1.2015 + resolvedSavings = tz.getDSTSavings(); 1.2016 + } 1.2017 + if (resolvedSavings == 0) { 1.2018 + // final fallback 1.2019 + resolvedSavings = U_MILLIS_PER_HOUR; 1.2020 + } 1.2021 + } 1.2022 + } 1.2023 + cal.set(UCAL_ZONE_OFFSET, raw); 1.2024 + cal.set(UCAL_DST_OFFSET, resolvedSavings); 1.2025 + delete copy; 1.2026 + } 1.2027 + } 1.2028 +ExitParse: 1.2029 + // Set the parsed result if local calendar is used 1.2030 + // instead of the input calendar 1.2031 + if (U_SUCCESS(status) && workCal != &cal) { 1.2032 + cal.setTimeZone(workCal->getTimeZone()); 1.2033 + cal.setTime(workCal->getTime(status), status); 1.2034 + } 1.2035 + 1.2036 + if (numericLeapMonthFormatter != NULL) { 1.2037 + delete numericLeapMonthFormatter; 1.2038 + } 1.2039 + if (calClone != NULL) { 1.2040 + delete calClone; 1.2041 + } 1.2042 + 1.2043 + // If any Calendar calls failed, we pretend that we 1.2044 + // couldn't parse the string, when in reality this isn't quite accurate-- 1.2045 + // we did parse it; the Calendar calls just failed. 1.2046 + if (U_FAILURE(status)) { 1.2047 + parsePos.setErrorIndex(pos); 1.2048 + parsePos.setIndex(start); 1.2049 + } 1.2050 +} 1.2051 + 1.2052 +//---------------------------------------------------------------------- 1.2053 + 1.2054 +static UBool 1.2055 +newBestMatchWithOptionalDot(const UnicodeString &lcaseText, 1.2056 + const UnicodeString &data, 1.2057 + UnicodeString &bestMatchName, 1.2058 + int32_t &bestMatchLength); 1.2059 + 1.2060 +int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text, 1.2061 + int32_t start, 1.2062 + UCalendarDateFields field, 1.2063 + const UnicodeString* data, 1.2064 + int32_t dataCount, 1.2065 + Calendar& cal) const 1.2066 +{ 1.2067 + int32_t i = 0; 1.2068 + int32_t count = dataCount; 1.2069 + 1.2070 + // There may be multiple strings in the data[] array which begin with 1.2071 + // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech). 1.2072 + // We keep track of the longest match, and return that. Note that this 1.2073 + // unfortunately requires us to test all array elements. 1.2074 + int32_t bestMatchLength = 0, bestMatch = -1; 1.2075 + UnicodeString bestMatchName; 1.2076 + 1.2077 + // {sfb} kludge to support case-insensitive comparison 1.2078 + // {markus 2002oct11} do not just use caseCompareBetween because we do not know 1.2079 + // the length of the match after case folding 1.2080 + // {alan 20040607} don't case change the whole string, since the length 1.2081 + // can change 1.2082 + // TODO we need a case-insensitive startsWith function 1.2083 + UnicodeString lcaseText; 1.2084 + text.extract(start, INT32_MAX, lcaseText); 1.2085 + lcaseText.foldCase(); 1.2086 + 1.2087 + for (; i < count; ++i) 1.2088 + { 1.2089 + // Always compare if we have no match yet; otherwise only compare 1.2090 + // against potentially better matches (longer strings). 1.2091 + 1.2092 + if (newBestMatchWithOptionalDot(lcaseText, data[i], bestMatchName, bestMatchLength)) { 1.2093 + bestMatch = i; 1.2094 + } 1.2095 + } 1.2096 + if (bestMatch >= 0) 1.2097 + { 1.2098 + cal.set(field, bestMatch * 3); 1.2099 + 1.2100 + // Once we have a match, we have to determine the length of the 1.2101 + // original source string. This will usually be == the length of 1.2102 + // the case folded string, but it may differ (e.g. sharp s). 1.2103 + 1.2104 + // Most of the time, the length will be the same as the length 1.2105 + // of the string from the locale data. Sometimes it will be 1.2106 + // different, in which case we will have to figure it out by 1.2107 + // adding a character at a time, until we have a match. We do 1.2108 + // this all in one loop, where we try 'len' first (at index 1.2109 + // i==0). 1.2110 + int32_t len = bestMatchName.length(); // 99+% of the time 1.2111 + int32_t n = text.length() - start; 1.2112 + for (i=0; i<=n; ++i) { 1.2113 + int32_t j=i; 1.2114 + if (i == 0) { 1.2115 + j = len; 1.2116 + } else if (i == len) { 1.2117 + continue; // already tried this when i was 0 1.2118 + } 1.2119 + text.extract(start, j, lcaseText); 1.2120 + lcaseText.foldCase(); 1.2121 + if (bestMatchName == lcaseText) { 1.2122 + return start + j; 1.2123 + } 1.2124 + } 1.2125 + } 1.2126 + 1.2127 + return -start; 1.2128 +} 1.2129 + 1.2130 +//---------------------------------------------------------------------- 1.2131 +UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern, 1.2132 + int32_t &patternOffset, 1.2133 + const UnicodeString &text, 1.2134 + int32_t &textOffset, 1.2135 + UBool lenient) 1.2136 +{ 1.2137 + UBool inQuote = FALSE; 1.2138 + UnicodeString literal; 1.2139 + int32_t i = patternOffset; 1.2140 + 1.2141 + // scan pattern looking for contiguous literal characters 1.2142 + for ( ; i < pattern.length(); i += 1) { 1.2143 + UChar ch = pattern.charAt(i); 1.2144 + 1.2145 + if (!inQuote && ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A))) { // unquoted [A-Za-z] 1.2146 + break; 1.2147 + } 1.2148 + 1.2149 + if (ch == QUOTE) { 1.2150 + // Match a quote literal ('') inside OR outside of quotes 1.2151 + if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) { 1.2152 + i += 1; 1.2153 + } else { 1.2154 + inQuote = !inQuote; 1.2155 + continue; 1.2156 + } 1.2157 + } 1.2158 + 1.2159 + literal += ch; 1.2160 + } 1.2161 + 1.2162 + // at this point, literal contains the literal text 1.2163 + // and i is the index of the next non-literal pattern character. 1.2164 + int32_t p; 1.2165 + int32_t t = textOffset; 1.2166 + 1.2167 + if (lenient) { 1.2168 + // trim leading, trailing whitespace from 1.2169 + // the literal text 1.2170 + literal.trim(); 1.2171 + 1.2172 + // ignore any leading whitespace in the text 1.2173 + while (t < text.length() && u_isWhitespace(text.charAt(t))) { 1.2174 + t += 1; 1.2175 + } 1.2176 + } 1.2177 + 1.2178 + for (p = 0; p < literal.length() && t < text.length();) { 1.2179 + UBool needWhitespace = FALSE; 1.2180 + 1.2181 + while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) { 1.2182 + needWhitespace = TRUE; 1.2183 + p += 1; 1.2184 + } 1.2185 + 1.2186 + if (needWhitespace) { 1.2187 + int32_t tStart = t; 1.2188 + 1.2189 + while (t < text.length()) { 1.2190 + UChar tch = text.charAt(t); 1.2191 + 1.2192 + if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) { 1.2193 + break; 1.2194 + } 1.2195 + 1.2196 + t += 1; 1.2197 + } 1.2198 + 1.2199 + // TODO: should we require internal spaces 1.2200 + // in lenient mode? (There won't be any 1.2201 + // leading or trailing spaces) 1.2202 + if (!lenient && t == tStart) { 1.2203 + // didn't find matching whitespace: 1.2204 + // an error in strict mode 1.2205 + return FALSE; 1.2206 + } 1.2207 + 1.2208 + // In strict mode, this run of whitespace 1.2209 + // may have been at the end. 1.2210 + if (p >= literal.length()) { 1.2211 + break; 1.2212 + } 1.2213 + } 1.2214 + 1.2215 + if (t >= text.length() || literal.charAt(p) != text.charAt(t)) { 1.2216 + // Ran out of text, or found a non-matching character: 1.2217 + // OK in lenient mode, an error in strict mode. 1.2218 + if (lenient) { 1.2219 + if (t == textOffset && text.charAt(t) == 0x2e && 1.2220 + isAfterNonNumericField(pattern, patternOffset)) { 1.2221 + // Lenient mode and the literal input text begins with a "." and 1.2222 + // we are after a non-numeric field: We skip the "." 1.2223 + ++t; 1.2224 + continue; // Do not update p. 1.2225 + } 1.2226 + break; 1.2227 + } 1.2228 + 1.2229 + return FALSE; 1.2230 + } 1.2231 + ++p; 1.2232 + ++t; 1.2233 + } 1.2234 + 1.2235 + // At this point if we're in strict mode we have a complete match. 1.2236 + // If we're in lenient mode we may have a partial match, or no 1.2237 + // match at all. 1.2238 + if (p <= 0) { 1.2239 + // no match. Pretend it matched a run of whitespace 1.2240 + // and ignorables in the text. 1.2241 + const UnicodeSet *ignorables = NULL; 1.2242 + UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(pattern.charAt(i)); 1.2243 + if (patternCharIndex != UDAT_FIELD_COUNT) { 1.2244 + ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex); 1.2245 + } 1.2246 + 1.2247 + for (t = textOffset; t < text.length(); t += 1) { 1.2248 + UChar ch = text.charAt(t); 1.2249 + 1.2250 + if (ignorables == NULL || !ignorables->contains(ch)) { 1.2251 + break; 1.2252 + } 1.2253 + } 1.2254 + } 1.2255 + 1.2256 + // if we get here, we've got a complete match. 1.2257 + patternOffset = i - 1; 1.2258 + textOffset = t; 1.2259 + 1.2260 + return TRUE; 1.2261 +} 1.2262 + 1.2263 +//---------------------------------------------------------------------- 1.2264 + 1.2265 +int32_t SimpleDateFormat::matchString(const UnicodeString& text, 1.2266 + int32_t start, 1.2267 + UCalendarDateFields field, 1.2268 + const UnicodeString* data, 1.2269 + int32_t dataCount, 1.2270 + const UnicodeString* monthPattern, 1.2271 + Calendar& cal) const 1.2272 +{ 1.2273 + int32_t i = 0; 1.2274 + int32_t count = dataCount; 1.2275 + 1.2276 + if (field == UCAL_DAY_OF_WEEK) i = 1; 1.2277 + 1.2278 + // There may be multiple strings in the data[] array which begin with 1.2279 + // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech). 1.2280 + // We keep track of the longest match, and return that. Note that this 1.2281 + // unfortunately requires us to test all array elements. 1.2282 + int32_t bestMatchLength = 0, bestMatch = -1; 1.2283 + UnicodeString bestMatchName; 1.2284 + int32_t isLeapMonth = 0; 1.2285 + 1.2286 + // {sfb} kludge to support case-insensitive comparison 1.2287 + // {markus 2002oct11} do not just use caseCompareBetween because we do not know 1.2288 + // the length of the match after case folding 1.2289 + // {alan 20040607} don't case change the whole string, since the length 1.2290 + // can change 1.2291 + // TODO we need a case-insensitive startsWith function 1.2292 + UnicodeString lcaseText; 1.2293 + text.extract(start, INT32_MAX, lcaseText); 1.2294 + lcaseText.foldCase(); 1.2295 + 1.2296 + for (; i < count; ++i) 1.2297 + { 1.2298 + // Always compare if we have no match yet; otherwise only compare 1.2299 + // against potentially better matches (longer strings). 1.2300 + 1.2301 + if (newBestMatchWithOptionalDot(lcaseText, data[i], bestMatchName, bestMatchLength)) { 1.2302 + bestMatch = i; 1.2303 + isLeapMonth = 0; 1.2304 + } 1.2305 + 1.2306 + if (monthPattern != NULL) { 1.2307 + UErrorCode status = U_ZERO_ERROR; 1.2308 + UnicodeString leapMonthName; 1.2309 + Formattable monthName((const UnicodeString&)(data[i])); 1.2310 + MessageFormat::format(*monthPattern, &monthName, 1, leapMonthName, status); 1.2311 + if (U_SUCCESS(status)) { 1.2312 + if (newBestMatchWithOptionalDot(lcaseText, leapMonthName, bestMatchName, bestMatchLength)) { 1.2313 + bestMatch = i; 1.2314 + isLeapMonth = 1; 1.2315 + } 1.2316 + } 1.2317 + } 1.2318 + } 1.2319 + if (bestMatch >= 0) 1.2320 + { 1.2321 + // Adjustment for Hebrew Calendar month Adar II 1.2322 + if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) { 1.2323 + cal.set(field,6); 1.2324 + } 1.2325 + else { 1.2326 + if (field == UCAL_YEAR) { 1.2327 + bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60 1.2328 + } 1.2329 + cal.set(field, bestMatch); 1.2330 + } 1.2331 + if (monthPattern != NULL) { 1.2332 + cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth); 1.2333 + } 1.2334 + 1.2335 + // Once we have a match, we have to determine the length of the 1.2336 + // original source string. This will usually be == the length of 1.2337 + // the case folded string, but it may differ (e.g. sharp s). 1.2338 + 1.2339 + // Most of the time, the length will be the same as the length 1.2340 + // of the string from the locale data. Sometimes it will be 1.2341 + // different, in which case we will have to figure it out by 1.2342 + // adding a character at a time, until we have a match. We do 1.2343 + // this all in one loop, where we try 'len' first (at index 1.2344 + // i==0). 1.2345 + int32_t len = bestMatchName.length(); // 99+% of the time 1.2346 + int32_t n = text.length() - start; 1.2347 + for (i=0; i<=n; ++i) { 1.2348 + int32_t j=i; 1.2349 + if (i == 0) { 1.2350 + j = len; 1.2351 + } else if (i == len) { 1.2352 + continue; // already tried this when i was 0 1.2353 + } 1.2354 + text.extract(start, j, lcaseText); 1.2355 + lcaseText.foldCase(); 1.2356 + if (bestMatchName == lcaseText) { 1.2357 + return start + j; 1.2358 + } 1.2359 + } 1.2360 + } 1.2361 + 1.2362 + return -start; 1.2363 +} 1.2364 + 1.2365 +static UBool 1.2366 +newBestMatchWithOptionalDot(const UnicodeString &lcaseText, 1.2367 + const UnicodeString &data, 1.2368 + UnicodeString &bestMatchName, 1.2369 + int32_t &bestMatchLength) { 1.2370 + UnicodeString lcase; 1.2371 + lcase.fastCopyFrom(data).foldCase(); 1.2372 + int32_t length = lcase.length(); 1.2373 + if (length <= bestMatchLength) { 1.2374 + // data cannot provide a better match. 1.2375 + return FALSE; 1.2376 + } 1.2377 + 1.2378 + if (lcaseText.compareBetween(0, length, lcase, 0, length) == 0) { 1.2379 + // normal match 1.2380 + bestMatchName = lcase; 1.2381 + bestMatchLength = length; 1.2382 + return TRUE; 1.2383 + } 1.2384 + if (lcase.charAt(--length) == 0x2e) { 1.2385 + if (lcaseText.compareBetween(0, length, lcase, 0, length) == 0) { 1.2386 + // The input text matches the data except for data's trailing dot. 1.2387 + bestMatchName = lcase; 1.2388 + bestMatchName.truncate(length); 1.2389 + bestMatchLength = length; 1.2390 + return TRUE; 1.2391 + } 1.2392 + } 1.2393 + return FALSE; 1.2394 +} 1.2395 + 1.2396 +//---------------------------------------------------------------------- 1.2397 + 1.2398 +void 1.2399 +SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status) 1.2400 +{ 1.2401 + parseAmbiguousDatesAsAfter(d, status); 1.2402 +} 1.2403 + 1.2404 +/** 1.2405 + * Private member function that converts the parsed date strings into 1.2406 + * timeFields. Returns -start (for ParsePosition) if failed. 1.2407 + * @param text the time text to be parsed. 1.2408 + * @param start where to start parsing. 1.2409 + * @param ch the pattern character for the date field text to be parsed. 1.2410 + * @param count the count of a pattern character. 1.2411 + * @return the new start position if matching succeeded; a negative number 1.2412 + * indicating matching failure, otherwise. 1.2413 + */ 1.2414 +int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count, 1.2415 + UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal, 1.2416 + int32_t patLoc, MessageFormat * numericLeapMonthFormatter) const 1.2417 +{ 1.2418 + Formattable number; 1.2419 + int32_t value = 0; 1.2420 + int32_t i; 1.2421 + int32_t ps = 0; 1.2422 + UErrorCode status = U_ZERO_ERROR; 1.2423 + ParsePosition pos(0); 1.2424 + UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch); 1.2425 + NumberFormat *currentNumberFormat; 1.2426 + UnicodeString temp; 1.2427 + UBool gotNumber = FALSE; 1.2428 + 1.2429 +#if defined (U_DEBUG_CAL) 1.2430 + //fprintf(stderr, "%s:%d - [%c] st=%d \n", __FILE__, __LINE__, (char) ch, start); 1.2431 +#endif 1.2432 + 1.2433 + if (patternCharIndex == UDAT_FIELD_COUNT) { 1.2434 + return -start; 1.2435 + } 1.2436 + 1.2437 + currentNumberFormat = getNumberFormatByIndex(patternCharIndex); 1.2438 + UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; 1.2439 + UnicodeString hebr("hebr", 4, US_INV); 1.2440 + 1.2441 + if (numericLeapMonthFormatter != NULL) { 1.2442 + numericLeapMonthFormatter->setFormats((const Format **)¤tNumberFormat, 1); 1.2443 + } 1.2444 + UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0); 1.2445 + 1.2446 + // If there are any spaces here, skip over them. If we hit the end 1.2447 + // of the string, then fail. 1.2448 + for (;;) { 1.2449 + if (start >= text.length()) { 1.2450 + return -start; 1.2451 + } 1.2452 + UChar32 c = text.char32At(start); 1.2453 + if (!u_isUWhiteSpace(c) /*||*/ && !PatternProps::isWhiteSpace(c)) { 1.2454 + break; 1.2455 + } 1.2456 + start += U16_LENGTH(c); 1.2457 + } 1.2458 + pos.setIndex(start); 1.2459 + 1.2460 + // We handle a few special cases here where we need to parse 1.2461 + // a number value. We handle further, more generic cases below. We need 1.2462 + // to handle some of them here because some fields require extra processing on 1.2463 + // the parsed value. 1.2464 + if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD || // k 1.2465 + patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD || // H 1.2466 + patternCharIndex == UDAT_HOUR1_FIELD || // h 1.2467 + patternCharIndex == UDAT_HOUR0_FIELD || // K 1.2468 + (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) || // e 1.2469 + (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) || // c 1.2470 + (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) || // M 1.2471 + (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) || // L 1.2472 + (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) || // Q 1.2473 + (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || // q 1.2474 + patternCharIndex == UDAT_YEAR_FIELD || // y 1.2475 + patternCharIndex == UDAT_YEAR_WOY_FIELD || // Y 1.2476 + patternCharIndex == UDAT_YEAR_NAME_FIELD || // U (falls back to numeric) 1.2477 + (patternCharIndex == UDAT_ERA_FIELD && isChineseCalendar) || // G 1.2478 + patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD) // S 1.2479 + { 1.2480 + int32_t parseStart = pos.getIndex(); 1.2481 + // It would be good to unify this with the obeyCount logic below, 1.2482 + // but that's going to be difficult. 1.2483 + const UnicodeString* src; 1.2484 + 1.2485 + UBool parsedNumericLeapMonth = FALSE; 1.2486 + if (numericLeapMonthFormatter != NULL && (patternCharIndex == UDAT_MONTH_FIELD || patternCharIndex == UDAT_STANDALONE_MONTH_FIELD)) { 1.2487 + int32_t argCount; 1.2488 + Formattable * args = numericLeapMonthFormatter->parse(text, pos, argCount); 1.2489 + if (args != NULL && argCount == 1 && pos.getIndex() > parseStart && args[0].isNumeric()) { 1.2490 + parsedNumericLeapMonth = TRUE; 1.2491 + number.setLong(args[0].getLong()); 1.2492 + cal.set(UCAL_IS_LEAP_MONTH, 1); 1.2493 + delete[] args; 1.2494 + } else { 1.2495 + pos.setIndex(parseStart); 1.2496 + cal.set(UCAL_IS_LEAP_MONTH, 0); 1.2497 + } 1.2498 + } 1.2499 + 1.2500 + if (!parsedNumericLeapMonth) { 1.2501 + if (obeyCount) { 1.2502 + if ((start+count) > text.length()) { 1.2503 + return -start; 1.2504 + } 1.2505 + 1.2506 + text.extractBetween(0, start + count, temp); 1.2507 + src = &temp; 1.2508 + } else { 1.2509 + src = &text; 1.2510 + } 1.2511 + 1.2512 + parseInt(*src, number, pos, allowNegative,currentNumberFormat); 1.2513 + } 1.2514 + 1.2515 + int32_t txtLoc = pos.getIndex(); 1.2516 + 1.2517 + if (txtLoc > parseStart) { 1.2518 + value = number.getLong(); 1.2519 + gotNumber = TRUE; 1.2520 + 1.2521 + // suffix processing 1.2522 + if (value < 0 ) { 1.2523 + txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE); 1.2524 + if (txtLoc != pos.getIndex()) { 1.2525 + value *= -1; 1.2526 + } 1.2527 + } 1.2528 + else { 1.2529 + txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE); 1.2530 + } 1.2531 + 1.2532 + if (!getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) { 1.2533 + // Check the range of the value 1.2534 + int32_t bias = gFieldRangeBias[patternCharIndex]; 1.2535 + if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) { 1.2536 + return -start; 1.2537 + } 1.2538 + } 1.2539 + 1.2540 + pos.setIndex(txtLoc); 1.2541 + } 1.2542 + } 1.2543 + 1.2544 + // Make sure that we got a number if 1.2545 + // we want one, and didn't get one 1.2546 + // if we don't want one. 1.2547 + switch (patternCharIndex) { 1.2548 + case UDAT_HOUR_OF_DAY1_FIELD: 1.2549 + case UDAT_HOUR_OF_DAY0_FIELD: 1.2550 + case UDAT_HOUR1_FIELD: 1.2551 + case UDAT_HOUR0_FIELD: 1.2552 + // special range check for hours: 1.2553 + if (value < 0 || value > 24) { 1.2554 + return -start; 1.2555 + } 1.2556 + 1.2557 + // fall through to gotNumber check 1.2558 + 1.2559 + case UDAT_YEAR_FIELD: 1.2560 + case UDAT_YEAR_WOY_FIELD: 1.2561 + case UDAT_FRACTIONAL_SECOND_FIELD: 1.2562 + // these must be a number 1.2563 + if (! gotNumber) { 1.2564 + return -start; 1.2565 + } 1.2566 + 1.2567 + break; 1.2568 + 1.2569 + default: 1.2570 + // we check the rest of the fields below. 1.2571 + break; 1.2572 + } 1.2573 + 1.2574 + switch (patternCharIndex) { 1.2575 + case UDAT_ERA_FIELD: 1.2576 + if (isChineseCalendar) { 1.2577 + if (!gotNumber) { 1.2578 + return -start; 1.2579 + } 1.2580 + cal.set(UCAL_ERA, value); 1.2581 + return pos.getIndex(); 1.2582 + } 1.2583 + if (count == 5) { 1.2584 + ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, NULL, cal); 1.2585 + } else if (count == 4) { 1.2586 + ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, NULL, cal); 1.2587 + } else { 1.2588 + ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, NULL, cal); 1.2589 + } 1.2590 + 1.2591 + // check return position, if it equals -start, then matchString error 1.2592 + // special case the return code so we don't necessarily fail out until we 1.2593 + // verify no year information also 1.2594 + if (ps == -start) 1.2595 + ps--; 1.2596 + 1.2597 + return ps; 1.2598 + 1.2599 + case UDAT_YEAR_FIELD: 1.2600 + // If there are 3 or more YEAR pattern characters, this indicates 1.2601 + // that the year value is to be treated literally, without any 1.2602 + // two-digit year adjustments (e.g., from "01" to 2001). Otherwise 1.2603 + // we made adjustments to place the 2-digit year in the proper 1.2604 + // century, for parsed strings from "00" to "99". Any other string 1.2605 + // is treated literally: "2250", "-1", "1", "002". 1.2606 + if (fDateOverride.compare(hebr)==0 && value < 1000) { 1.2607 + value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR; 1.2608 + } else if ((pos.getIndex() - start) == 2 && !isChineseCalendar 1.2609 + && u_isdigit(text.charAt(start)) 1.2610 + && u_isdigit(text.charAt(start+1))) 1.2611 + { 1.2612 + // only adjust year for patterns less than 3. 1.2613 + if(count < 3) { 1.2614 + // Assume for example that the defaultCenturyStart is 6/18/1903. 1.2615 + // This means that two-digit years will be forced into the range 1.2616 + // 6/18/1903 to 6/17/2003. As a result, years 00, 01, and 02 1.2617 + // correspond to 2000, 2001, and 2002. Years 04, 05, etc. correspond 1.2618 + // to 1904, 1905, etc. If the year is 03, then it is 2003 if the 1.2619 + // other fields specify a date before 6/18, or 1903 if they specify a 1.2620 + // date afterwards. As a result, 03 is an ambiguous year. All other 1.2621 + // two-digit years are unambiguous. 1.2622 + if(fHaveDefaultCentury) { // check if this formatter even has a pivot year 1.2623 + int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100; 1.2624 + ambiguousYear[0] = (value == ambiguousTwoDigitYear); 1.2625 + value += (fDefaultCenturyStartYear/100)*100 + 1.2626 + (value < ambiguousTwoDigitYear ? 100 : 0); 1.2627 + } 1.2628 + } 1.2629 + } 1.2630 + cal.set(UCAL_YEAR, value); 1.2631 + 1.2632 + // Delayed checking for adjustment of Hebrew month numbers in non-leap years. 1.2633 + if (saveHebrewMonth >= 0) { 1.2634 + HebrewCalendar *hc = (HebrewCalendar*)&cal; 1.2635 + if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) { 1.2636 + cal.set(UCAL_MONTH,saveHebrewMonth); 1.2637 + } else { 1.2638 + cal.set(UCAL_MONTH,saveHebrewMonth-1); 1.2639 + } 1.2640 + saveHebrewMonth = -1; 1.2641 + } 1.2642 + return pos.getIndex(); 1.2643 + 1.2644 + case UDAT_YEAR_WOY_FIELD: 1.2645 + // Comment is the same as for UDAT_Year_FIELDs - look above 1.2646 + if (fDateOverride.compare(hebr)==0 && value < 1000) { 1.2647 + value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR; 1.2648 + } else if ((pos.getIndex() - start) == 2 1.2649 + && u_isdigit(text.charAt(start)) 1.2650 + && u_isdigit(text.charAt(start+1)) 1.2651 + && fHaveDefaultCentury ) 1.2652 + { 1.2653 + int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100; 1.2654 + ambiguousYear[0] = (value == ambiguousTwoDigitYear); 1.2655 + value += (fDefaultCenturyStartYear/100)*100 + 1.2656 + (value < ambiguousTwoDigitYear ? 100 : 0); 1.2657 + } 1.2658 + cal.set(UCAL_YEAR_WOY, value); 1.2659 + return pos.getIndex(); 1.2660 + 1.2661 + case UDAT_YEAR_NAME_FIELD: 1.2662 + if (fSymbols->fShortYearNames != NULL) { 1.2663 + int32_t newStart = matchString(text, start, UCAL_YEAR, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount, NULL, cal); 1.2664 + if (newStart > 0) { 1.2665 + return newStart; 1.2666 + } 1.2667 + } 1.2668 + if (gotNumber && (getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC,status) || value > fSymbols->fShortYearNamesCount)) { 1.2669 + cal.set(UCAL_YEAR, value); 1.2670 + return pos.getIndex(); 1.2671 + } 1.2672 + return -start; 1.2673 + 1.2674 + case UDAT_MONTH_FIELD: 1.2675 + case UDAT_STANDALONE_MONTH_FIELD: 1.2676 + if (gotNumber) // i.e., M or MM. 1.2677 + { 1.2678 + // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether 1.2679 + // 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 1.2680 + // the year is parsed. 1.2681 + if (!strcmp(cal.getType(),"hebrew")) { 1.2682 + HebrewCalendar *hc = (HebrewCalendar*)&cal; 1.2683 + if (cal.isSet(UCAL_YEAR)) { 1.2684 + UErrorCode status = U_ZERO_ERROR; 1.2685 + if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) { 1.2686 + cal.set(UCAL_MONTH, value); 1.2687 + } else { 1.2688 + cal.set(UCAL_MONTH, value - 1); 1.2689 + } 1.2690 + } else { 1.2691 + saveHebrewMonth = value; 1.2692 + } 1.2693 + } else { 1.2694 + // Don't want to parse the month if it is a string 1.2695 + // while pattern uses numeric style: M/MM, L/LL 1.2696 + // [We computed 'value' above.] 1.2697 + cal.set(UCAL_MONTH, value - 1); 1.2698 + } 1.2699 + return pos.getIndex(); 1.2700 + } else { 1.2701 + // count >= 3 // i.e., MMM/MMMM, LLL/LLLL 1.2702 + // Want to be able to parse both short and long forms. 1.2703 + // Try count == 4 first: 1.2704 + UnicodeString * wideMonthPat = NULL; 1.2705 + UnicodeString * shortMonthPat = NULL; 1.2706 + if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) { 1.2707 + if (patternCharIndex==UDAT_MONTH_FIELD) { 1.2708 + wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]; 1.2709 + shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]; 1.2710 + } else { 1.2711 + wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]; 1.2712 + shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]; 1.2713 + } 1.2714 + } 1.2715 + int32_t newStart = 0; 1.2716 + if (patternCharIndex==UDAT_MONTH_FIELD) { 1.2717 + newStart = matchString(text, start, UCAL_MONTH, fSymbols->fMonths, fSymbols->fMonthsCount, wideMonthPat, cal); // try MMMM 1.2718 + if (newStart > 0) { 1.2719 + return newStart; 1.2720 + } 1.2721 + newStart = matchString(text, start, UCAL_MONTH, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, shortMonthPat, cal); // try MMM 1.2722 + } else { 1.2723 + newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, wideMonthPat, cal); // try LLLL 1.2724 + if (newStart > 0) { 1.2725 + return newStart; 1.2726 + } 1.2727 + newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, shortMonthPat, cal); // try LLL 1.2728 + } 1.2729 + if (newStart > 0 || !getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) // currently we do not try to parse MMMMM/LLLLL: #8860 1.2730 + return newStart; 1.2731 + // else we allowing parsing as number, below 1.2732 + } 1.2733 + break; 1.2734 + 1.2735 + case UDAT_HOUR_OF_DAY1_FIELD: 1.2736 + // [We computed 'value' above.] 1.2737 + if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1) 1.2738 + value = 0; 1.2739 + 1.2740 + // fall through to set field 1.2741 + 1.2742 + case UDAT_HOUR_OF_DAY0_FIELD: 1.2743 + cal.set(UCAL_HOUR_OF_DAY, value); 1.2744 + return pos.getIndex(); 1.2745 + 1.2746 + case UDAT_FRACTIONAL_SECOND_FIELD: 1.2747 + // Fractional seconds left-justify 1.2748 + i = pos.getIndex() - start; 1.2749 + if (i < 3) { 1.2750 + while (i < 3) { 1.2751 + value *= 10; 1.2752 + i++; 1.2753 + } 1.2754 + } else { 1.2755 + int32_t a = 1; 1.2756 + while (i > 3) { 1.2757 + a *= 10; 1.2758 + i--; 1.2759 + } 1.2760 + value /= a; 1.2761 + } 1.2762 + cal.set(UCAL_MILLISECOND, value); 1.2763 + return pos.getIndex(); 1.2764 + 1.2765 + case UDAT_DOW_LOCAL_FIELD: 1.2766 + if (gotNumber) // i.e., e or ee 1.2767 + { 1.2768 + // [We computed 'value' above.] 1.2769 + cal.set(UCAL_DOW_LOCAL, value); 1.2770 + return pos.getIndex(); 1.2771 + } 1.2772 + // else for eee-eeeee fall through to handling of EEE-EEEEE 1.2773 + // fall through, do not break here 1.2774 + case UDAT_DAY_OF_WEEK_FIELD: 1.2775 + { 1.2776 + // Want to be able to parse both short and long forms. 1.2777 + // Try count == 4 (EEEE) wide first: 1.2778 + int32_t newStart = 0; 1.2779 + if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 1.2780 + fSymbols->fWeekdays, fSymbols->fWeekdaysCount, NULL, cal)) > 0) 1.2781 + return newStart; 1.2782 + // EEEE wide failed, now try EEE abbreviated 1.2783 + else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 1.2784 + fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, NULL, cal)) > 0) 1.2785 + return newStart; 1.2786 + // EEE abbreviated failed, now try EEEEEE short 1.2787 + else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 1.2788 + fSymbols->fShorterWeekdays, fSymbols->fShorterWeekdaysCount, NULL, cal)) > 0) 1.2789 + return newStart; 1.2790 + // EEEEEE short failed, now try EEEEE narrow 1.2791 + else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 1.2792 + fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, NULL, cal)) > 0) 1.2793 + return newStart; 1.2794 + else if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status) || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD) 1.2795 + return newStart; 1.2796 + // else we allowing parsing as number, below 1.2797 + } 1.2798 + break; 1.2799 + 1.2800 + case UDAT_STANDALONE_DAY_FIELD: 1.2801 + { 1.2802 + if (gotNumber) // c or cc 1.2803 + { 1.2804 + // [We computed 'value' above.] 1.2805 + cal.set(UCAL_DOW_LOCAL, value); 1.2806 + return pos.getIndex(); 1.2807 + } 1.2808 + // Want to be able to parse both short and long forms. 1.2809 + // Try count == 4 (cccc) first: 1.2810 + int32_t newStart = 0; 1.2811 + if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 1.2812 + fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, NULL, cal)) > 0) 1.2813 + return newStart; 1.2814 + else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 1.2815 + fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, NULL, cal)) > 0) 1.2816 + return newStart; 1.2817 + else if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK, 1.2818 + fSymbols->fStandaloneShorterWeekdays, fSymbols->fStandaloneShorterWeekdaysCount, NULL, cal)) > 0) 1.2819 + return newStart; 1.2820 + else if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) 1.2821 + return newStart; 1.2822 + // else we allowing parsing as number, below 1.2823 + } 1.2824 + break; 1.2825 + 1.2826 + case UDAT_AM_PM_FIELD: 1.2827 + return matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal); 1.2828 + 1.2829 + case UDAT_HOUR1_FIELD: 1.2830 + // [We computed 'value' above.] 1.2831 + if (value == cal.getLeastMaximum(UCAL_HOUR)+1) 1.2832 + value = 0; 1.2833 + 1.2834 + // fall through to set field 1.2835 + 1.2836 + case UDAT_HOUR0_FIELD: 1.2837 + cal.set(UCAL_HOUR, value); 1.2838 + return pos.getIndex(); 1.2839 + 1.2840 + case UDAT_QUARTER_FIELD: 1.2841 + if (gotNumber) // i.e., Q or QQ. 1.2842 + { 1.2843 + // Don't want to parse the month if it is a string 1.2844 + // while pattern uses numeric style: Q or QQ. 1.2845 + // [We computed 'value' above.] 1.2846 + cal.set(UCAL_MONTH, (value - 1) * 3); 1.2847 + return pos.getIndex(); 1.2848 + } else { 1.2849 + // count >= 3 // i.e., QQQ or QQQQ 1.2850 + // Want to be able to parse both short and long forms. 1.2851 + // Try count == 4 first: 1.2852 + int32_t newStart = 0; 1.2853 + 1.2854 + if ((newStart = matchQuarterString(text, start, UCAL_MONTH, 1.2855 + fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0) 1.2856 + return newStart; 1.2857 + else if ((newStart = matchQuarterString(text, start, UCAL_MONTH, 1.2858 + fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0) 1.2859 + return newStart; 1.2860 + else if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) 1.2861 + return newStart; 1.2862 + // else we allowing parsing as number, below 1.2863 + } 1.2864 + break; 1.2865 + 1.2866 + case UDAT_STANDALONE_QUARTER_FIELD: 1.2867 + if (gotNumber) // i.e., q or qq. 1.2868 + { 1.2869 + // Don't want to parse the month if it is a string 1.2870 + // while pattern uses numeric style: q or q. 1.2871 + // [We computed 'value' above.] 1.2872 + cal.set(UCAL_MONTH, (value - 1) * 3); 1.2873 + return pos.getIndex(); 1.2874 + } else { 1.2875 + // count >= 3 // i.e., qqq or qqqq 1.2876 + // Want to be able to parse both short and long forms. 1.2877 + // Try count == 4 first: 1.2878 + int32_t newStart = 0; 1.2879 + 1.2880 + if ((newStart = matchQuarterString(text, start, UCAL_MONTH, 1.2881 + fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0) 1.2882 + return newStart; 1.2883 + else if ((newStart = matchQuarterString(text, start, UCAL_MONTH, 1.2884 + fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0) 1.2885 + return newStart; 1.2886 + else if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) 1.2887 + return newStart; 1.2888 + // else we allowing parsing as number, below 1.2889 + } 1.2890 + break; 1.2891 + 1.2892 + case UDAT_TIMEZONE_FIELD: // 'z' 1.2893 + { 1.2894 + UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; 1.2895 + UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG; 1.2896 + TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType); 1.2897 + if (tz != NULL) { 1.2898 + ((SimpleDateFormat*)this)->tztype = tzTimeType; 1.2899 + cal.adoptTimeZone(tz); 1.2900 + return pos.getIndex(); 1.2901 + } 1.2902 + } 1.2903 + break; 1.2904 + case UDAT_TIMEZONE_RFC_FIELD: // 'Z' 1.2905 + { 1.2906 + UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; 1.2907 + UTimeZoneFormatStyle style = (count < 4) ? 1.2908 + UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT); 1.2909 + TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType); 1.2910 + if (tz != NULL) { 1.2911 + ((SimpleDateFormat*)this)->tztype = tzTimeType; 1.2912 + cal.adoptTimeZone(tz); 1.2913 + return pos.getIndex(); 1.2914 + } 1.2915 + return -start; 1.2916 + } 1.2917 + case UDAT_TIMEZONE_GENERIC_FIELD: // 'v' 1.2918 + { 1.2919 + UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; 1.2920 + UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG; 1.2921 + TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType); 1.2922 + if (tz != NULL) { 1.2923 + ((SimpleDateFormat*)this)->tztype = tzTimeType; 1.2924 + cal.adoptTimeZone(tz); 1.2925 + return pos.getIndex(); 1.2926 + } 1.2927 + return -start; 1.2928 + } 1.2929 + case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V' 1.2930 + { 1.2931 + UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; 1.2932 + UTimeZoneFormatStyle style; 1.2933 + switch (count) { 1.2934 + case 1: 1.2935 + style = UTZFMT_STYLE_ZONE_ID_SHORT; 1.2936 + break; 1.2937 + case 2: 1.2938 + style = UTZFMT_STYLE_ZONE_ID; 1.2939 + break; 1.2940 + case 3: 1.2941 + style = UTZFMT_STYLE_EXEMPLAR_LOCATION; 1.2942 + break; 1.2943 + default: 1.2944 + style = UTZFMT_STYLE_GENERIC_LOCATION; 1.2945 + break; 1.2946 + } 1.2947 + TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType); 1.2948 + if (tz != NULL) { 1.2949 + ((SimpleDateFormat*)this)->tztype = tzTimeType; 1.2950 + cal.adoptTimeZone(tz); 1.2951 + return pos.getIndex(); 1.2952 + } 1.2953 + return -start; 1.2954 + } 1.2955 + case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O' 1.2956 + { 1.2957 + UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; 1.2958 + UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT; 1.2959 + TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType); 1.2960 + if (tz != NULL) { 1.2961 + ((SimpleDateFormat*)this)->tztype = tzTimeType; 1.2962 + cal.adoptTimeZone(tz); 1.2963 + return pos.getIndex(); 1.2964 + } 1.2965 + return -start; 1.2966 + } 1.2967 + case UDAT_TIMEZONE_ISO_FIELD: // 'X' 1.2968 + { 1.2969 + UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; 1.2970 + UTimeZoneFormatStyle style; 1.2971 + switch (count) { 1.2972 + case 1: 1.2973 + style = UTZFMT_STYLE_ISO_BASIC_SHORT; 1.2974 + break; 1.2975 + case 2: 1.2976 + style = UTZFMT_STYLE_ISO_BASIC_FIXED; 1.2977 + break; 1.2978 + case 3: 1.2979 + style = UTZFMT_STYLE_ISO_EXTENDED_FIXED; 1.2980 + break; 1.2981 + case 4: 1.2982 + style = UTZFMT_STYLE_ISO_BASIC_FULL; 1.2983 + break; 1.2984 + default: 1.2985 + style = UTZFMT_STYLE_ISO_EXTENDED_FULL; 1.2986 + break; 1.2987 + } 1.2988 + TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType); 1.2989 + if (tz != NULL) { 1.2990 + ((SimpleDateFormat*)this)->tztype = tzTimeType; 1.2991 + cal.adoptTimeZone(tz); 1.2992 + return pos.getIndex(); 1.2993 + } 1.2994 + return -start; 1.2995 + } 1.2996 + case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x' 1.2997 + { 1.2998 + UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN; 1.2999 + UTimeZoneFormatStyle style; 1.3000 + switch (count) { 1.3001 + case 1: 1.3002 + style = UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT; 1.3003 + break; 1.3004 + case 2: 1.3005 + style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED; 1.3006 + break; 1.3007 + case 3: 1.3008 + style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED; 1.3009 + break; 1.3010 + case 4: 1.3011 + style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL; 1.3012 + break; 1.3013 + default: 1.3014 + style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL; 1.3015 + break; 1.3016 + } 1.3017 + TimeZone *tz = tzFormat()->parse(style, text, pos, &tzTimeType); 1.3018 + if (tz != NULL) { 1.3019 + ((SimpleDateFormat*)this)->tztype = tzTimeType; 1.3020 + cal.adoptTimeZone(tz); 1.3021 + return pos.getIndex(); 1.3022 + } 1.3023 + return -start; 1.3024 + } 1.3025 + 1.3026 + default: 1.3027 + // Handle "generic" fields 1.3028 + // this is now handled below, outside the switch block 1.3029 + break; 1.3030 + } 1.3031 + // Handle "generic" fields: 1.3032 + // switch default case now handled here (outside switch block) to allow 1.3033 + // parsing of some string fields as digits for lenient case 1.3034 + 1.3035 + int32_t parseStart = pos.getIndex(); 1.3036 + const UnicodeString* src; 1.3037 + if (obeyCount) { 1.3038 + if ((start+count) > text.length()) { 1.3039 + return -start; 1.3040 + } 1.3041 + text.extractBetween(0, start + count, temp); 1.3042 + src = &temp; 1.3043 + } else { 1.3044 + src = &text; 1.3045 + } 1.3046 + parseInt(*src, number, pos, allowNegative,currentNumberFormat); 1.3047 + if (pos.getIndex() != parseStart) { 1.3048 + int32_t value = number.getLong(); 1.3049 + 1.3050 + // Don't need suffix processing here (as in number processing at the beginning of the function); 1.3051 + // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes. 1.3052 + 1.3053 + if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) { 1.3054 + // Check the range of the value 1.3055 + int32_t bias = gFieldRangeBias[patternCharIndex]; 1.3056 + if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) { 1.3057 + return -start; 1.3058 + } 1.3059 + } 1.3060 + 1.3061 + // For the following, need to repeat some of the "if (gotNumber)" code above: 1.3062 + // UDAT_[STANDALONE_]MONTH_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_STANDALONE_DAY_FIELD, 1.3063 + // UDAT_[STANDALONE_]QUARTER_FIELD 1.3064 + switch (patternCharIndex) { 1.3065 + case UDAT_MONTH_FIELD: 1.3066 + // See notes under UDAT_MONTH_FIELD case above 1.3067 + if (!strcmp(cal.getType(),"hebrew")) { 1.3068 + HebrewCalendar *hc = (HebrewCalendar*)&cal; 1.3069 + if (cal.isSet(UCAL_YEAR)) { 1.3070 + UErrorCode status = U_ZERO_ERROR; 1.3071 + if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) { 1.3072 + cal.set(UCAL_MONTH, value); 1.3073 + } else { 1.3074 + cal.set(UCAL_MONTH, value - 1); 1.3075 + } 1.3076 + } else { 1.3077 + saveHebrewMonth = value; 1.3078 + } 1.3079 + } else { 1.3080 + cal.set(UCAL_MONTH, value - 1); 1.3081 + } 1.3082 + break; 1.3083 + case UDAT_STANDALONE_MONTH_FIELD: 1.3084 + cal.set(UCAL_MONTH, value - 1); 1.3085 + break; 1.3086 + case UDAT_DOW_LOCAL_FIELD: 1.3087 + case UDAT_STANDALONE_DAY_FIELD: 1.3088 + cal.set(UCAL_DOW_LOCAL, value); 1.3089 + break; 1.3090 + case UDAT_QUARTER_FIELD: 1.3091 + case UDAT_STANDALONE_QUARTER_FIELD: 1.3092 + cal.set(UCAL_MONTH, (value - 1) * 3); 1.3093 + break; 1.3094 + default: 1.3095 + cal.set(field, value); 1.3096 + break; 1.3097 + } 1.3098 + return pos.getIndex(); 1.3099 + } 1.3100 + return -start; 1.3101 +} 1.3102 + 1.3103 +/** 1.3104 + * Parse an integer using fNumberFormat. This method is semantically 1.3105 + * const, but actually may modify fNumberFormat. 1.3106 + */ 1.3107 +void SimpleDateFormat::parseInt(const UnicodeString& text, 1.3108 + Formattable& number, 1.3109 + ParsePosition& pos, 1.3110 + UBool allowNegative, 1.3111 + NumberFormat *fmt) const { 1.3112 + parseInt(text, number, -1, pos, allowNegative,fmt); 1.3113 +} 1.3114 + 1.3115 +/** 1.3116 + * Parse an integer using fNumberFormat up to maxDigits. 1.3117 + */ 1.3118 +void SimpleDateFormat::parseInt(const UnicodeString& text, 1.3119 + Formattable& number, 1.3120 + int32_t maxDigits, 1.3121 + ParsePosition& pos, 1.3122 + UBool allowNegative, 1.3123 + NumberFormat *fmt) const { 1.3124 + UnicodeString oldPrefix; 1.3125 + DecimalFormat* df = NULL; 1.3126 + if (!allowNegative && (df = dynamic_cast<DecimalFormat*>(fmt)) != NULL) { 1.3127 + df->getNegativePrefix(oldPrefix); 1.3128 + df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1)); 1.3129 + } 1.3130 + int32_t oldPos = pos.getIndex(); 1.3131 + fmt->parse(text, number, pos); 1.3132 + if (df != NULL) { 1.3133 + df->setNegativePrefix(oldPrefix); 1.3134 + } 1.3135 + 1.3136 + if (maxDigits > 0) { 1.3137 + // adjust the result to fit into 1.3138 + // the maxDigits and move the position back 1.3139 + int32_t nDigits = pos.getIndex() - oldPos; 1.3140 + if (nDigits > maxDigits) { 1.3141 + int32_t val = number.getLong(); 1.3142 + nDigits -= maxDigits; 1.3143 + while (nDigits > 0) { 1.3144 + val /= 10; 1.3145 + nDigits--; 1.3146 + } 1.3147 + pos.setIndex(oldPos + maxDigits); 1.3148 + number.setLong(val); 1.3149 + } 1.3150 + } 1.3151 +} 1.3152 + 1.3153 +//---------------------------------------------------------------------- 1.3154 + 1.3155 +void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern, 1.3156 + UnicodeString& translatedPattern, 1.3157 + const UnicodeString& from, 1.3158 + const UnicodeString& to, 1.3159 + UErrorCode& status) 1.3160 +{ 1.3161 + // run through the pattern and convert any pattern symbols from the version 1.3162 + // in "from" to the corresponding character ion "to". This code takes 1.3163 + // quoted strings into account (it doesn't try to translate them), and it signals 1.3164 + // an error if a particular "pattern character" doesn't appear in "from". 1.3165 + // Depending on the values of "from" and "to" this can convert from generic 1.3166 + // to localized patterns or localized to generic. 1.3167 + if (U_FAILURE(status)) 1.3168 + return; 1.3169 + 1.3170 + translatedPattern.remove(); 1.3171 + UBool inQuote = FALSE; 1.3172 + for (int32_t i = 0; i < originalPattern.length(); ++i) { 1.3173 + UChar c = originalPattern[i]; 1.3174 + if (inQuote) { 1.3175 + if (c == QUOTE) 1.3176 + inQuote = FALSE; 1.3177 + } 1.3178 + else { 1.3179 + if (c == QUOTE) 1.3180 + inQuote = TRUE; 1.3181 + else if ((c >= 0x0061 /*'a'*/ && c <= 0x007A) /*'z'*/ 1.3182 + || (c >= 0x0041 /*'A'*/ && c <= 0x005A /*'Z'*/)) { 1.3183 + int32_t ci = from.indexOf(c); 1.3184 + if (ci == -1) { 1.3185 + status = U_INVALID_FORMAT_ERROR; 1.3186 + return; 1.3187 + } 1.3188 + c = to[ci]; 1.3189 + } 1.3190 + } 1.3191 + translatedPattern += c; 1.3192 + } 1.3193 + if (inQuote) { 1.3194 + status = U_INVALID_FORMAT_ERROR; 1.3195 + return; 1.3196 + } 1.3197 +} 1.3198 + 1.3199 +//---------------------------------------------------------------------- 1.3200 + 1.3201 +UnicodeString& 1.3202 +SimpleDateFormat::toPattern(UnicodeString& result) const 1.3203 +{ 1.3204 + result = fPattern; 1.3205 + return result; 1.3206 +} 1.3207 + 1.3208 +//---------------------------------------------------------------------- 1.3209 + 1.3210 +UnicodeString& 1.3211 +SimpleDateFormat::toLocalizedPattern(UnicodeString& result, 1.3212 + UErrorCode& status) const 1.3213 +{ 1.3214 + translatePattern(fPattern, result, 1.3215 + UnicodeString(DateFormatSymbols::getPatternUChars()), 1.3216 + fSymbols->fLocalPatternChars, status); 1.3217 + return result; 1.3218 +} 1.3219 + 1.3220 +//---------------------------------------------------------------------- 1.3221 + 1.3222 +void 1.3223 +SimpleDateFormat::applyPattern(const UnicodeString& pattern) 1.3224 +{ 1.3225 + fPattern = pattern; 1.3226 +} 1.3227 + 1.3228 +//---------------------------------------------------------------------- 1.3229 + 1.3230 +void 1.3231 +SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern, 1.3232 + UErrorCode &status) 1.3233 +{ 1.3234 + translatePattern(pattern, fPattern, 1.3235 + fSymbols->fLocalPatternChars, 1.3236 + UnicodeString(DateFormatSymbols::getPatternUChars()), status); 1.3237 +} 1.3238 + 1.3239 +//---------------------------------------------------------------------- 1.3240 + 1.3241 +const DateFormatSymbols* 1.3242 +SimpleDateFormat::getDateFormatSymbols() const 1.3243 +{ 1.3244 + return fSymbols; 1.3245 +} 1.3246 + 1.3247 +//---------------------------------------------------------------------- 1.3248 + 1.3249 +void 1.3250 +SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols) 1.3251 +{ 1.3252 + delete fSymbols; 1.3253 + fSymbols = newFormatSymbols; 1.3254 +} 1.3255 + 1.3256 +//---------------------------------------------------------------------- 1.3257 +void 1.3258 +SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols) 1.3259 +{ 1.3260 + delete fSymbols; 1.3261 + fSymbols = new DateFormatSymbols(newFormatSymbols); 1.3262 +} 1.3263 + 1.3264 +//---------------------------------------------------------------------- 1.3265 +const TimeZoneFormat* 1.3266 +SimpleDateFormat::getTimeZoneFormat(void) const { 1.3267 + return (const TimeZoneFormat*)tzFormat(); 1.3268 +} 1.3269 + 1.3270 +//---------------------------------------------------------------------- 1.3271 +void 1.3272 +SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt) 1.3273 +{ 1.3274 + delete fTimeZoneFormat; 1.3275 + fTimeZoneFormat = timeZoneFormatToAdopt; 1.3276 +} 1.3277 + 1.3278 +//---------------------------------------------------------------------- 1.3279 +void 1.3280 +SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat) 1.3281 +{ 1.3282 + delete fTimeZoneFormat; 1.3283 + fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat); 1.3284 +} 1.3285 + 1.3286 +//---------------------------------------------------------------------- 1.3287 + 1.3288 + 1.3289 +void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt) 1.3290 +{ 1.3291 + UErrorCode status = U_ZERO_ERROR; 1.3292 + DateFormat::adoptCalendar(calendarToAdopt); 1.3293 + delete fSymbols; 1.3294 + fSymbols=NULL; 1.3295 + initializeSymbols(fLocale, fCalendar, status); // we need new symbols 1.3296 + initializeDefaultCentury(); // we need a new century (possibly) 1.3297 +} 1.3298 + 1.3299 + 1.3300 +//---------------------------------------------------------------------- 1.3301 + 1.3302 + 1.3303 +void SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status) 1.3304 +{ 1.3305 + if (U_FAILURE(status)) 1.3306 + return; 1.3307 + if ( (UDisplayContextType)((uint32_t)value >> 8) == UDISPCTX_TYPE_CAPITALIZATION ) { 1.3308 + fCapitalizationContext = value; 1.3309 + } else { 1.3310 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.3311 + } 1.3312 +} 1.3313 + 1.3314 + 1.3315 +//---------------------------------------------------------------------- 1.3316 + 1.3317 + 1.3318 +UDisplayContext SimpleDateFormat::getContext(UDisplayContextType type, UErrorCode& status) const 1.3319 +{ 1.3320 + if (U_FAILURE(status)) 1.3321 + return (UDisplayContext)0; 1.3322 + if (type != UDISPCTX_TYPE_CAPITALIZATION) { 1.3323 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.3324 + return (UDisplayContext)0; 1.3325 + } 1.3326 + return fCapitalizationContext; 1.3327 +} 1.3328 + 1.3329 + 1.3330 +//---------------------------------------------------------------------- 1.3331 + 1.3332 + 1.3333 +UBool 1.3334 +SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const { 1.3335 + return isFieldUnitIgnored(fPattern, field); 1.3336 +} 1.3337 + 1.3338 + 1.3339 +UBool 1.3340 +SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern, 1.3341 + UCalendarDateFields field) { 1.3342 + int32_t fieldLevel = fgCalendarFieldToLevel[field]; 1.3343 + int32_t level; 1.3344 + UChar ch; 1.3345 + UBool inQuote = FALSE; 1.3346 + UChar prevCh = 0; 1.3347 + int32_t count = 0; 1.3348 + 1.3349 + for (int32_t i = 0; i < pattern.length(); ++i) { 1.3350 + ch = pattern[i]; 1.3351 + if (ch != prevCh && count > 0) { 1.3352 + level = fgPatternCharToLevel[prevCh - PATTERN_CHAR_BASE]; 1.3353 + // the larger the level, the smaller the field unit. 1.3354 + if ( fieldLevel <= level ) { 1.3355 + return FALSE; 1.3356 + } 1.3357 + count = 0; 1.3358 + } 1.3359 + if (ch == QUOTE) { 1.3360 + if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) { 1.3361 + ++i; 1.3362 + } else { 1.3363 + inQuote = ! inQuote; 1.3364 + } 1.3365 + } 1.3366 + else if ( ! inQuote && ((ch >= 0x0061 /*'a'*/ && ch <= 0x007A /*'z'*/) 1.3367 + || (ch >= 0x0041 /*'A'*/ && ch <= 0x005A /*'Z'*/))) { 1.3368 + prevCh = ch; 1.3369 + ++count; 1.3370 + } 1.3371 + } 1.3372 + if ( count > 0 ) { 1.3373 + // last item 1.3374 + level = fgPatternCharToLevel[prevCh - PATTERN_CHAR_BASE]; 1.3375 + if ( fieldLevel <= level ) { 1.3376 + return FALSE; 1.3377 + } 1.3378 + } 1.3379 + return TRUE; 1.3380 +} 1.3381 + 1.3382 +//---------------------------------------------------------------------- 1.3383 + 1.3384 +const Locale& 1.3385 +SimpleDateFormat::getSmpFmtLocale(void) const { 1.3386 + return fLocale; 1.3387 +} 1.3388 + 1.3389 +//---------------------------------------------------------------------- 1.3390 + 1.3391 +int32_t 1.3392 +SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start, 1.3393 + int32_t patLoc, UBool isNegative) const { 1.3394 + // local variables 1.3395 + UnicodeString suf; 1.3396 + int32_t patternMatch; 1.3397 + int32_t textPreMatch; 1.3398 + int32_t textPostMatch; 1.3399 + 1.3400 + // check that we are still in range 1.3401 + if ( (start > text.length()) || 1.3402 + (start < 0) || 1.3403 + (patLoc < 0) || 1.3404 + (patLoc > fPattern.length())) { 1.3405 + // out of range, don't advance location in text 1.3406 + return start; 1.3407 + } 1.3408 + 1.3409 + // get the suffix 1.3410 + DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat); 1.3411 + if (decfmt != NULL) { 1.3412 + if (isNegative) { 1.3413 + suf = decfmt->getNegativeSuffix(suf); 1.3414 + } 1.3415 + else { 1.3416 + suf = decfmt->getPositiveSuffix(suf); 1.3417 + } 1.3418 + } 1.3419 + 1.3420 + // check for suffix 1.3421 + if (suf.length() <= 0) { 1.3422 + return start; 1.3423 + } 1.3424 + 1.3425 + // check suffix will be encountered in the pattern 1.3426 + patternMatch = compareSimpleAffix(suf,fPattern,patLoc); 1.3427 + 1.3428 + // check if a suffix will be encountered in the text 1.3429 + textPreMatch = compareSimpleAffix(suf,text,start); 1.3430 + 1.3431 + // check if a suffix was encountered in the text 1.3432 + textPostMatch = compareSimpleAffix(suf,text,start-suf.length()); 1.3433 + 1.3434 + // check for suffix match 1.3435 + if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) { 1.3436 + return start; 1.3437 + } 1.3438 + else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) { 1.3439 + return start - suf.length(); 1.3440 + } 1.3441 + 1.3442 + // should not get here 1.3443 + return start; 1.3444 +} 1.3445 + 1.3446 +//---------------------------------------------------------------------- 1.3447 + 1.3448 +int32_t 1.3449 +SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix, 1.3450 + const UnicodeString& input, 1.3451 + int32_t pos) const { 1.3452 + int32_t start = pos; 1.3453 + for (int32_t i=0; i<affix.length(); ) { 1.3454 + UChar32 c = affix.char32At(i); 1.3455 + int32_t len = U16_LENGTH(c); 1.3456 + if (PatternProps::isWhiteSpace(c)) { 1.3457 + // We may have a pattern like: \u200F \u0020 1.3458 + // and input text like: \u200F \u0020 1.3459 + // Note that U+200F and U+0020 are Pattern_White_Space but only 1.3460 + // U+0020 is UWhiteSpace. So we have to first do a direct 1.3461 + // match of the run of Pattern_White_Space in the pattern, 1.3462 + // then match any extra characters. 1.3463 + UBool literalMatch = FALSE; 1.3464 + while (pos < input.length() && 1.3465 + input.char32At(pos) == c) { 1.3466 + literalMatch = TRUE; 1.3467 + i += len; 1.3468 + pos += len; 1.3469 + if (i == affix.length()) { 1.3470 + break; 1.3471 + } 1.3472 + c = affix.char32At(i); 1.3473 + len = U16_LENGTH(c); 1.3474 + if (!PatternProps::isWhiteSpace(c)) { 1.3475 + break; 1.3476 + } 1.3477 + } 1.3478 + 1.3479 + // Advance over run in pattern 1.3480 + i = skipPatternWhiteSpace(affix, i); 1.3481 + 1.3482 + // Advance over run in input text 1.3483 + // Must see at least one white space char in input, 1.3484 + // unless we've already matched some characters literally. 1.3485 + int32_t s = pos; 1.3486 + pos = skipUWhiteSpace(input, pos); 1.3487 + if (pos == s && !literalMatch) { 1.3488 + return -1; 1.3489 + } 1.3490 + 1.3491 + // If we skip UWhiteSpace in the input text, we need to skip it in the pattern. 1.3492 + // Otherwise, the previous lines may have skipped over text (such as U+00A0) that 1.3493 + // is also in the affix. 1.3494 + i = skipUWhiteSpace(affix, i); 1.3495 + } else { 1.3496 + if (pos < input.length() && 1.3497 + input.char32At(pos) == c) { 1.3498 + i += len; 1.3499 + pos += len; 1.3500 + } else { 1.3501 + return -1; 1.3502 + } 1.3503 + } 1.3504 + } 1.3505 + return pos - start; 1.3506 +} 1.3507 + 1.3508 +//---------------------------------------------------------------------- 1.3509 + 1.3510 +int32_t 1.3511 +SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const { 1.3512 + const UChar* s = text.getBuffer(); 1.3513 + return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s); 1.3514 +} 1.3515 + 1.3516 +//---------------------------------------------------------------------- 1.3517 + 1.3518 +int32_t 1.3519 +SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const { 1.3520 + while (pos < text.length()) { 1.3521 + UChar32 c = text.char32At(pos); 1.3522 + if (!u_isUWhiteSpace(c)) { 1.3523 + break; 1.3524 + } 1.3525 + pos += U16_LENGTH(c); 1.3526 + } 1.3527 + return pos; 1.3528 +} 1.3529 + 1.3530 +//---------------------------------------------------------------------- 1.3531 + 1.3532 +// Lazy TimeZoneFormat instantiation, semantically const. 1.3533 +TimeZoneFormat * 1.3534 +SimpleDateFormat::tzFormat() const { 1.3535 + if (fTimeZoneFormat == NULL) { 1.3536 + umtx_lock(&LOCK); 1.3537 + { 1.3538 + if (fTimeZoneFormat == NULL) { 1.3539 + UErrorCode status = U_ZERO_ERROR; 1.3540 + TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status); 1.3541 + if (U_FAILURE(status)) { 1.3542 + return NULL; 1.3543 + } 1.3544 + 1.3545 + const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt; 1.3546 + } 1.3547 + } 1.3548 + umtx_unlock(&LOCK); 1.3549 + } 1.3550 + return fTimeZoneFormat; 1.3551 +} 1.3552 + 1.3553 +U_NAMESPACE_END 1.3554 + 1.3555 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.3556 + 1.3557 +//eof