Bug Summary

File:out/../deps/icu-small/source/i18n/smpdtfmt.cpp
Warning:line 2041, column 13
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

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