Coverage Report

Created: 2025-06-24 06:43

/src/icu/source/i18n/smpdtfmt.cpp
Line
Count
Source (jump to first uncovered line)
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_MAX 128
30
31
#include "unicode/utypes.h"
32
33
#if !UCONFIG_NO_FORMATTING
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
88
U_NAMESPACE_BEGIN
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
108
typedef 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
121
typedef enum OvrStrType {
122
    kOvrStrDate = 0,
123
    kOvrStrTime = 1,
124
    kOvrStrBoth = 2
125
} OvrStrType;
126
127
static 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 };
144
static const int8_t kDateFieldsCount = 16;
145
146
static 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 };
157
static 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.
162
static 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).
170
static 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
 */
176
static 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
 */
187
static 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_SEPARATOR
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
232
static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
233
static 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
 */
240
static const double MAX_DAYLIGHT_DETECTION_RANGE = 30*365*24*60*60*1000.0;
241
242
static UMutex LOCK;
243
244
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
245
246
0
SimpleDateFormat::NSOverride::~NSOverride() {
247
0
    if (snf != NULL) {
248
0
        snf->removeRef();
249
0
    }
250
0
}
251
252
253
0
void SimpleDateFormat::NSOverride::free() {
254
0
    NSOverride *cur = this;
255
0
    while (cur) {
256
0
        NSOverride *next_temp = cur->next;
257
0
        delete cur;
258
0
        cur = next_temp;
259
0
    }
260
0
}
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
265
0
static void fixNumberFormatForDates(NumberFormat &nf) {
266
0
    nf.setGroupingUsed(FALSE);
267
0
    DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(&nf);
268
0
    if (decfmt != NULL) {
269
0
        decfmt->setDecimalSeparatorAlwaysShown(FALSE);
270
0
    }
271
0
    nf.setParseIntegerOnly(TRUE);
272
0
    nf.setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
273
0
}
274
275
static const SharedNumberFormat *createSharedNumberFormat(
276
0
        NumberFormat *nfToAdopt) {
277
0
    fixNumberFormatForDates(*nfToAdopt);
278
0
    const SharedNumberFormat *result = new SharedNumberFormat(nfToAdopt);
279
0
    if (result == NULL) {
280
0
        delete nfToAdopt;
281
0
    }
282
0
    return result;
283
0
}
284
285
static const SharedNumberFormat *createSharedNumberFormat(
286
0
        const Locale &loc, UErrorCode &status) {
287
0
    NumberFormat *nf = NumberFormat::createInstance(loc, status);
288
0
    if (U_FAILURE(status)) {
289
0
        return NULL;
290
0
    }
291
0
    const SharedNumberFormat *result = createSharedNumberFormat(nf);
292
0
    if (result == NULL) {
293
0
        status = U_MEMORY_ALLOCATION_ERROR;
294
0
    }
295
0
    return result;
296
0
}
297
298
0
static const SharedNumberFormat **allocSharedNumberFormatters() {
299
0
    const SharedNumberFormat **result = (const SharedNumberFormat**)
300
0
            uprv_malloc(UDAT_FIELD_COUNT * sizeof(const SharedNumberFormat*));
301
0
    if (result == NULL) {
302
0
        return NULL;
303
0
    }
304
0
    for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
305
0
        result[i] = NULL;
306
0
    }
307
0
    return result;
308
0
}
309
310
0
static void freeSharedNumberFormatters(const SharedNumberFormat ** list) {
311
0
    for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
312
0
        SharedObject::clearPtr(list[i]);
313
0
    }
314
0
    uprv_free(list);
315
0
}
316
317
const NumberFormat *SimpleDateFormat::getNumberFormatByIndex(
318
0
        UDateFormatField index) const {
319
0
    if (fSharedNumberFormatters == NULL ||
320
0
        fSharedNumberFormatters[index] == NULL) {
321
0
        return fNumberFormat;
322
0
    }
323
0
    return &(**fSharedNumberFormatters[index]);
324
0
}
325
326
//----------------------------------------------------------------------
327
328
SimpleDateFormat::~SimpleDateFormat()
329
0
{
330
0
    delete fSymbols;
331
0
    if (fSharedNumberFormatters) {
332
0
        freeSharedNumberFormatters(fSharedNumberFormatters);
333
0
    }
334
0
    if (fTimeZoneFormat) {
335
0
        delete fTimeZoneFormat;
336
0
    }
337
0
    freeFastNumberFormatters();
338
339
0
#if !UCONFIG_NO_BREAK_ITERATION
340
0
    delete fCapitalizationBrkIter;
341
0
#endif
342
0
}
343
344
//----------------------------------------------------------------------
345
346
SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
347
0
  :   fLocale(Locale::getDefault()),
348
      fSymbols(NULL),
349
      fTimeZoneFormat(NULL),
350
      fSharedNumberFormatters(NULL),
351
      fCapitalizationBrkIter(NULL)
352
0
{
353
0
    initializeBooleanAttributes();
354
0
    construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
355
0
    initializeDefaultCentury();
356
0
}
357
358
//----------------------------------------------------------------------
359
360
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
361
                                   UErrorCode &status)
362
0
:   fPattern(pattern),
363
0
    fLocale(Locale::getDefault()),
364
    fSymbols(NULL),
365
    fTimeZoneFormat(NULL),
366
    fSharedNumberFormatters(NULL),
367
    fCapitalizationBrkIter(NULL)
368
0
{
369
0
    fDateOverride.setToBogus();
370
0
    fTimeOverride.setToBogus();
371
0
    initializeBooleanAttributes();
372
0
    initializeCalendar(NULL,fLocale,status);
373
0
    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
374
0
    initialize(fLocale, status);
375
0
    initializeDefaultCentury();
376
377
0
}
378
//----------------------------------------------------------------------
379
380
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
381
                                   const UnicodeString& override,
382
                                   UErrorCode &status)
383
0
:   fPattern(pattern),
384
0
    fLocale(Locale::getDefault()),
385
    fSymbols(NULL),
386
    fTimeZoneFormat(NULL),
387
    fSharedNumberFormatters(NULL),
388
    fCapitalizationBrkIter(NULL)
389
0
{
390
0
    fDateOverride.setTo(override);
391
0
    fTimeOverride.setToBogus();
392
0
    initializeBooleanAttributes();
393
0
    initializeCalendar(NULL,fLocale,status);
394
0
    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
395
0
    initialize(fLocale, status);
396
0
    initializeDefaultCentury();
397
398
0
    processOverrideString(fLocale,override,kOvrStrBoth,status);
399
400
0
}
401
402
//----------------------------------------------------------------------
403
404
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
405
                                   const Locale& locale,
406
                                   UErrorCode& status)
407
0
:   fPattern(pattern),
408
0
    fLocale(locale),
409
    fTimeZoneFormat(NULL),
410
    fSharedNumberFormatters(NULL),
411
    fCapitalizationBrkIter(NULL)
412
0
{
413
414
0
    fDateOverride.setToBogus();
415
0
    fTimeOverride.setToBogus();
416
0
    initializeBooleanAttributes();
417
418
0
    initializeCalendar(NULL,fLocale,status);
419
0
    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
420
0
    initialize(fLocale, status);
421
0
    initializeDefaultCentury();
422
0
}
423
424
//----------------------------------------------------------------------
425
426
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
427
                                   const UnicodeString& override,
428
                                   const Locale& locale,
429
                                   UErrorCode& status)
430
0
:   fPattern(pattern),
431
0
    fLocale(locale),
432
    fTimeZoneFormat(NULL),
433
    fSharedNumberFormatters(NULL),
434
    fCapitalizationBrkIter(NULL)
435
0
{
436
437
0
    fDateOverride.setTo(override);
438
0
    fTimeOverride.setToBogus();
439
0
    initializeBooleanAttributes();
440
441
0
    initializeCalendar(NULL,fLocale,status);
442
0
    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
443
0
    initialize(fLocale, status);
444
0
    initializeDefaultCentury();
445
446
0
    processOverrideString(locale,override,kOvrStrBoth,status);
447
448
0
}
449
450
//----------------------------------------------------------------------
451
452
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
453
                                   DateFormatSymbols* symbolsToAdopt,
454
                                   UErrorCode& status)
455
0
:   fPattern(pattern),
456
0
    fLocale(Locale::getDefault()),
457
0
    fSymbols(symbolsToAdopt),
458
    fTimeZoneFormat(NULL),
459
    fSharedNumberFormatters(NULL),
460
    fCapitalizationBrkIter(NULL)
461
0
{
462
463
0
    fDateOverride.setToBogus();
464
0
    fTimeOverride.setToBogus();
465
0
    initializeBooleanAttributes();
466
467
0
    initializeCalendar(NULL,fLocale,status);
468
0
    initialize(fLocale, status);
469
0
    initializeDefaultCentury();
470
0
}
471
472
//----------------------------------------------------------------------
473
474
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
475
                                   const DateFormatSymbols& symbols,
476
                                   UErrorCode& status)
477
0
:   fPattern(pattern),
478
0
    fLocale(Locale::getDefault()),
479
0
    fSymbols(new DateFormatSymbols(symbols)),
480
    fTimeZoneFormat(NULL),
481
    fSharedNumberFormatters(NULL),
482
    fCapitalizationBrkIter(NULL)
483
0
{
484
485
0
    fDateOverride.setToBogus();
486
0
    fTimeOverride.setToBogus();
487
0
    initializeBooleanAttributes();
488
489
0
    initializeCalendar(NULL, fLocale, status);
490
0
    initialize(fLocale, status);
491
0
    initializeDefaultCentury();
492
0
}
493
494
//----------------------------------------------------------------------
495
496
// Not for public consumption; used by DateFormat
497
SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
498
                                   EStyle dateStyle,
499
                                   const Locale& locale,
500
                                   UErrorCode& status)
501
0
:   fLocale(locale),
502
    fSymbols(NULL),
503
    fTimeZoneFormat(NULL),
504
    fSharedNumberFormatters(NULL),
505
    fCapitalizationBrkIter(NULL)
506
0
{
507
0
    initializeBooleanAttributes();
508
0
    construct(timeStyle, dateStyle, fLocale, status);
509
0
    if(U_SUCCESS(status)) {
510
0
      initializeDefaultCentury();
511
0
    }
512
0
}
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
 */
521
SimpleDateFormat::SimpleDateFormat(const Locale& locale,
522
                                   UErrorCode& status)
523
0
:   fPattern(gDefaultPattern),
524
0
    fLocale(locale),
525
    fSymbols(NULL),
526
    fTimeZoneFormat(NULL),
527
    fSharedNumberFormatters(NULL),
528
    fCapitalizationBrkIter(NULL)
529
0
{
530
0
    if (U_FAILURE(status)) return;
531
0
    initializeBooleanAttributes();
532
0
    initializeCalendar(NULL, fLocale, status);
533
0
    fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
534
0
    if (U_FAILURE(status))
535
0
    {
536
0
        status = U_ZERO_ERROR;
537
0
        delete fSymbols;
538
        // This constructor doesn't fail; it uses last resort data
539
0
        fSymbols = new DateFormatSymbols(status);
540
        /* test for NULL */
541
0
        if (fSymbols == 0) {
542
0
            status = U_MEMORY_ALLOCATION_ERROR;
543
0
            return;
544
0
        }
545
0
    }
546
547
0
    fDateOverride.setToBogus();
548
0
    fTimeOverride.setToBogus();
549
550
0
    initialize(fLocale, status);
551
0
    if(U_SUCCESS(status)) {
552
0
      initializeDefaultCentury();
553
0
    }
554
0
}
555
556
//----------------------------------------------------------------------
557
558
SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
559
0
:   DateFormat(other),
560
0
    fLocale(other.fLocale),
561
    fSymbols(NULL),
562
    fTimeZoneFormat(NULL),
563
    fSharedNumberFormatters(NULL),
564
    fCapitalizationBrkIter(NULL)
565
0
{
566
0
    initializeBooleanAttributes();
567
0
    *this = other;
568
0
}
569
570
//----------------------------------------------------------------------
571
572
SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
573
0
{
574
0
    if (this == &other) {
575
0
        return *this;
576
0
    }
577
0
    DateFormat::operator=(other);
578
0
    fDateOverride = other.fDateOverride;
579
0
    fTimeOverride = other.fTimeOverride;
580
581
0
    delete fSymbols;
582
0
    fSymbols = NULL;
583
584
0
    if (other.fSymbols)
585
0
        fSymbols = new DateFormatSymbols(*other.fSymbols);
586
587
0
    fDefaultCenturyStart         = other.fDefaultCenturyStart;
588
0
    fDefaultCenturyStartYear     = other.fDefaultCenturyStartYear;
589
0
    fHaveDefaultCentury          = other.fHaveDefaultCentury;
590
591
0
    fPattern = other.fPattern;
592
0
    fHasMinute = other.fHasMinute;
593
0
    fHasSecond = other.fHasSecond;
594
595
0
    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
0
    delete fTimeZoneFormat;
600
0
    fTimeZoneFormat = nullptr;
601
0
    TimeZoneFormat *otherTZFormat;
602
0
    {
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
0
        Mutex m(&LOCK);
617
0
        otherTZFormat = other.fTimeZoneFormat;
618
0
    }
619
0
    if (otherTZFormat) {
620
0
        fTimeZoneFormat = new TimeZoneFormat(*otherTZFormat);
621
0
    }
622
623
0
#if !UCONFIG_NO_BREAK_ITERATION
624
0
    if (other.fCapitalizationBrkIter != NULL) {
625
0
        fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();
626
0
    }
627
0
#endif
628
629
0
    if (fSharedNumberFormatters != NULL) {
630
0
        freeSharedNumberFormatters(fSharedNumberFormatters);
631
0
        fSharedNumberFormatters = NULL;
632
0
    }
633
0
    if (other.fSharedNumberFormatters != NULL) {
634
0
        fSharedNumberFormatters = allocSharedNumberFormatters();
635
0
        if (fSharedNumberFormatters) {
636
0
            for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
637
0
                SharedObject::copyPtr(
638
0
                        other.fSharedNumberFormatters[i],
639
0
                        fSharedNumberFormatters[i]);
640
0
            }
641
0
        }
642
0
    }
643
644
0
    UErrorCode localStatus = U_ZERO_ERROR;
645
0
    freeFastNumberFormatters();
646
0
    initFastNumberFormatters(localStatus);
647
648
0
    return *this;
649
0
}
650
651
//----------------------------------------------------------------------
652
653
SimpleDateFormat*
654
SimpleDateFormat::clone() const
655
0
{
656
0
    return new SimpleDateFormat(*this);
657
0
}
658
659
//----------------------------------------------------------------------
660
661
bool
662
SimpleDateFormat::operator==(const Format& other) const
663
0
{
664
0
    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
0
        SimpleDateFormat* that = (SimpleDateFormat*)&other;
669
0
        return (fPattern             == that->fPattern &&
670
0
                fSymbols             != NULL && // Check for pathological object
671
0
                that->fSymbols       != NULL && // Check for pathological object
672
0
                *fSymbols            == *that->fSymbols &&
673
0
                fHaveDefaultCentury  == that->fHaveDefaultCentury &&
674
0
                fDefaultCenturyStart == that->fDefaultCenturyStart);
675
0
    }
676
0
    return FALSE;
677
0
}
678
679
//----------------------------------------------------------------------
680
static const UChar* timeSkeletons[4] = {
681
    u"jmmsszzzz",   // kFull
682
    u"jmmssz",      // kLong
683
    u"jmmss",       // kMedium
684
    u"jmm",         // kShort
685
};
686
687
void SimpleDateFormat::construct(EStyle timeStyle,
688
                                 EStyle dateStyle,
689
                                 const Locale& locale,
690
                                 UErrorCode& status)
691
0
{
692
    // called by several constructors to load pattern data from the resources
693
0
    if (U_FAILURE(status)) return;
694
695
    // We will need the calendar to know what type of symbols to load.
696
0
    initializeCalendar(NULL, locale, status);
697
0
    if (U_FAILURE(status)) return;
698
699
    // Load date time patterns directly from resources.
700
0
    const char* cType = fCalendar ? fCalendar->getType() : NULL;
701
0
    LocalUResourceBundlePointer bundle(ures_open(NULL, locale.getBaseName(), &status));
702
0
    if (U_FAILURE(status)) return;
703
704
0
    UBool cTypeIsGregorian = TRUE;
705
0
    LocalUResourceBundlePointer dateTimePatterns;
706
0
    if (cType != NULL && uprv_strcmp(cType, "gregorian") != 0) {
707
0
        CharString resourcePath("calendar/", status);
708
0
        resourcePath.append(cType, status).append("/DateTimePatterns", status);
709
0
        dateTimePatterns.adoptInstead(
710
0
            ures_getByKeyWithFallback(bundle.getAlias(), resourcePath.data(),
711
0
                                      (UResourceBundle*)NULL, &status));
712
0
        cTypeIsGregorian = FALSE;
713
0
    }
714
715
    // Check for "gregorian" fallback.
716
0
    if (cTypeIsGregorian || status == U_MISSING_RESOURCE_ERROR) {
717
0
        status = U_ZERO_ERROR;
718
0
        dateTimePatterns.adoptInstead(
719
0
            ures_getByKeyWithFallback(bundle.getAlias(),
720
0
                                      "calendar/gregorian/DateTimePatterns",
721
0
                                      (UResourceBundle*)NULL, &status));
722
0
    }
723
0
    if (U_FAILURE(status)) return;
724
725
0
    LocalUResourceBundlePointer currentBundle;
726
727
0
    if (ures_getSize(dateTimePatterns.getAlias()) <= kDateTime)
728
0
    {
729
0
        status = U_INVALID_FORMAT_ERROR;
730
0
        return;
731
0
    }
732
733
0
    setLocaleIDs(ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_VALID_LOCALE, &status),
734
0
                 ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_ACTUAL_LOCALE, &status));
735
736
    // create a symbols object from the locale
737
0
    fSymbols = DateFormatSymbols::createForLocale(locale, status);
738
0
    if (U_FAILURE(status)) return;
739
    /* test for NULL */
740
0
    if (fSymbols == 0) {
741
0
        status = U_MEMORY_ALLOCATION_ERROR;
742
0
        return;
743
0
    }
744
745
0
    const UChar *resStr,*ovrStr;
746
0
    int32_t resStrLen,ovrStrLen = 0;
747
0
    fDateOverride.setToBogus();
748
0
    fTimeOverride.setToBogus();
749
750
0
    UnicodeString timePattern;
751
0
    if (timeStyle >= kFull && timeStyle <= kShort) {
752
0
        const char* baseLocID = locale.getBaseName();
753
0
        if (baseLocID[0]!=0 && uprv_strcmp(baseLocID,"und")!=0) {
754
0
            UErrorCode useStatus = U_ZERO_ERROR;
755
0
            Locale baseLoc(baseLocID);
756
0
            Locale validLoc(getLocale(ULOC_VALID_LOCALE, useStatus));
757
0
            if (U_SUCCESS(useStatus) && validLoc!=baseLoc) {
758
0
                bool useDTPG = false;
759
0
                const char* baseReg = baseLoc.getCountry(); // empty string if no region
760
0
                if ((baseReg[0]!=0 && uprv_strncmp(baseReg,validLoc.getCountry(),ULOC_COUNTRY_CAPACITY)!=0)
761
0
                        || uprv_strncmp(baseLoc.getLanguage(),validLoc.getLanguage(),ULOC_LANG_CAPACITY)!=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
0
                    useDTPG = true;
766
0
                }
767
0
                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
0
                    LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstanceNoStdPat(locale, useStatus));
778
0
                    if (U_SUCCESS(useStatus)) {
779
0
                        UnicodeString timeSkeleton(TRUE, timeSkeletons[timeStyle], -1);
780
0
                        timePattern = dtpg->getBestPattern(timeSkeleton, useStatus);
781
0
                    }
782
0
                }
783
0
            }
784
0
        }
785
0
    }
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
0
    if ((timeStyle != kNone) && (dateStyle != kNone))
791
0
    {
792
0
        UnicodeString tempus1(timePattern);
793
0
        if (tempus1.length() == 0) {
794
0
            currentBundle.adoptInstead(
795
0
                    ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)timeStyle, NULL, &status));
796
0
            if (U_FAILURE(status)) {
797
0
               status = U_INVALID_FORMAT_ERROR;
798
0
               return;
799
0
            }
800
0
            switch (ures_getType(currentBundle.getAlias())) {
801
0
                case URES_STRING: {
802
0
                   resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
803
0
                   break;
804
0
                }
805
0
                case URES_ARRAY: {
806
0
                   resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
807
0
                   ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
808
0
                   fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen);
809
0
                   break;
810
0
                }
811
0
                default: {
812
0
                   status = U_INVALID_FORMAT_ERROR;
813
0
                   return;
814
0
                }
815
0
            }
816
817
0
            tempus1.setTo(TRUE, resStr, resStrLen);
818
0
        }
819
820
0
        currentBundle.adoptInstead(
821
0
                ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)dateStyle, NULL, &status));
822
0
        if (U_FAILURE(status)) {
823
0
           status = U_INVALID_FORMAT_ERROR;
824
0
           return;
825
0
        }
826
0
        switch (ures_getType(currentBundle.getAlias())) {
827
0
            case URES_STRING: {
828
0
               resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
829
0
               break;
830
0
            }
831
0
            case URES_ARRAY: {
832
0
               resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
833
0
               ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
834
0
               fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
835
0
               break;
836
0
            }
837
0
            default: {
838
0
               status = U_INVALID_FORMAT_ERROR;
839
0
               return;
840
0
            }
841
0
        }
842
843
0
        UnicodeString tempus2(TRUE, resStr, resStrLen);
844
845
0
        int32_t glueIndex = kDateTime;
846
0
        int32_t patternsSize = ures_getSize(dateTimePatterns.getAlias());
847
0
        if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
848
            // Get proper date time format
849
0
            glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset));
850
0
        }
851
852
0
        resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), glueIndex, &resStrLen, &status);
853
0
        SimpleFormatter(UnicodeString(TRUE, resStr, resStrLen), 2, 2, status).
854
0
                format(tempus1, tempus2, fPattern, status);
855
0
    }
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
0
    else if (timeStyle != kNone) {
860
0
        fPattern.setTo(timePattern);
861
0
        if (fPattern.length() == 0) {
862
0
            currentBundle.adoptInstead(
863
0
                    ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)timeStyle, NULL, &status));
864
0
            if (U_FAILURE(status)) {
865
0
               status = U_INVALID_FORMAT_ERROR;
866
0
               return;
867
0
            }
868
0
            switch (ures_getType(currentBundle.getAlias())) {
869
0
                case URES_STRING: {
870
0
                   resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
871
0
                   break;
872
0
                }
873
0
                case URES_ARRAY: {
874
0
                   resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
875
0
                   ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
876
0
                   fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
877
0
                   break;
878
0
                }
879
0
                default: {
880
0
                   status = U_INVALID_FORMAT_ERROR;
881
0
                   return;
882
0
                }
883
0
            }
884
0
            fPattern.setTo(TRUE, resStr, resStrLen);
885
0
        }
886
0
    }
887
0
    else if (dateStyle != kNone) {
888
0
        currentBundle.adoptInstead(
889
0
                ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)dateStyle, NULL, &status));
890
0
        if (U_FAILURE(status)) {
891
0
           status = U_INVALID_FORMAT_ERROR;
892
0
           return;
893
0
        }
894
0
        switch (ures_getType(currentBundle.getAlias())) {
895
0
            case URES_STRING: {
896
0
               resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
897
0
               break;
898
0
            }
899
0
            case URES_ARRAY: {
900
0
               resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
901
0
               ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
902
0
               fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
903
0
               break;
904
0
            }
905
0
            default: {
906
0
               status = U_INVALID_FORMAT_ERROR;
907
0
               return;
908
0
            }
909
0
        }
910
0
        fPattern.setTo(TRUE, resStr, resStrLen);
911
0
    }
912
913
    // and if it includes _neither_, that's an error
914
0
    else
915
0
        status = U_INVALID_FORMAT_ERROR;
916
917
    // finally, finish initializing by creating a Calendar and a NumberFormat
918
0
    initialize(locale, status);
919
0
}
920
921
//----------------------------------------------------------------------
922
923
Calendar*
924
SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)
925
0
{
926
0
    if(!U_FAILURE(status)) {
927
0
        fCalendar = Calendar::createInstance(
928
0
            adoptZone ? adoptZone : TimeZone::forLocaleOrDefault(locale), locale, status);
929
0
    }
930
0
    return fCalendar;
931
0
}
932
933
void
934
SimpleDateFormat::initialize(const Locale& locale,
935
                             UErrorCode& status)
936
0
{
937
0
    if (U_FAILURE(status)) return;
938
939
0
    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
0
    if (fDateOverride.isBogus() && fHasHanYearChar &&
945
0
            fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
946
0
            uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
947
0
        fDateOverride.setTo(u"y=jpanyear", -1);
948
0
    }
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
0
    fNumberFormat = NumberFormat::createInstance(locale, status);
953
0
    if (fNumberFormat != NULL && U_SUCCESS(status))
954
0
    {
955
0
        fixNumberFormatForDates(*fNumberFormat);
956
        //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
957
958
0
        initNumberFormatters(locale, status);
959
0
        initFastNumberFormatters(status);
960
961
0
    }
962
0
    else if (U_SUCCESS(status))
963
0
    {
964
0
        status = U_MISSING_RESOURCE_ERROR;
965
0
    }
966
0
}
967
968
/* Initialize the fields we use to disambiguate ambiguous years. Separate
969
 * so we can call it from readObject().
970
 */
971
void SimpleDateFormat::initializeDefaultCentury()
972
0
{
973
0
  if(fCalendar) {
974
0
    fHaveDefaultCentury = fCalendar->haveDefaultCentury();
975
0
    if(fHaveDefaultCentury) {
976
0
      fDefaultCenturyStart = fCalendar->defaultCenturyStart();
977
0
      fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear();
978
0
    } else {
979
0
      fDefaultCenturyStart = DBL_MIN;
980
0
      fDefaultCenturyStartYear = -1;
981
0
    }
982
0
  }
983
0
}
984
985
/*
986
 * Initialize the boolean attributes. Separate so we can call it from all constructors.
987
 */
988
void SimpleDateFormat::initializeBooleanAttributes()
989
0
{
990
0
    UErrorCode status = U_ZERO_ERROR;
991
992
0
    setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status);
993
0
    setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status);
994
0
    setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, true, status);
995
0
    setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, true, status);
996
0
}
997
998
/* Define one-century window into which to disambiguate dates using
999
 * two-digit years. Make public in JDK 1.2.
1000
 */
1001
void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)
1002
0
{
1003
0
    if(U_FAILURE(status)) {
1004
0
        return;
1005
0
    }
1006
0
    if(!fCalendar) {
1007
0
      status = U_ILLEGAL_ARGUMENT_ERROR;
1008
0
      return;
1009
0
    }
1010
1011
0
    fCalendar->setTime(startDate, status);
1012
0
    if(U_SUCCESS(status)) {
1013
0
        fHaveDefaultCentury = TRUE;
1014
0
        fDefaultCenturyStart = startDate;
1015
0
        fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status);
1016
0
    }
1017
0
}
1018
1019
//----------------------------------------------------------------------
1020
1021
UnicodeString&
1022
SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const
1023
0
{
1024
0
  UErrorCode status = U_ZERO_ERROR;
1025
0
  FieldPositionOnlyHandler handler(pos);
1026
0
  return _format(cal, appendTo, handler, status);
1027
0
}
1028
1029
//----------------------------------------------------------------------
1030
1031
UnicodeString&
1032
SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,
1033
                         FieldPositionIterator* posIter, UErrorCode& status) const
1034
0
{
1035
0
  FieldPositionIteratorHandler handler(posIter, status);
1036
0
  return _format(cal, appendTo, handler, status);
1037
0
}
1038
1039
//----------------------------------------------------------------------
1040
1041
UnicodeString&
1042
SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
1043
                            FieldPositionHandler& handler, UErrorCode& status) const
1044
0
{
1045
0
    if ( U_FAILURE(status) ) {
1046
0
       return appendTo;
1047
0
    }
1048
0
    Calendar* workCal = &cal;
1049
0
    Calendar* calClone = NULL;
1050
0
    if (&cal != fCalendar && uprv_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
0
        calClone = fCalendar->clone();
1055
0
        if (calClone != NULL) {
1056
0
            UDate t = cal.getTime(status);
1057
0
            calClone->setTime(t, status);
1058
0
            calClone->setTimeZone(cal.getTimeZone());
1059
0
            workCal = calClone;
1060
0
        } else {
1061
0
            status = U_MEMORY_ALLOCATION_ERROR;
1062
0
            return appendTo;
1063
0
        }
1064
0
    }
1065
1066
0
    UBool inQuote = FALSE;
1067
0
    UChar prevCh = 0;
1068
0
    int32_t count = 0;
1069
0
    int32_t fieldNum = 0;
1070
0
    UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
1071
1072
    // loop through the pattern string character by character
1073
0
    for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
1074
0
        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
0
        if (ch != prevCh && count > 0) {
1079
0
            subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,
1080
0
                      prevCh, handler, *workCal, status);
1081
0
            count = 0;
1082
0
        }
1083
0
        if (ch == QUOTE) {
1084
            // Consecutive single quotes are a single quote literal,
1085
            // either outside of quotes or between quotes
1086
0
            if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) {
1087
0
                appendTo += (UChar)QUOTE;
1088
0
                ++i;
1089
0
            } else {
1090
0
                inQuote = ! inQuote;
1091
0
            }
1092
0
        }
1093
0
        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
0
            prevCh = ch;
1097
0
            ++count;
1098
0
        }
1099
0
        else {
1100
            // Append quoted characters and unquoted non-pattern characters
1101
0
            appendTo += ch;
1102
0
        }
1103
0
    }
1104
1105
    // Format the last item in the pattern, if any
1106
0
    if (count > 0) {
1107
0
        subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,
1108
0
                  prevCh, handler, *workCal, status);
1109
0
    }
1110
1111
0
    if (calClone != NULL) {
1112
0
        delete calClone;
1113
0
    }
1114
1115
0
    return appendTo;
1116
0
}
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
 */
1126
const int32_t
1127
SimpleDateFormat::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
1139
0
int32_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
0
    static const int32_t mapCharToLevel[] = {
1144
0
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1145
        //
1146
0
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1147
        //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
1148
0
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1149
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
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
0
            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1155
0
#endif
1156
        //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
1157
0
            -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
0
            -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
0
            -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
0
            -1, 20, 10, 70, -1, 10,  0, 20,  0, 10,  0, -1, -1, -1, -1, -1
1164
0
    };
1165
1166
0
    return ch < UPRV_LENGTHOF(mapCharToLevel) ? mapCharToLevel[ch] : -1;
1167
0
}
1168
1169
0
UBool SimpleDateFormat::isSyntaxChar(UChar ch) {
1170
0
    static const UBool mapCharToIsSyntax[] = {
1171
        //
1172
0
        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1173
        //
1174
0
        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1175
        //
1176
0
        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1177
        //
1178
0
        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1179
        //         !      "      #      $      %      &      '
1180
0
        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1181
        //  (      )      *      +      ,      -      .      /
1182
0
        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1183
        //  0      1      2      3      4      5      6      7
1184
0
        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1185
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
1186
        //  8      9      :      ;      <      =      >      ?
1187
        FALSE, FALSE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
1188
#else
1189
        //  8      9      :      ;      <      =      >      ?
1190
0
        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1191
0
#endif
1192
        //  @      A      B      C      D      E      F      G
1193
0
        FALSE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1194
        //  H      I      J      K      L      M      N      O
1195
0
         TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1196
        //  P      Q      R      S      T      U      V      W
1197
0
         TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1198
        //  X      Y      Z      [      \      ]      ^      _
1199
0
         TRUE,  TRUE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
1200
        //  `      a      b      c      d      e      f      g
1201
0
        FALSE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1202
        //  h      i      j      k      l      m      n      o
1203
0
         TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1204
        //  p      q      r      s      t      u      v      w
1205
0
         TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1206
        //  x      y      z      {      |      }      ~
1207
0
         TRUE,  TRUE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE
1208
0
    };
1209
1210
0
    return ch < UPRV_LENGTHOF(mapCharToIsSyntax) ? mapCharToIsSyntax[ch] : FALSE;
1211
0
}
1212
1213
// Map index into pattern character string to Calendar field number.
1214
const UCalendarDateFields
1215
SimpleDateFormat::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_SEPARATOR
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
1244
const UDateFormatField
1245
SimpleDateFormat::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_SEPARATOR
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
 */
1278
static inline void
1279
_appendSymbol(UnicodeString& dst,
1280
              int32_t value,
1281
              const UnicodeString* symbols,
1282
0
              int32_t symbolsCount) {
1283
0
    U_ASSERT(0 <= value && value < symbolsCount);
1284
0
    if (0 <= value && value < symbolsCount) {
1285
0
        dst += symbols[value];
1286
0
    }
1287
0
}
1288
1289
static inline void
1290
_appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount,
1291
0
              const UnicodeString* monthPattern, UErrorCode& status) {
1292
0
    U_ASSERT(0 <= value && value < symbolsCount);
1293
0
    if (0 <= value && value < symbolsCount) {
1294
0
        if (monthPattern == NULL) {
1295
0
            dst += symbols[value];
1296
0
        } else {
1297
0
            SimpleFormatter(*monthPattern, 1, 1, status).format(symbols[value], dst, status);
1298
0
        }
1299
0
    }
1300
0
}
1301
1302
//----------------------------------------------------------------------
1303
1304
static number::LocalizedNumberFormatter*
1305
0
createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt, UErrorCode& status) {
1306
0
    const number::LocalizedNumberFormatter* lnfBase = df->toNumberFormatter(status);
1307
0
    if (U_FAILURE(status)) {
1308
0
        return nullptr;
1309
0
    }
1310
0
    return lnfBase->integerWidth(
1311
0
        number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt)
1312
0
    ).clone().orphan();
1313
0
}
1314
1315
0
void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) {
1316
0
    if (U_FAILURE(status)) {
1317
0
        return;
1318
0
    }
1319
0
    auto* df = dynamic_cast<const DecimalFormat*>(fNumberFormat);
1320
0
    if (df == nullptr) {
1321
0
        return;
1322
0
    }
1323
0
    fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10, status);
1324
0
    fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10, status);
1325
0
    fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10, status);
1326
0
    fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10, status);
1327
0
    fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2, status);
1328
0
}
1329
1330
0
void SimpleDateFormat::freeFastNumberFormatters() {
1331
0
    delete fFastNumberFormatters[SMPDTFMT_NF_1x10];
1332
0
    delete fFastNumberFormatters[SMPDTFMT_NF_2x10];
1333
0
    delete fFastNumberFormatters[SMPDTFMT_NF_3x10];
1334
0
    delete fFastNumberFormatters[SMPDTFMT_NF_4x10];
1335
0
    delete fFastNumberFormatters[SMPDTFMT_NF_2x2];
1336
0
    fFastNumberFormatters[SMPDTFMT_NF_1x10] = nullptr;
1337
0
    fFastNumberFormatters[SMPDTFMT_NF_2x10] = nullptr;
1338
0
    fFastNumberFormatters[SMPDTFMT_NF_3x10] = nullptr;
1339
0
    fFastNumberFormatters[SMPDTFMT_NF_4x10] = nullptr;
1340
0
    fFastNumberFormatters[SMPDTFMT_NF_2x2] = nullptr;
1341
0
}
1342
1343
1344
void
1345
0
SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
1346
0
    if (U_FAILURE(status)) {
1347
0
        return;
1348
0
    }
1349
0
    if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
1350
0
        return;
1351
0
    }
1352
0
    umtx_lock(&LOCK);
1353
0
    if (fSharedNumberFormatters == NULL) {
1354
0
        fSharedNumberFormatters = allocSharedNumberFormatters();
1355
0
        if (fSharedNumberFormatters == NULL) {
1356
0
            status = U_MEMORY_ALLOCATION_ERROR;
1357
0
        }
1358
0
    }
1359
0
    umtx_unlock(&LOCK);
1360
1361
0
    if (U_FAILURE(status)) {
1362
0
        return;
1363
0
    }
1364
1365
0
    processOverrideString(locale,fDateOverride,kOvrStrDate,status);
1366
0
    processOverrideString(locale,fTimeOverride,kOvrStrTime,status);
1367
0
}
1368
1369
void
1370
0
SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) {
1371
0
    if (str.isBogus() || U_FAILURE(status)) {
1372
0
        return;
1373
0
    }
1374
1375
0
    int32_t start = 0;
1376
0
    int32_t len;
1377
0
    UnicodeString nsName;
1378
0
    UnicodeString ovrField;
1379
0
    UBool moreToProcess = TRUE;
1380
0
    NSOverride *overrideList = NULL;
1381
1382
0
    while (moreToProcess) {
1383
0
        int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
1384
0
        if (delimiterPosition == -1) {
1385
0
            moreToProcess = FALSE;
1386
0
            len = str.length() - start;
1387
0
        } else {
1388
0
            len = delimiterPosition - start;
1389
0
        }
1390
0
        UnicodeString currentString(str,start,len);
1391
0
        int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0);
1392
0
        if (equalSignPosition == -1) { // Simple override string such as "hebrew"
1393
0
            nsName.setTo(currentString);
1394
0
            ovrField.setToBogus();
1395
0
        } else { // Field specific override string such as "y=hebrew"
1396
0
            nsName.setTo(currentString,equalSignPosition+1);
1397
0
            ovrField.setTo(currentString,0,1); // We just need the first character.
1398
0
        }
1399
1400
0
        int32_t nsNameHash = nsName.hashCode();
1401
        // See if the numbering system is in the override list, if not, then add it.
1402
0
        NSOverride *curr = overrideList;
1403
0
        const SharedNumberFormat *snf = NULL;
1404
0
        UBool found = FALSE;
1405
0
        while ( curr && !found ) {
1406
0
            if ( curr->hash == nsNameHash ) {
1407
0
                snf = curr->snf;
1408
0
                found = TRUE;
1409
0
            }
1410
0
            curr = curr->next;
1411
0
        }
1412
1413
0
        if (!found) {
1414
0
           LocalPointer<NSOverride> cur(new NSOverride);
1415
0
           if (!cur.isNull()) {
1416
0
               char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
1417
0
               uprv_strcpy(kw,"numbers=");
1418
0
               nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
1419
1420
0
               Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);
1421
0
               cur->hash = nsNameHash;
1422
0
               cur->next = overrideList;
1423
0
               SharedObject::copyPtr(
1424
0
                       createSharedNumberFormat(ovrLoc, status), cur->snf);
1425
0
               if (U_FAILURE(status)) {
1426
0
                   if (overrideList) {
1427
0
                       overrideList->free();
1428
0
                   }
1429
0
                   return;
1430
0
               }
1431
0
               snf = cur->snf;
1432
0
               overrideList = cur.orphan();
1433
0
           } else {
1434
0
               status = U_MEMORY_ALLOCATION_ERROR;
1435
0
               if (overrideList) {
1436
0
                   overrideList->free();
1437
0
               }
1438
0
               return;
1439
0
           }
1440
0
        }
1441
1442
        // Now that we have an appropriate number formatter, fill in the appropriate spaces in the
1443
        // number formatters table.
1444
0
        if (ovrField.isBogus()) {
1445
0
            switch (type) {
1446
0
                case kOvrStrDate:
1447
0
                case kOvrStrBoth: {
1448
0
                    for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
1449
0
                        SharedObject::copyPtr(snf, fSharedNumberFormatters[kDateFields[i]]);
1450
0
                    }
1451
0
                    if (type==kOvrStrDate) {
1452
0
                        break;
1453
0
                    }
1454
0
                    U_FALLTHROUGH;
1455
0
                }
1456
0
                case kOvrStrTime : {
1457
0
                    for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
1458
0
                        SharedObject::copyPtr(snf, fSharedNumberFormatters[kTimeFields[i]]);
1459
0
                    }
1460
0
                    break;
1461
0
                }
1462
0
            }
1463
0
        } else {
1464
           // if the pattern character is unrecognized, signal an error and bail out
1465
0
           UDateFormatField patternCharIndex =
1466
0
              DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0));
1467
0
           if (patternCharIndex == UDAT_FIELD_COUNT) {
1468
0
               status = U_INVALID_FORMAT_ERROR;
1469
0
               if (overrideList) {
1470
0
                   overrideList->free();
1471
0
               }
1472
0
               return;
1473
0
           }
1474
0
           SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
1475
0
        }
1476
1477
0
        start = delimiterPosition + 1;
1478
0
    }
1479
0
    if (overrideList) {
1480
0
        overrideList->free();
1481
0
    }
1482
0
}
1483
1484
//---------------------------------------------------------------------
1485
void
1486
SimpleDateFormat::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
0
{
1496
0
    if (U_FAILURE(status)) {
1497
0
        return;
1498
0
    }
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
0
    UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
1504
0
    const int32_t maxIntCount = 10;
1505
0
    int32_t beginOffset = appendTo.length();
1506
0
    const NumberFormat *currentNumberFormat;
1507
0
    DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;
1508
1509
0
    UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0);
1510
0
    UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);
1511
1512
    // if the pattern character is unrecognized, signal an error and dump out
1513
0
    if (patternCharIndex == UDAT_FIELD_COUNT)
1514
0
    {
1515
0
        if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
1516
0
            status = U_INVALID_FORMAT_ERROR;
1517
0
        }
1518
0
        return;
1519
0
    }
1520
1521
0
    UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
1522
0
    int32_t value = 0;
1523
    // Don't get value unless it is useful
1524
0
    if (field < UCAL_FIELD_COUNT) {
1525
0
        value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status);
1526
0
    }
1527
0
    if (U_FAILURE(status)) {
1528
0
        return;
1529
0
    }
1530
1531
0
    currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
1532
0
    if (currentNumberFormat == NULL) {
1533
0
        status = U_INTERNAL_PROGRAM_ERROR;
1534
0
        return;
1535
0
    }
1536
0
    UnicodeString hebr("hebr", 4, US_INV);
1537
1538
0
    switch (patternCharIndex) {
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
0
    case UDAT_ERA_FIELD:
1543
0
        if (isChineseCalendar) {
1544
0
            zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J
1545
0
        } else {
1546
0
            if (count == 5) {
1547
0
                _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
1548
0
                capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow;
1549
0
            } else if (count == 4) {
1550
0
                _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
1551
0
                capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide;
1552
0
            } else {
1553
0
                _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
1554
0
                capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev;
1555
0
            }
1556
0
        }
1557
0
        break;
1558
1559
0
     case UDAT_YEAR_NAME_FIELD:
1560
0
        if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) {
1561
            // the Calendar YEAR field runs 1 through 60 for cyclic years
1562
0
            _appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount);
1563
0
            break;
1564
0
        }
1565
        // else fall through to numeric year handling, do not break here
1566
0
        U_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
0
    case UDAT_YEAR_FIELD:
1577
0
    case UDAT_YEAR_WOY_FIELD:
1578
0
        if (fDateOverride.compare(hebr)==0 && value>HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value<HEBREW_CAL_CUR_MILLENIUM_END_YEAR) {
1579
0
            value-=HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
1580
0
        }
1581
0
        if(count == 2)
1582
0
            zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2);
1583
0
        else
1584
0
            zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount);
1585
0
        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
0
    case UDAT_MONTH_FIELD:
1592
0
    case UDAT_STANDALONE_MONTH_FIELD:
1593
0
        if ( isHebrewCalendar ) {
1594
0
           HebrewCalendar *hc = (HebrewCalendar*)&cal;
1595
0
           if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
1596
0
               value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
1597
0
           if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
1598
0
               value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
1599
0
        }
1600
0
        {
1601
0
            int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)?
1602
0
                        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
0
            if (count == 5) {
1605
0
                if (patternCharIndex == UDAT_MONTH_FIELD) {
1606
0
                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount,
1607
0
                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): NULL, status);
1608
0
                } else {
1609
0
                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount,
1610
0
                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): NULL, status);
1611
0
                }
1612
0
                capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow;
1613
0
            } else if (count == 4) {
1614
0
                if (patternCharIndex == UDAT_MONTH_FIELD) {
1615
0
                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount,
1616
0
                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): NULL, status);
1617
0
                    capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
1618
0
                } else {
1619
0
                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount,
1620
0
                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): NULL, status);
1621
0
                    capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
1622
0
                }
1623
0
            } else if (count == 3) {
1624
0
                if (patternCharIndex == UDAT_MONTH_FIELD) {
1625
0
                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount,
1626
0
                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): NULL, status);
1627
0
                    capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
1628
0
                } else {
1629
0
                    _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount,
1630
0
                            (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): NULL, status);
1631
0
                    capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
1632
0
                }
1633
0
            } else {
1634
0
                UnicodeString monthNumber;
1635
0
                zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount);
1636
0
                _appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1,
1637
0
                        (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): NULL, status);
1638
0
            }
1639
0
        }
1640
0
        break;
1641
1642
    // for "k" and "kk", write out the hour, adjusting midnight to appear as "24"
1643
0
    case UDAT_HOUR_OF_DAY1_FIELD:
1644
0
        if (value == 0)
1645
0
            zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
1646
0
        else
1647
0
            zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1648
0
        break;
1649
1650
0
    case UDAT_FRACTIONAL_SECOND_FIELD:
1651
        // Fractional seconds left-justify
1652
0
        {
1653
0
            int32_t minDigits = (count > 3) ? 3 : count;
1654
0
            if (count == 1) {
1655
0
                value /= 100;
1656
0
            } else if (count == 2) {
1657
0
                value /= 10;
1658
0
            }
1659
0
            zeroPaddingNumber(currentNumberFormat, appendTo, value, minDigits, maxIntCount);
1660
0
            if (count > 3) {
1661
0
                zeroPaddingNumber(currentNumberFormat, appendTo, 0, count - 3, maxIntCount);
1662
0
            }
1663
0
        }
1664
0
        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
0
    case UDAT_DOW_LOCAL_FIELD:
1672
0
        if ( count < 3 ) {
1673
0
            zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1674
0
            break;
1675
0
        }
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
0
        value = cal.get(UCAL_DAY_OF_WEEK, status);
1679
0
        if (U_FAILURE(status)) {
1680
0
            return;
1681
0
        }
1682
        // fall through, do not break here
1683
0
        U_FALLTHROUGH;
1684
0
    case UDAT_DAY_OF_WEEK_FIELD:
1685
0
        if (count == 5) {
1686
0
            _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
1687
0
                          fSymbols->fNarrowWeekdaysCount);
1688
0
            capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
1689
0
        } else if (count == 4) {
1690
0
            _appendSymbol(appendTo, value, fSymbols->fWeekdays,
1691
0
                          fSymbols->fWeekdaysCount);
1692
0
            capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
1693
0
        } else if (count == 6) {
1694
0
            _appendSymbol(appendTo, value, fSymbols->fShorterWeekdays,
1695
0
                          fSymbols->fShorterWeekdaysCount);
1696
0
            capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
1697
0
        } else {
1698
0
            _appendSymbol(appendTo, value, fSymbols->fShortWeekdays,
1699
0
                          fSymbols->fShortWeekdaysCount);
1700
0
            capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
1701
0
        }
1702
0
        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
0
    case UDAT_STANDALONE_DAY_FIELD:
1709
0
        if ( count < 3 ) {
1710
0
            zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount);
1711
0
            break;
1712
0
        }
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
0
        value = cal.get(UCAL_DAY_OF_WEEK, status);
1716
0
        if (U_FAILURE(status)) {
1717
0
            return;
1718
0
        }
1719
0
        if (count == 5) {
1720
0
            _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,
1721
0
                          fSymbols->fStandaloneNarrowWeekdaysCount);
1722
0
            capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
1723
0
        } else if (count == 4) {
1724
0
            _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
1725
0
                          fSymbols->fStandaloneWeekdaysCount);
1726
0
            capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
1727
0
        } else if (count == 6) {
1728
0
            _appendSymbol(appendTo, value, fSymbols->fStandaloneShorterWeekdays,
1729
0
                          fSymbols->fStandaloneShorterWeekdaysCount);
1730
0
            capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
1731
0
        } else { // count == 3
1732
0
            _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,
1733
0
                          fSymbols->fStandaloneShortWeekdaysCount);
1734
0
            capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
1735
0
        }
1736
0
        break;
1737
1738
    // for "a" symbol, write out the whole AM/PM string
1739
0
    case UDAT_AM_PM_FIELD:
1740
0
        if (count < 5) {
1741
0
            _appendSymbol(appendTo, value, fSymbols->fAmPms,
1742
0
                          fSymbols->fAmPmsCount);
1743
0
        } else {
1744
0
            _appendSymbol(appendTo, value, fSymbols->fNarrowAmPms,
1745
0
                          fSymbols->fNarrowAmPmsCount);
1746
0
        }
1747
0
        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
0
    case UDAT_TIME_SEPARATOR_FIELD:
1752
0
        {
1753
0
            UnicodeString separator;
1754
0
            appendTo += fSymbols->getTimeSeparatorString(separator);
1755
0
        }
1756
0
        break;
1757
1758
    // for "h" and "hh", write out the hour, adjusting noon and midnight to show up
1759
    // as "12"
1760
0
    case UDAT_HOUR1_FIELD:
1761
0
        if (value == 0)
1762
0
            zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
1763
0
        else
1764
0
            zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1765
0
        break;
1766
1767
0
    case UDAT_TIMEZONE_FIELD: // 'z'
1768
0
    case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
1769
0
    case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
1770
0
    case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
1771
0
    case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
1772
0
    case UDAT_TIMEZONE_ISO_FIELD: // 'X'
1773
0
    case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
1774
0
        {
1775
0
            UChar zsbuf[ZONE_NAME_U16_MAX];
1776
0
            UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf));
1777
0
            const TimeZone& tz = cal.getTimeZone();
1778
0
            UDate date = cal.getTime(status);
1779
0
            const TimeZoneFormat *tzfmt = tzFormat(status);
1780
0
            if (U_SUCCESS(status)) {
1781
0
                if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
1782
0
                    if (count < 4) {
1783
                        // "z", "zz", "zzz"
1784
0
                        tzfmt->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
1785
0
                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
1786
0
                    } else {
1787
                        // "zzzz" or longer
1788
0
                        tzfmt->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
1789
0
                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
1790
0
                    }
1791
0
                }
1792
0
                else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) {
1793
0
                    if (count < 4) {
1794
                        // "Z"
1795
0
                        tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
1796
0
                    } else if (count == 5) {
1797
                        // "ZZZZZ"
1798
0
                        tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
1799
0
                    } else {
1800
                        // "ZZ", "ZZZ", "ZZZZ"
1801
0
                        tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
1802
0
                    }
1803
0
                }
1804
0
                else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
1805
0
                    if (count == 1) {
1806
                        // "v"
1807
0
                        tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
1808
0
                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
1809
0
                    } else if (count == 4) {
1810
                        // "vvvv"
1811
0
                        tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
1812
0
                        capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
1813
0
                    }
1814
0
                }
1815
0
                else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) {
1816
0
                    if (count == 1) {
1817
                        // "V"
1818
0
                        tzfmt->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
1819
0
                    } else if (count == 2) {
1820
                        // "VV"
1821
0
                        tzfmt->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
1822
0
                    } else if (count == 3) {
1823
                        // "VVV"
1824
0
                        tzfmt->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
1825
0
                    } else if (count == 4) {
1826
                        // "VVVV"
1827
0
                        tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
1828
0
                        capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;
1829
0
                    }
1830
0
                }
1831
0
                else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) {
1832
0
                    if (count == 1) {
1833
                        // "O"
1834
0
                        tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
1835
0
                    } else if (count == 4) {
1836
                        // "OOOO"
1837
0
                        tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
1838
0
                    }
1839
0
                }
1840
0
                else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) {
1841
0
                    if (count == 1) {
1842
                        // "X"
1843
0
                        tzfmt->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
1844
0
                    } else if (count == 2) {
1845
                        // "XX"
1846
0
                        tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
1847
0
                    } else if (count == 3) {
1848
                        // "XXX"
1849
0
                        tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
1850
0
                    } else if (count == 4) {
1851
                        // "XXXX"
1852
0
                        tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
1853
0
                    } else if (count == 5) {
1854
                        // "XXXXX"
1855
0
                        tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
1856
0
                    }
1857
0
                }
1858
0
                else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) {
1859
0
                    if (count == 1) {
1860
                        // "x"
1861
0
                        tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString);
1862
0
                    } else if (count == 2) {
1863
                        // "xx"
1864
0
                        tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString);
1865
0
                    } else if (count == 3) {
1866
                        // "xxx"
1867
0
                        tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString);
1868
0
                    } else if (count == 4) {
1869
                        // "xxxx"
1870
0
                        tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
1871
0
                    } else if (count == 5) {
1872
                        // "xxxxx"
1873
0
                        tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
1874
0
                    }
1875
0
                }
1876
0
                else {
1877
0
                    UPRV_UNREACHABLE;
1878
0
                }
1879
0
            }
1880
0
            appendTo += zoneString;
1881
0
        }
1882
0
        break;
1883
1884
0
    case UDAT_QUARTER_FIELD:
1885
0
        if (count >= 5)
1886
0
            _appendSymbol(appendTo, value/3, fSymbols->fNarrowQuarters,
1887
0
                          fSymbols->fNarrowQuartersCount);
1888
0
         else if (count == 4)
1889
0
            _appendSymbol(appendTo, value/3, fSymbols->fQuarters,
1890
0
                          fSymbols->fQuartersCount);
1891
0
        else if (count == 3)
1892
0
            _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters,
1893
0
                          fSymbols->fShortQuartersCount);
1894
0
        else
1895
0
            zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
1896
0
        break;
1897
1898
0
    case UDAT_STANDALONE_QUARTER_FIELD:
1899
0
        if (count >= 5)
1900
0
            _appendSymbol(appendTo, value/3, fSymbols->fStandaloneNarrowQuarters,
1901
0
                          fSymbols->fStandaloneNarrowQuartersCount);
1902
0
        else if (count == 4)
1903
0
            _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,
1904
0
                          fSymbols->fStandaloneQuartersCount);
1905
0
        else if (count == 3)
1906
0
            _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters,
1907
0
                          fSymbols->fStandaloneShortQuartersCount);
1908
0
        else
1909
0
            zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
1910
0
        break;
1911
1912
0
    case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
1913
0
    {
1914
0
        const UnicodeString *toAppend = NULL;
1915
0
        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
0
        if ((/*hour == 0 ||*/ hour == 12) &&
1924
0
                (!fHasMinute || cal.get(UCAL_MINUTE, status) == 0) &&
1925
0
                (!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
0
            int32_t val = cal.get(UCAL_AM_PM, status);
1930
1931
0
            if (count <= 3) {
1932
0
                toAppend = &fSymbols->fAbbreviatedDayPeriods[val];
1933
0
            } else if (count == 4 || count > 5) {
1934
0
                toAppend = &fSymbols->fWideDayPeriods[val];
1935
0
            } else { // count == 5
1936
0
                toAppend = &fSymbols->fNarrowDayPeriods[val];
1937
0
            }
1938
0
        }
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
0
        if (toAppend == 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
0
            subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'b', handler, cal, status);
1949
0
            return;
1950
0
        } else {
1951
0
            appendTo += *toAppend;
1952
0
        }
1953
1954
0
        break;
1955
0
    }
1956
1957
0
    case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
1958
0
    {
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
0
        const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
1962
0
        if (U_FAILURE(status)) {
1963
            // Data doesn't conform to spec, therefore loading failed.
1964
0
            break;
1965
0
        }
1966
0
        if (ruleSet == NULL) {
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
0
            subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'B', handler, cal, status);
1973
0
            return;
1974
0
        }
1975
1976
        // Get current display time.
1977
0
        int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
1978
0
        int32_t minute = 0;
1979
0
        if (fHasMinute) {
1980
0
            minute = cal.get(UCAL_MINUTE, status);
1981
0
        }
1982
0
        int32_t second = 0;
1983
0
        if (fHasSecond) {
1984
0
            second = cal.get(UCAL_SECOND, status);
1985
0
        }
1986
1987
        // Determine day period.
1988
0
        DayPeriodRules::DayPeriod periodType;
1989
0
        if (hour == 0 && minute == 0 && second == 0 && ruleSet->hasMidnight()) {
1990
0
            periodType = DayPeriodRules::DAYPERIOD_MIDNIGHT;
1991
0
        } else if (hour == 12 && minute == 0 && second == 0 && ruleSet->hasNoon()) {
1992
0
            periodType = DayPeriodRules::DAYPERIOD_NOON;
1993
0
        } else {
1994
0
            periodType = ruleSet->getDayPeriodForHour(hour);
1995
0
        }
1996
1997
        // Rule set exists, therefore periodType can't be UNKNOWN.
1998
        // Get localized string.
1999
0
        U_ASSERT(periodType != DayPeriodRules::DAYPERIOD_UNKNOWN);
2000
0
        UnicodeString *toAppend = NULL;
2001
0
        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
0
        if (periodType != DayPeriodRules::DAYPERIOD_AM &&
2007
0
                periodType != DayPeriodRules::DAYPERIOD_PM &&
2008
0
                periodType != DayPeriodRules::DAYPERIOD_MIDNIGHT) {
2009
0
            index = (int32_t)periodType;
2010
0
            if (count <= 3) {
2011
0
                toAppend = &fSymbols->fAbbreviatedDayPeriods[index];  // i.e. short
2012
0
            } else if (count == 4 || count > 5) {
2013
0
                toAppend = &fSymbols->fWideDayPeriods[index];
2014
0
            } else {  // count == 5
2015
0
                toAppend = &fSymbols->fNarrowDayPeriods[index];
2016
0
            }
2017
0
        }
2018
2019
        // Fallback schedule:
2020
        // Midnight/Noon -> General Periods -> AM/PM.
2021
2022
        // Midnight/Noon -> General Periods.
2023
0
        if ((toAppend == NULL || toAppend->isBogus()) &&
2024
0
                (periodType == DayPeriodRules::DAYPERIOD_MIDNIGHT ||
2025
0
                 periodType == DayPeriodRules::DAYPERIOD_NOON)) {
2026
0
            periodType = ruleSet->getDayPeriodForHour(hour);
2027
0
            index = (int32_t)periodType;
2028
2029
0
            if (count <= 3) {
2030
0
                toAppend = &fSymbols->fAbbreviatedDayPeriods[index];  // i.e. short
2031
0
            } else if (count == 4 || count > 5) {
2032
0
                toAppend = &fSymbols->fWideDayPeriods[index];
2033
0
            } else {  // count == 5
2034
0
                toAppend = &fSymbols->fNarrowDayPeriods[index];
2035
0
            }
2036
0
        }
2037
2038
        // General Periods -> AM/PM.
2039
0
        if (periodType == DayPeriodRules::DAYPERIOD_AM ||
2040
0
            periodType == DayPeriodRules::DAYPERIOD_PM ||
2041
0
            toAppend->isBogus()) {
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
0
            subFormat(appendTo, u'a', count, capitalizationContext, fieldNum, u'B', handler, cal, status);
2046
0
            return;
2047
0
        }
2048
0
        else {
2049
0
            appendTo += *toAppend;
2050
0
        }
2051
2052
0
        break;
2053
0
    }
2054
2055
    // all of the other pattern symbols can be formatted as simple numbers with
2056
    // appropriate zero padding
2057
0
    default:
2058
0
        zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
2059
0
        break;
2060
0
    }
2061
0
#if !UCONFIG_NO_BREAK_ITERATION
2062
    // if first field, check to see whether we need to and are able to titlecase it
2063
0
    if (fieldNum == 0 && fCapitalizationBrkIter != NULL && appendTo.length() > beginOffset &&
2064
0
            u_islower(appendTo.char32At(beginOffset))) {
2065
0
        UBool titlecase = FALSE;
2066
0
        switch (capitalizationContext) {
2067
0
            case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
2068
0
                titlecase = TRUE;
2069
0
                break;
2070
0
            case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU:
2071
0
                titlecase = fSymbols->fCapitalization[capContextUsageType][0];
2072
0
                break;
2073
0
            case UDISPCTX_CAPITALIZATION_FOR_STANDALONE:
2074
0
                titlecase = fSymbols->fCapitalization[capContextUsageType][1];
2075
0
                break;
2076
0
            default:
2077
                // titlecase = FALSE;
2078
0
                break;
2079
0
        }
2080
0
        if (titlecase) {
2081
0
            BreakIterator* const mutableCapitalizationBrkIter = fCapitalizationBrkIter->clone();
2082
0
            UnicodeString firstField(appendTo, beginOffset);
2083
0
            firstField.toTitle(mutableCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
2084
0
            appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);
2085
0
            delete mutableCapitalizationBrkIter;
2086
0
        }
2087
0
    }
2088
0
#endif
2089
2090
0
    handler.addAttribute(DateFormatSymbols::getPatternCharIndex(fieldToOutput), beginOffset, appendTo.length());
2091
0
}
2092
2093
//----------------------------------------------------------------------
2094
2095
0
void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
2096
0
    fixNumberFormatForDates(*formatToAdopt);
2097
0
    delete fNumberFormat;
2098
0
    fNumberFormat = formatToAdopt;
2099
2100
    // We successfully set the default number format. Now delete the overrides
2101
    // (can't fail).
2102
0
    if (fSharedNumberFormatters) {
2103
0
        freeSharedNumberFormatters(fSharedNumberFormatters);
2104
0
        fSharedNumberFormatters = NULL;
2105
0
    }
2106
2107
    // Also re-compute the fast formatters.
2108
0
    UErrorCode localStatus = U_ZERO_ERROR;
2109
0
    freeFastNumberFormatters();
2110
0
    initFastNumberFormatters(localStatus);
2111
0
}
2112
2113
0
void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){
2114
0
    fixNumberFormatForDates(*formatToAdopt);
2115
0
    LocalPointer<NumberFormat> fmt(formatToAdopt);
2116
0
    if (U_FAILURE(status)) {
2117
0
        return;
2118
0
    }
2119
2120
    // We must ensure fSharedNumberFormatters is allocated.
2121
0
    if (fSharedNumberFormatters == NULL) {
2122
0
        fSharedNumberFormatters = allocSharedNumberFormatters();
2123
0
        if (fSharedNumberFormatters == NULL) {
2124
0
            status = U_MEMORY_ALLOCATION_ERROR;
2125
0
            return;
2126
0
        }
2127
0
    }
2128
0
    const SharedNumberFormat *newFormat = createSharedNumberFormat(fmt.orphan());
2129
0
    if (newFormat == NULL) {
2130
0
        status = U_MEMORY_ALLOCATION_ERROR;
2131
0
        return;
2132
0
    }
2133
0
    for (int i=0; i<fields.length(); i++) {
2134
0
        UChar field = fields.charAt(i);
2135
        // if the pattern character is unrecognized, signal an error and bail out
2136
0
        UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(field);
2137
0
        if (patternCharIndex == UDAT_FIELD_COUNT) {
2138
0
            status = U_INVALID_FORMAT_ERROR;
2139
0
            newFormat->deleteIfZeroRefCount();
2140
0
            return;
2141
0
        }
2142
2143
        // Set the number formatter in the table
2144
0
        SharedObject::copyPtr(
2145
0
                newFormat, fSharedNumberFormatters[patternCharIndex]);
2146
0
    }
2147
0
    newFormat->deleteIfZeroRefCount();
2148
0
}
2149
2150
const NumberFormat *
2151
0
SimpleDateFormat::getNumberFormatForField(UChar field) const {
2152
0
    UDateFormatField index = DateFormatSymbols::getPatternCharIndex(field);
2153
0
    if (index == UDAT_FIELD_COUNT) {
2154
0
        return NULL;
2155
0
    }
2156
0
    return getNumberFormatByIndex(index);
2157
0
}
2158
2159
//----------------------------------------------------------------------
2160
void
2161
SimpleDateFormat::zeroPaddingNumber(
2162
        const NumberFormat *currentNumberFormat,
2163
        UnicodeString &appendTo,
2164
        int32_t value, int32_t minDigits, int32_t maxDigits) const
2165
0
{
2166
0
    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
0
    if (currentNumberFormat == fNumberFormat) {
2170
0
        if (maxDigits == 10) {
2171
0
            if (minDigits == 1) {
2172
0
                fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_1x10];
2173
0
            } else if (minDigits == 2) {
2174
0
                fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x10];
2175
0
            } else if (minDigits == 3) {
2176
0
                fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_3x10];
2177
0
            } else if (minDigits == 4) {
2178
0
                fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_4x10];
2179
0
            }
2180
0
        } else if (maxDigits == 2) {
2181
0
            if (minDigits == 2) {
2182
0
                fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x2];
2183
0
            }
2184
0
        }
2185
0
    }
2186
0
    if (fastFormatter != nullptr) {
2187
        // Can use fast path
2188
0
        number::impl::UFormattedNumberData result;
2189
0
        result.quantity.setToInt(value);
2190
0
        UErrorCode localStatus = U_ZERO_ERROR;
2191
0
        fastFormatter->formatImpl(&result, localStatus);
2192
0
        if (U_FAILURE(localStatus)) {
2193
0
            return;
2194
0
        }
2195
0
        appendTo.append(result.getStringRef().toTempUnicodeString());
2196
0
        return;
2197
0
    }
2198
2199
    // Check for RBNF (no clone necessary)
2200
0
    auto* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(currentNumberFormat);
2201
0
    if (rbnf != nullptr) {
2202
0
        FieldPosition pos(FieldPosition::DONT_CARE);
2203
0
        rbnf->format(value, appendTo, pos);  // 3rd arg is there to speed up processing
2204
0
        return;
2205
0
    }
2206
2207
    // Fall back to slow path (clone and mutate the NumberFormat)
2208
0
    if (currentNumberFormat != nullptr) {
2209
0
        FieldPosition pos(FieldPosition::DONT_CARE);
2210
0
        LocalPointer<NumberFormat> nf(currentNumberFormat->clone());
2211
0
        nf->setMinimumIntegerDigits(minDigits);
2212
0
        nf->setMaximumIntegerDigits(maxDigits);
2213
0
        nf->format(value, appendTo, pos);  // 3rd arg is there to speed up processing
2214
0
    }
2215
0
}
2216
2217
//----------------------------------------------------------------------
2218
2219
/**
2220
 * Return true if the given format character, occurring count
2221
 * times, represents a numeric field.
2222
 */
2223
0
UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) {
2224
0
    return DateFormatSymbols::isNumericPatternChar(formatChar, count);
2225
0
}
2226
2227
UBool
2228
0
SimpleDateFormat::isAtNumericField(const UnicodeString &pattern, int32_t patternOffset) {
2229
0
    if (patternOffset >= pattern.length()) {
2230
        // not at any field
2231
0
        return FALSE;
2232
0
    }
2233
0
    UChar ch = pattern.charAt(patternOffset);
2234
0
    UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
2235
0
    if (f == UDAT_FIELD_COUNT) {
2236
        // not at any field
2237
0
        return FALSE;
2238
0
    }
2239
0
    int32_t i = patternOffset;
2240
0
    while (pattern.charAt(++i) == ch) {}
2241
0
    return DateFormatSymbols::isNumericField(f, i - patternOffset);
2242
0
}
2243
2244
UBool
2245
0
SimpleDateFormat::isAfterNonNumericField(const UnicodeString &pattern, int32_t patternOffset) {
2246
0
    if (patternOffset <= 0) {
2247
        // not after any field
2248
0
        return FALSE;
2249
0
    }
2250
0
    UChar ch = pattern.charAt(--patternOffset);
2251
0
    UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
2252
0
    if (f == UDAT_FIELD_COUNT) {
2253
        // not after any field
2254
0
        return FALSE;
2255
0
    }
2256
0
    int32_t i = patternOffset;
2257
0
    while (pattern.charAt(--i) == ch) {}
2258
0
    return !DateFormatSymbols::isNumericField(f, patternOffset - i);
2259
0
}
2260
2261
void
2262
SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const
2263
0
{
2264
0
    UErrorCode status = U_ZERO_ERROR;
2265
0
    int32_t pos = parsePos.getIndex();
2266
0
    if(parsePos.getIndex() < 0) {
2267
0
        parsePos.setErrorIndex(0);
2268
0
        return;
2269
0
    }
2270
0
    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
0
    int32_t dayPeriodInt = -1;
2275
2276
0
    UBool ambiguousYear[] = { FALSE };
2277
0
    int32_t saveHebrewMonth = -1;
2278
0
    int32_t count = 0;
2279
0
    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
0
    int32_t abutPat = -1; // If >=0, we are in a run of abutting numeric fields
2287
0
    int32_t abutStart = 0;
2288
0
    int32_t abutPass = 0;
2289
0
    UBool inQuote = FALSE;
2290
2291
0
    MessageFormat * numericLeapMonthFormatter = NULL;
2292
2293
0
    Calendar* calClone = NULL;
2294
0
    Calendar *workCal = &cal;
2295
0
    if (&cal != fCalendar && uprv_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
0
        calClone = fCalendar->clone();
2300
0
        if (calClone != NULL) {
2301
0
            calClone->setTime(cal.getTime(status),status);
2302
0
            if (U_FAILURE(status)) {
2303
0
                goto ExitParse;
2304
0
            }
2305
0
            calClone->setTimeZone(cal.getTimeZone());
2306
0
            workCal = calClone;
2307
0
        } else {
2308
0
            status = U_MEMORY_ALLOCATION_ERROR;
2309
0
            goto ExitParse;
2310
0
        }
2311
0
    }
2312
2313
0
    if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
2314
0
        numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status);
2315
0
        if (numericLeapMonthFormatter == NULL) {
2316
0
             status = U_MEMORY_ALLOCATION_ERROR;
2317
0
             goto ExitParse;
2318
0
        } else if (U_FAILURE(status)) {
2319
0
             goto ExitParse; // this will delete numericLeapMonthFormatter
2320
0
        }
2321
0
    }
2322
2323
0
    for (int32_t i=0; i<fPattern.length(); ++i) {
2324
0
        UChar ch = fPattern.charAt(i);
2325
2326
        // Handle alphabetic field characters.
2327
0
        if (!inQuote && isSyntaxChar(ch)) {
2328
0
            int32_t fieldPat = i;
2329
2330
            // Count the length of this field specifier
2331
0
            count = 1;
2332
0
            while ((i+1)<fPattern.length() &&
2333
0
                   fPattern.charAt(i+1) == ch) {
2334
0
                ++count;
2335
0
                ++i;
2336
0
            }
2337
2338
0
            if (isNumeric(ch, count)) {
2339
0
                if (abutPat < 0) {
2340
                    // Determine if there is an abutting numeric field.
2341
                    // Record the start of a set of abutting numeric fields.
2342
0
                    if (isAtNumericField(fPattern, i + 1)) {
2343
0
                        abutPat = fieldPat;
2344
0
                        abutStart = pos;
2345
0
                        abutPass = 0;
2346
0
                    }
2347
0
                }
2348
0
            } else {
2349
0
                abutPat = -1; // End of any abutting fields
2350
0
            }
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
0
            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
0
                if (fieldPat == abutPat) {
2365
0
                    count -= abutPass++;
2366
0
                    if (count == 0) {
2367
0
                        status = U_PARSE_ERROR;
2368
0
                        goto ExitParse;
2369
0
                    }
2370
0
                }
2371
2372
0
                pos = subParse(text, pos, ch, count,
2373
0
                               TRUE, FALSE, 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
0
                if (pos < 0) {
2378
0
                    i = abutPat - 1;
2379
0
                    pos = abutStart;
2380
0
                    continue;
2381
0
                }
2382
0
            }
2383
2384
            // Handle non-numeric fields and non-abutting numeric
2385
            // fields.
2386
0
            else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
2387
0
                int32_t s = subParse(text, pos, ch, count,
2388
0
                               FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, &dayPeriodInt);
2389
2390
0
                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
0
                    s = pos;
2394
2395
0
                    if (i+1 < fPattern.length()) {
2396
                        // move to next pattern character
2397
0
                        UChar c = fPattern.charAt(i+1);
2398
2399
                        // check for whitespace
2400
0
                        if (PatternProps::isWhiteSpace(c)) {
2401
0
                            i++;
2402
                            // Advance over run in pattern
2403
0
                            while ((i+1)<fPattern.length() &&
2404
0
                                   PatternProps::isWhiteSpace(fPattern.charAt(i+1))) {
2405
0
                                ++i;
2406
0
                            }
2407
0
                        }
2408
0
                    }
2409
0
                }
2410
0
                else if (s <= 0) {
2411
0
                    status = U_PARSE_ERROR;
2412
0
                    goto ExitParse;
2413
0
                }
2414
0
                pos = s;
2415
0
            }
2416
0
        }
2417
2418
        // Handle literal pattern characters.  These are any
2419
        // quoted characters and non-alphabetic unquoted
2420
        // characters.
2421
0
        else {
2422
2423
0
            abutPat = -1; // End of any abutting fields
2424
2425
0
            if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status), isLenient())) {
2426
0
                status = U_PARSE_ERROR;
2427
0
                goto ExitParse;
2428
0
            }
2429
0
        }
2430
0
    }
2431
2432
    // Special hack for trailing "." after non-numeric field.
2433
0
    if (text.charAt(pos) == 0x2e && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) {
2434
        // only do if the last field is not numeric
2435
0
        if (isAfterNonNumericField(fPattern, fPattern.length())) {
2436
0
            pos++; // skip the extra "."
2437
0
        }
2438
0
    }
2439
2440
    // If dayPeriod is set, use it in conjunction with hour-of-day to determine am/pm.
2441
0
    if (dayPeriodInt >= 0) {
2442
0
        DayPeriodRules::DayPeriod dayPeriod = (DayPeriodRules::DayPeriod)dayPeriodInt;
2443
0
        const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
2444
2445
0
        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
0
            double midPoint = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
2449
2450
            // If we can't get midPoint we do nothing.
2451
0
            if (U_SUCCESS(status)) {
2452
                // Truncate midPoint toward zero to get the hour.
2453
                // Any leftover means it was a half-hour.
2454
0
                int32_t midPointHour = (int32_t) midPoint;
2455
0
                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
0
                cal.set(UCAL_HOUR_OF_DAY, midPointHour);
2459
0
                cal.set(UCAL_MINUTE, midPointMinute);
2460
0
            }
2461
0
        } else {
2462
0
            int hourOfDay;
2463
2464
0
            if (cal.isSet(UCAL_HOUR_OF_DAY)) {  // Hour is parsed in 24-hour format.
2465
0
                hourOfDay = cal.get(UCAL_HOUR_OF_DAY, status);
2466
0
            } else {  // Hour is parsed in 12-hour format.
2467
0
                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
0
                if (hourOfDay == 0) { hourOfDay = 12; }
2471
0
            }
2472
0
            U_ASSERT(0 <= hourOfDay && hourOfDay <= 23);
2473
2474
2475
            // If hour-of-day is 0 or 13 thru 23 then input time in unambiguously in 24-hour format.
2476
0
            if (hourOfDay == 0 || (13 <= hourOfDay && hourOfDay <= 23)) {
2477
                // Make hour-of-day take precedence over (hour + am/pm) by setting it again.
2478
0
                cal.set(UCAL_HOUR_OF_DAY, hourOfDay);
2479
0
            } 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
0
                if (hourOfDay == 12) { hourOfDay = 0; }
2492
0
                double currentHour = hourOfDay + (cal.get(UCAL_MINUTE, status)) / 60.0;
2493
0
                double midPointHour = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
2494
2495
0
                if (U_SUCCESS(status)) {
2496
0
                    double hoursAheadMidPoint = currentHour - midPointHour;
2497
2498
                    // Assume current time is in the AM.
2499
0
                    if (-6 <= hoursAheadMidPoint && hoursAheadMidPoint < 6) {
2500
                        // Assumption holds; set time as such.
2501
0
                        cal.set(UCAL_AM_PM, 0);
2502
0
                    } else {
2503
0
                        cal.set(UCAL_AM_PM, 1);
2504
0
                    }
2505
0
                }
2506
0
            }
2507
0
        }
2508
0
    }
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
0
    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
0
    if (ambiguousYear[0] || tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) // If this is true then the two-digit year == the default start year
2539
0
    {
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
0
        Calendar *copy;
2545
0
        if (ambiguousYear[0]) {
2546
0
            copy = cal.clone();
2547
            // Check for failed cloning.
2548
0
            if (copy == NULL) {
2549
0
                status = U_MEMORY_ALLOCATION_ERROR;
2550
0
                goto ExitParse;
2551
0
            }
2552
0
            UDate parsedDate = copy->getTime(status);
2553
            // {sfb} check internalGetDefaultCenturyStart
2554
0
            if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) {
2555
                // We can't use add here because that does a complete() first.
2556
0
                cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100);
2557
0
            }
2558
0
            delete copy;
2559
0
        }
2560
2561
0
        if (tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) {
2562
0
            copy = cal.clone();
2563
            // Check for failed cloning.
2564
0
            if (copy == NULL) {
2565
0
                status = U_MEMORY_ALLOCATION_ERROR;
2566
0
                goto ExitParse;
2567
0
            }
2568
0
            const TimeZone & tz = cal.getTimeZone();
2569
0
            BasicTimeZone *btz = NULL;
2570
2571
0
            if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL
2572
0
                || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL
2573
0
                || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL
2574
0
                || dynamic_cast<const VTimeZone *>(&tz) != NULL) {
2575
0
                btz = (BasicTimeZone*)&tz;
2576
0
            }
2577
2578
            // Get local millis
2579
0
            copy->set(UCAL_ZONE_OFFSET, 0);
2580
0
            copy->set(UCAL_DST_OFFSET, 0);
2581
0
            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
0
            int32_t raw, dst;
2586
0
            if (btz != NULL) {
2587
0
                if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) {
2588
0
                    btz->getOffsetFromLocal(localMillis,
2589
0
                        UCAL_TZ_LOCAL_STANDARD_FORMER, UCAL_TZ_LOCAL_STANDARD_LATTER, raw, dst, status);
2590
0
                } else {
2591
0
                    btz->getOffsetFromLocal(localMillis,
2592
0
                        UCAL_TZ_LOCAL_DAYLIGHT_FORMER, UCAL_TZ_LOCAL_DAYLIGHT_LATTER, raw, dst, status);
2593
0
                }
2594
0
            } else {
2595
                // No good way to resolve ambiguous time at transition,
2596
                // but following code work in most case.
2597
0
                tz.getOffset(localMillis, TRUE, raw, dst, status);
2598
0
            }
2599
2600
            // Now, compare the results with parsed type, either standard or daylight saving time
2601
0
            int32_t resolvedSavings = dst;
2602
0
            if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) {
2603
0
                if (dst != 0) {
2604
                    // Override DST_OFFSET = 0 in the result calendar
2605
0
                    resolvedSavings = 0;
2606
0
                }
2607
0
            } else { // tztype == TZTYPE_DST
2608
0
                if (dst == 0) {
2609
0
                    if (btz != NULL) {
2610
                        // This implementation resolves daylight saving time offset
2611
                        // closest rule after the given time.
2612
0
                        UDate baseTime = localMillis + raw;
2613
0
                        UDate time = baseTime;
2614
0
                        UDate limit = baseTime + MAX_DAYLIGHT_DETECTION_RANGE;
2615
0
                        TimeZoneTransition trs;
2616
0
                        UBool trsAvail;
2617
2618
                        // Search for DST rule after the given time
2619
0
                        while (time < limit) {
2620
0
                            trsAvail = btz->getNextTransition(time, FALSE, trs);
2621
0
                            if (!trsAvail) {
2622
0
                                break;
2623
0
                            }
2624
0
                            resolvedSavings = trs.getTo()->getDSTSavings();
2625
0
                            if (resolvedSavings != 0) {
2626
0
                                break;
2627
0
                            }
2628
0
                            time = trs.getTime();
2629
0
                        }
2630
2631
0
                        if (resolvedSavings == 0) {
2632
                            // If no DST rule after the given time was found, search for
2633
                            // DST rule before.
2634
0
                            time = baseTime;
2635
0
                            limit = baseTime - MAX_DAYLIGHT_DETECTION_RANGE;
2636
0
                            while (time > limit) {
2637
0
                                trsAvail = btz->getPreviousTransition(time, TRUE, trs);
2638
0
                                if (!trsAvail) {
2639
0
                                    break;
2640
0
                                }
2641
0
                                resolvedSavings = trs.getFrom()->getDSTSavings();
2642
0
                                if (resolvedSavings != 0) {
2643
0
                                    break;
2644
0
                                }
2645
0
                                time = trs.getTime() - 1;
2646
0
                            }
2647
2648
0
                            if (resolvedSavings == 0) {
2649
0
                                resolvedSavings = btz->getDSTSavings();
2650
0
                            }
2651
0
                        }
2652
0
                    } else {
2653
0
                        resolvedSavings = tz.getDSTSavings();
2654
0
                    }
2655
0
                    if (resolvedSavings == 0) {
2656
                        // final fallback
2657
0
                        resolvedSavings = U_MILLIS_PER_HOUR;
2658
0
                    }
2659
0
                }
2660
0
            }
2661
0
            cal.set(UCAL_ZONE_OFFSET, raw);
2662
0
            cal.set(UCAL_DST_OFFSET, resolvedSavings);
2663
0
            delete copy;
2664
0
        }
2665
0
    }
2666
0
ExitParse:
2667
    // Set the parsed result if local calendar is used
2668
    // instead of the input calendar
2669
0
    if (U_SUCCESS(status) && workCal != &cal) {
2670
0
        cal.setTimeZone(workCal->getTimeZone());
2671
0
        cal.setTime(workCal->getTime(status), status);
2672
0
    }
2673
2674
0
    if (numericLeapMonthFormatter != NULL) {
2675
0
        delete numericLeapMonthFormatter;
2676
0
    }
2677
0
    if (calClone != NULL) {
2678
0
        delete calClone;
2679
0
    }
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
0
    if (U_FAILURE(status)) {
2685
0
        parsePos.setErrorIndex(pos);
2686
0
        parsePos.setIndex(start);
2687
0
    }
2688
0
}
2689
2690
//----------------------------------------------------------------------
2691
2692
static int32_t
2693
matchStringWithOptionalDot(const UnicodeString &text,
2694
                            int32_t index,
2695
                            const UnicodeString &data);
2696
2697
int32_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
0
{
2704
0
    int32_t i = 0;
2705
0
    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
0
    int32_t bestMatchLength = 0, bestMatch = -1;
2712
0
    UnicodeString bestMatchName;
2713
2714
0
    for (; i < count; ++i) {
2715
0
        int32_t matchLength = 0;
2716
0
        if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
2717
0
            bestMatchLength = matchLength;
2718
0
            bestMatch = i;
2719
0
        }
2720
0
    }
2721
2722
0
    if (bestMatch >= 0) {
2723
0
        cal.set(field, bestMatch * 3);
2724
0
        return start + bestMatchLength;
2725
0
    }
2726
2727
0
    return -start;
2728
0
}
2729
2730
int32_t SimpleDateFormat::matchDayPeriodStrings(const UnicodeString& text, int32_t start,
2731
                              const UnicodeString* data, int32_t dataCount,
2732
                              int32_t &dayPeriod) const
2733
0
{
2734
2735
0
    int32_t bestMatchLength = 0, bestMatch = -1;
2736
2737
0
    for (int32_t i = 0; i < dataCount; ++i) {
2738
0
        int32_t matchLength = 0;
2739
0
        if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
2740
0
            bestMatchLength = matchLength;
2741
0
            bestMatch = i;
2742
0
        }
2743
0
    }
2744
2745
0
    if (bestMatch >= 0) {
2746
0
        dayPeriod = bestMatch;
2747
0
        return start + bestMatchLength;
2748
0
    }
2749
2750
0
    return -start;
2751
0
}
2752
2753
//----------------------------------------------------------------------
2754
UBool 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
0
{
2762
0
    UBool inQuote = FALSE;
2763
0
    UnicodeString literal;
2764
0
    int32_t i = patternOffset;
2765
2766
    // scan pattern looking for contiguous literal characters
2767
0
    for ( ; i < pattern.length(); i += 1) {
2768
0
        UChar ch = pattern.charAt(i);
2769
2770
0
        if (!inQuote && isSyntaxChar(ch)) {
2771
0
            break;
2772
0
        }
2773
2774
0
        if (ch == QUOTE) {
2775
            // Match a quote literal ('') inside OR outside of quotes
2776
0
            if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) {
2777
0
                i += 1;
2778
0
            } else {
2779
0
                inQuote = !inQuote;
2780
0
                continue;
2781
0
            }
2782
0
        }
2783
2784
0
        literal += ch;
2785
0
    }
2786
2787
    // at this point, literal contains the literal text
2788
    // and i is the index of the next non-literal pattern character.
2789
0
    int32_t p;
2790
0
    int32_t t = textOffset;
2791
2792
0
    if (whitespaceLenient) {
2793
        // trim leading, trailing whitespace from
2794
        // the literal text
2795
0
        literal.trim();
2796
2797
        // ignore any leading whitespace in the text
2798
0
        while (t < text.length() && u_isWhitespace(text.charAt(t))) {
2799
0
            t += 1;
2800
0
        }
2801
0
    }
2802
2803
0
    for (p = 0; p < literal.length() && t < text.length();) {
2804
0
        UBool needWhitespace = FALSE;
2805
2806
0
        while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
2807
0
            needWhitespace = TRUE;
2808
0
            p += 1;
2809
0
        }
2810
2811
0
        if (needWhitespace) {
2812
0
            int32_t tStart = t;
2813
2814
0
            while (t < text.length()) {
2815
0
                UChar tch = text.charAt(t);
2816
2817
0
                if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) {
2818
0
                    break;
2819
0
                }
2820
2821
0
                t += 1;
2822
0
            }
2823
2824
            // TODO: should we require internal spaces
2825
            // in lenient mode? (There won't be any
2826
            // leading or trailing spaces)
2827
0
            if (!whitespaceLenient && t == tStart) {
2828
                // didn't find matching whitespace:
2829
                // an error in strict mode
2830
0
                return FALSE;
2831
0
            }
2832
2833
            // In strict mode, this run of whitespace
2834
            // may have been at the end.
2835
0
            if (p >= literal.length()) {
2836
0
                break;
2837
0
            }
2838
0
        }
2839
0
        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
0
            if (whitespaceLenient) {
2843
0
                if (t == textOffset && text.charAt(t) == 0x2e &&
2844
0
                        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
0
                    ++t;
2848
0
                    continue;  // Do not update p.
2849
0
                }
2850
                // if it is actual whitespace and we're whitespace lenient it's OK
2851
2852
0
                UChar wsc = text.charAt(t);
2853
0
                if(PatternProps::isWhiteSpace(wsc)) {
2854
                    // Lenient mode and it's just whitespace we skip it
2855
0
                    ++t;
2856
0
                    continue;  // Do not update p.
2857
0
                }
2858
0
            }
2859
            // hack around oldleniency being a bit of a catch-all bucket and we're just adding support specifically for partial matches
2860
0
            if(partialMatchLenient && oldLeniency) {
2861
0
                break;
2862
0
            }
2863
2864
0
            return FALSE;
2865
0
        }
2866
0
        ++p;
2867
0
        ++t;
2868
0
    }
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
0
    if (p <= 0) {
2874
        // no match. Pretend it matched a run of whitespace
2875
        // and ignorables in the text.
2876
0
        const  UnicodeSet *ignorables = NULL;
2877
0
        UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(pattern.charAt(i));
2878
0
        if (patternCharIndex != UDAT_FIELD_COUNT) {
2879
0
            ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
2880
0
        }
2881
2882
0
        for (t = textOffset; t < text.length(); t += 1) {
2883
0
            UChar ch = text.charAt(t);
2884
2885
0
            if (ignorables == NULL || !ignorables->contains(ch)) {
2886
0
                break;
2887
0
            }
2888
0
        }
2889
0
    }
2890
2891
    // if we get here, we've got a complete match.
2892
0
    patternOffset = i - 1;
2893
0
    textOffset = t;
2894
2895
0
    return TRUE;
2896
0
}
2897
2898
//----------------------------------------------------------------------
2899
2900
int32_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
0
{
2908
0
    int32_t i = 0;
2909
0
    int32_t count = dataCount;
2910
2911
0
    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
0
    int32_t bestMatchLength = 0, bestMatch = -1;
2918
0
    UnicodeString bestMatchName;
2919
0
    int32_t isLeapMonth = 0;
2920
2921
0
    for (; i < count; ++i) {
2922
0
        int32_t matchLen = 0;
2923
0
        if ((matchLen = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
2924
0
            bestMatch = i;
2925
0
            bestMatchLength = matchLen;
2926
0
        }
2927
2928
0
        if (monthPattern != NULL) {
2929
0
            UErrorCode status = U_ZERO_ERROR;
2930
0
            UnicodeString leapMonthName;
2931
0
            SimpleFormatter(*monthPattern, 1, 1, status).format(data[i], leapMonthName, status);
2932
0
            if (U_SUCCESS(status)) {
2933
0
                if ((matchLen = matchStringWithOptionalDot(text, start, leapMonthName)) > bestMatchLength) {
2934
0
                    bestMatch = i;
2935
0
                    bestMatchLength = matchLen;
2936
0
                    isLeapMonth = 1;
2937
0
                }
2938
0
            }
2939
0
        }
2940
0
    }
2941
2942
0
    if (bestMatch >= 0) {
2943
0
        if (field < UCAL_FIELD_COUNT) {
2944
            // Adjustment for Hebrew Calendar month Adar II
2945
0
            if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
2946
0
                cal.set(field,6);
2947
0
            } else {
2948
0
                if (field == UCAL_YEAR) {
2949
0
                    bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
2950
0
                }
2951
0
                cal.set(field, bestMatch);
2952
0
            }
2953
0
            if (monthPattern != NULL) {
2954
0
                cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth);
2955
0
            }
2956
0
        }
2957
2958
0
        return start + bestMatchLength;
2959
0
    }
2960
2961
0
    return -start;
2962
0
}
2963
2964
static int32_t
2965
matchStringWithOptionalDot(const UnicodeString &text,
2966
                            int32_t index,
2967
0
                            const UnicodeString &data) {
2968
0
    UErrorCode sts = U_ZERO_ERROR;
2969
0
    int32_t matchLenText = 0;
2970
0
    int32_t matchLenData = 0;
2971
2972
0
    u_caseInsensitivePrefixMatch(text.getBuffer() + index, text.length() - index,
2973
0
                                 data.getBuffer(), data.length(),
2974
0
                                 0 /* default case option */,
2975
0
                                 &matchLenText, &matchLenData,
2976
0
                                 &sts);
2977
0
    U_ASSERT (U_SUCCESS(sts));
2978
2979
0
    if (matchLenData == data.length() /* normal match */
2980
0
        || (data.charAt(data.length() - 1) == 0x2e
2981
0
            && matchLenData == data.length() - 1 /* match without trailing dot */)) {
2982
0
        return matchLenText;
2983
0
    }
2984
2985
0
    return 0;
2986
0
}
2987
2988
//----------------------------------------------------------------------
2989
2990
void
2991
SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
2992
0
{
2993
0
    parseAmbiguousDatesAsAfter(d, status);
2994
0
}
2995
2996
/**
2997
 * Private member function that converts the parsed date strings into
2998
 * timeFields. Returns -start (for ParsePosition) if failed.
2999
 */
3000
int32_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
0
{
3005
0
    Formattable number;
3006
0
    int32_t value = 0;
3007
0
    int32_t i;
3008
0
    int32_t ps = 0;
3009
0
    UErrorCode status = U_ZERO_ERROR;
3010
0
    ParsePosition pos(0);
3011
0
    UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
3012
0
    const NumberFormat *currentNumberFormat;
3013
0
    UnicodeString temp;
3014
0
    UBool gotNumber = FALSE;
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
0
    if (patternCharIndex == UDAT_FIELD_COUNT) {
3021
0
        return -start;
3022
0
    }
3023
3024
0
    currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
3025
0
    if (currentNumberFormat == NULL) {
3026
0
        return -start;
3027
0
    }
3028
0
    UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; // UCAL_FIELD_COUNT if irrelevant
3029
0
    UnicodeString hebr("hebr", 4, US_INV);
3030
3031
0
    if (numericLeapMonthFormatter != NULL) {
3032
0
        numericLeapMonthFormatter->setFormats((const Format **)&currentNumberFormat, 1);
3033
0
    }
3034
0
    UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_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
0
    for (;;) {
3039
0
        if (start >= text.length()) {
3040
0
            return -start;
3041
0
        }
3042
0
        UChar32 c = text.char32At(start);
3043
0
        if (!u_isUWhiteSpace(c) /*||*/ && !PatternProps::isWhiteSpace(c)) {
3044
0
            break;
3045
0
        }
3046
0
        start += U16_LENGTH(c);
3047
0
    }
3048
0
    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
0
    if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||                       // k
3055
0
        patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD ||                       // H
3056
0
        patternCharIndex == UDAT_HOUR1_FIELD ||                              // h
3057
0
        patternCharIndex == UDAT_HOUR0_FIELD ||                              // K
3058
0
        (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) ||          // e
3059
0
        (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) ||     // c
3060
0
        (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||              // M
3061
0
        (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) ||   // L
3062
0
        (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) ||            // Q
3063
0
        (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || // q
3064
0
        patternCharIndex == UDAT_YEAR_FIELD ||                               // y
3065
0
        patternCharIndex == UDAT_YEAR_WOY_FIELD ||                           // Y
3066
0
        patternCharIndex == UDAT_YEAR_NAME_FIELD ||                          // U (falls back to numeric)
3067
0
        (patternCharIndex == UDAT_ERA_FIELD && isChineseCalendar) ||         // G
3068
0
        patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)                    // S
3069
0
    {
3070
0
        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
0
        const UnicodeString* src;
3074
3075
0
        UBool parsedNumericLeapMonth = FALSE;
3076
0
        if (numericLeapMonthFormatter != NULL && (patternCharIndex == UDAT_MONTH_FIELD || patternCharIndex == UDAT_STANDALONE_MONTH_FIELD)) {
3077
0
            int32_t argCount;
3078
0
            Formattable * args = numericLeapMonthFormatter->parse(text, pos, argCount);
3079
0
            if (args != NULL && argCount == 1 && pos.getIndex() > parseStart && args[0].isNumeric()) {
3080
0
                parsedNumericLeapMonth = TRUE;
3081
0
                number.setLong(args[0].getLong());
3082
0
                cal.set(UCAL_IS_LEAP_MONTH, 1);
3083
0
                delete[] args;
3084
0
            } else {
3085
0
                pos.setIndex(parseStart);
3086
0
                cal.set(UCAL_IS_LEAP_MONTH, 0);
3087
0
            }
3088
0
        }
3089
3090
0
        if (!parsedNumericLeapMonth) {
3091
0
            if (obeyCount) {
3092
0
                if ((start+count) > text.length()) {
3093
0
                    return -start;
3094
0
                }
3095
3096
0
                text.extractBetween(0, start + count, temp);
3097
0
                src = &temp;
3098
0
            } else {
3099
0
                src = &text;
3100
0
            }
3101
3102
0
            parseInt(*src, number, pos, allowNegative,currentNumberFormat);
3103
0
        }
3104
3105
0
        int32_t txtLoc = pos.getIndex();
3106
3107
0
        if (txtLoc > parseStart) {
3108
0
            value = number.getLong();
3109
0
            gotNumber = TRUE;
3110
3111
            // suffix processing
3112
0
            if (value < 0 ) {
3113
0
                txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
3114
0
                if (txtLoc != pos.getIndex()) {
3115
0
                    value *= -1;
3116
0
                }
3117
0
            }
3118
0
            else {
3119
0
                txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);
3120
0
            }
3121
3122
0
            if (!getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) {
3123
                // Check the range of the value
3124
0
                int32_t bias = gFieldRangeBias[patternCharIndex];
3125
0
                if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
3126
0
                    return -start;
3127
0
                }
3128
0
            }
3129
3130
0
            pos.setIndex(txtLoc);
3131
0
        }
3132
0
    }
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
0
    switch (patternCharIndex) {
3138
0
        case UDAT_HOUR_OF_DAY1_FIELD:
3139
0
        case UDAT_HOUR_OF_DAY0_FIELD:
3140
0
        case UDAT_HOUR1_FIELD:
3141
0
        case UDAT_HOUR0_FIELD:
3142
            // special range check for hours:
3143
0
            if (value < 0 || value > 24) {
3144
0
                return -start;
3145
0
            }
3146
3147
            // fall through to gotNumber check
3148
0
            U_FALLTHROUGH;
3149
0
        case UDAT_YEAR_FIELD:
3150
0
        case UDAT_YEAR_WOY_FIELD:
3151
0
        case UDAT_FRACTIONAL_SECOND_FIELD:
3152
            // these must be a number
3153
0
            if (! gotNumber) {
3154
0
                return -start;
3155
0
            }
3156
3157
0
            break;
3158
3159
0
        default:
3160
            // we check the rest of the fields below.
3161
0
            break;
3162
0
    }
3163
3164
0
    switch (patternCharIndex) {
3165
0
    case UDAT_ERA_FIELD:
3166
0
        if (isChineseCalendar) {
3167
0
            if (!gotNumber) {
3168
0
                return -start;
3169
0
            }
3170
0
            cal.set(UCAL_ERA, value);
3171
0
            return pos.getIndex();
3172
0
        }
3173
0
        if (count == 5) {
3174
0
            ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, NULL, cal);
3175
0
        } else if (count == 4) {
3176
0
            ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, NULL, cal);
3177
0
        } else {
3178
0
            ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, NULL, cal);
3179
0
        }
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
0
        if (ps == -start)
3185
0
            ps--;
3186
3187
0
        return ps;
3188
3189
0
    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
0
        if (fDateOverride.compare(hebr)==0 && value < 1000) {
3197
0
            value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
3198
0
        } else if (text.moveIndex32(start, 2) == pos.getIndex() && !isChineseCalendar
3199
0
            && u_isdigit(text.char32At(start))
3200
0
            && u_isdigit(text.char32At(text.moveIndex32(start, 1))))
3201
0
        {
3202
            // only adjust year for patterns less than 3.
3203
0
            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
0
                if(fHaveDefaultCentury) { // check if this formatter even has a pivot year
3213
0
                    int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
3214
0
                    ambiguousYear[0] = (value == ambiguousTwoDigitYear);
3215
0
                    value += (fDefaultCenturyStartYear/100)*100 +
3216
0
                            (value < ambiguousTwoDigitYear ? 100 : 0);
3217
0
                }
3218
0
            }
3219
0
        }
3220
0
        cal.set(UCAL_YEAR, value);
3221
3222
        // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
3223
0
        if (saveHebrewMonth >= 0) {
3224
0
            HebrewCalendar *hc = (HebrewCalendar*)&cal;
3225
0
            if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) {
3226
0
               cal.set(UCAL_MONTH,saveHebrewMonth);
3227
0
            } else {
3228
0
               cal.set(UCAL_MONTH,saveHebrewMonth-1);
3229
0
            }
3230
0
            saveHebrewMonth = -1;
3231
0
        }
3232
0
        return pos.getIndex();
3233
3234
0
    case UDAT_YEAR_WOY_FIELD:
3235
        // Comment is the same as for UDAT_Year_FIELDs - look above
3236
0
        if (fDateOverride.compare(hebr)==0 && value < 1000) {
3237
0
            value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
3238
0
        } else if (text.moveIndex32(start, 2) == pos.getIndex()
3239
0
            && u_isdigit(text.char32At(start))
3240
0
            && u_isdigit(text.char32At(text.moveIndex32(start, 1)))
3241
0
            && fHaveDefaultCentury )
3242
0
        {
3243
0
            int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
3244
0
            ambiguousYear[0] = (value == ambiguousTwoDigitYear);
3245
0
            value += (fDefaultCenturyStartYear/100)*100 +
3246
0
                (value < ambiguousTwoDigitYear ? 100 : 0);
3247
0
        }
3248
0
        cal.set(UCAL_YEAR_WOY, value);
3249
0
        return pos.getIndex();
3250
3251
0
    case UDAT_YEAR_NAME_FIELD:
3252
0
        if (fSymbols->fShortYearNames != NULL) {
3253
0
            int32_t newStart = matchString(text, start, UCAL_YEAR, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount, NULL, cal);
3254
0
            if (newStart > 0) {
3255
0
                return newStart;
3256
0
            }
3257
0
        }
3258
0
        if (gotNumber && (getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC,status) || value > fSymbols->fShortYearNamesCount)) {
3259
0
            cal.set(UCAL_YEAR, value);
3260
0
            return pos.getIndex();
3261
0
        }
3262
0
        return -start;
3263
3264
0
    case UDAT_MONTH_FIELD:
3265
0
    case UDAT_STANDALONE_MONTH_FIELD:
3266
0
        if (gotNumber) // i.e., M or MM.
3267
0
        {
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
0
            if (!strcmp(cal.getType(),"hebrew")) {
3272
0
                HebrewCalendar *hc = (HebrewCalendar*)&cal;
3273
0
                if (cal.isSet(UCAL_YEAR)) {
3274
0
                   UErrorCode monthStatus = U_ZERO_ERROR;
3275
0
                   if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) {
3276
0
                       cal.set(UCAL_MONTH, value);
3277
0
                   } else {
3278
0
                       cal.set(UCAL_MONTH, value - 1);
3279
0
                   }
3280
0
                } else {
3281
0
                    saveHebrewMonth = value;
3282
0
                }
3283
0
            } 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
0
                cal.set(UCAL_MONTH, value - 1);
3288
0
            }
3289
0
            return pos.getIndex();
3290
0
        } 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
0
            UnicodeString * wideMonthPat = NULL;
3295
0
            UnicodeString * shortMonthPat = NULL;
3296
0
            if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
3297
0
                if (patternCharIndex==UDAT_MONTH_FIELD) {
3298
0
                    wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide];
3299
0
                    shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev];
3300
0
                } else {
3301
0
                    wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide];
3302
0
                    shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev];
3303
0
                }
3304
0
            }
3305
0
            int32_t newStart = 0;
3306
0
            if (patternCharIndex==UDAT_MONTH_FIELD) {
3307
0
                if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3308
0
                    newStart = matchString(text, start, UCAL_MONTH, fSymbols->fMonths, fSymbols->fMonthsCount, wideMonthPat, cal); // try MMMM
3309
0
                    if (newStart > 0) {
3310
0
                        return newStart;
3311
0
                    }
3312
0
                }
3313
0
                if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3314
0
                    newStart = matchString(text, start, UCAL_MONTH, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, shortMonthPat, cal); // try MMM
3315
0
                }
3316
0
            } else {
3317
0
                if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3318
0
                    newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, wideMonthPat, cal); // try LLLL
3319
0
                    if (newStart > 0) {
3320
0
                        return newStart;
3321
0
                    }
3322
0
                }
3323
0
                if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3324
0
                    newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, shortMonthPat, cal); // try LLL
3325
0
                }
3326
0
            }
3327
0
            if (newStart > 0 || !getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))  // currently we do not try to parse MMMMM/LLLLL: #8860
3328
0
                return newStart;
3329
            // else we allowing parsing as number, below
3330
0
        }
3331
0
        break;
3332
3333
0
    case UDAT_HOUR_OF_DAY1_FIELD:
3334
        // [We computed 'value' above.]
3335
0
        if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
3336
0
            value = 0;
3337
3338
        // fall through to set field
3339
0
        U_FALLTHROUGH;
3340
0
    case UDAT_HOUR_OF_DAY0_FIELD:
3341
0
        cal.set(UCAL_HOUR_OF_DAY, value);
3342
0
        return pos.getIndex();
3343
3344
0
    case UDAT_FRACTIONAL_SECOND_FIELD:
3345
        // Fractional seconds left-justify
3346
0
        i = countDigits(text, start, pos.getIndex());
3347
0
        if (i < 3) {
3348
0
            while (i < 3) {
3349
0
                value *= 10;
3350
0
                i++;
3351
0
            }
3352
0
        } else {
3353
0
            int32_t a = 1;
3354
0
            while (i > 3) {
3355
0
                a *= 10;
3356
0
                i--;
3357
0
            }
3358
0
            value /= a;
3359
0
        }
3360
0
        cal.set(UCAL_MILLISECOND, value);
3361
0
        return pos.getIndex();
3362
3363
0
    case UDAT_DOW_LOCAL_FIELD:
3364
0
        if (gotNumber) // i.e., e or ee
3365
0
        {
3366
            // [We computed 'value' above.]
3367
0
            cal.set(UCAL_DOW_LOCAL, value);
3368
0
            return pos.getIndex();
3369
0
        }
3370
        // else for eee-eeeee fall through to handling of EEE-EEEEE
3371
        // fall through, do not break here
3372
0
        U_FALLTHROUGH;
3373
0
    case UDAT_DAY_OF_WEEK_FIELD:
3374
0
        {
3375
            // Want to be able to parse both short and long forms.
3376
            // Try count == 4 (EEEE) wide first:
3377
0
            int32_t newStart = 0;
3378
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3379
0
                if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3380
0
                                          fSymbols->fWeekdays, fSymbols->fWeekdaysCount, NULL, cal)) > 0)
3381
0
                    return newStart;
3382
0
            }
3383
            // EEEE wide failed, now try EEE abbreviated
3384
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3385
0
                if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3386
0
                                       fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, NULL, cal)) > 0)
3387
0
                    return newStart;
3388
0
            }
3389
            // EEE abbreviated failed, now try EEEEEE short
3390
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) {
3391
0
                if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3392
0
                                       fSymbols->fShorterWeekdays, fSymbols->fShorterWeekdaysCount, NULL, cal)) > 0)
3393
0
                    return newStart;
3394
0
            }
3395
            // EEEEEE short failed, now try EEEEE narrow
3396
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
3397
0
                if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3398
0
                                       fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, NULL, cal)) > 0)
3399
0
                    return newStart;
3400
0
            }
3401
0
            if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status) || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD)
3402
0
                return newStart;
3403
            // else we allowing parsing as number, below
3404
0
        }
3405
0
        break;
3406
3407
0
    case UDAT_STANDALONE_DAY_FIELD:
3408
0
        {
3409
0
            if (gotNumber) // c or cc
3410
0
            {
3411
                // [We computed 'value' above.]
3412
0
                cal.set(UCAL_DOW_LOCAL, value);
3413
0
                return pos.getIndex();
3414
0
            }
3415
            // Want to be able to parse both short and long forms.
3416
            // Try count == 4 (cccc) first:
3417
0
            int32_t newStart = 0;
3418
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3419
0
                if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3420
0
                                      fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, NULL, cal)) > 0)
3421
0
                    return newStart;
3422
0
            }
3423
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3424
0
                if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3425
0
                                          fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, NULL, cal)) > 0)
3426
0
                    return newStart;
3427
0
            }
3428
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) {
3429
0
                if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3430
0
                                          fSymbols->fStandaloneShorterWeekdays, fSymbols->fStandaloneShorterWeekdaysCount, NULL, cal)) > 0)
3431
0
                    return newStart;
3432
0
            }
3433
0
            if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
3434
0
                return newStart;
3435
            // else we allowing parsing as number, below
3436
0
        }
3437
0
        break;
3438
3439
0
    case UDAT_AM_PM_FIELD:
3440
0
        {
3441
            // optionally try both wide/abbrev and narrow forms
3442
0
            int32_t newStart = 0;
3443
            // try wide/abbrev
3444
0
            if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count < 5 ) {
3445
0
                if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal)) > 0) {
3446
0
                    return newStart;
3447
0
                }
3448
0
            }
3449
            // try narrow
3450
0
            if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count >= 5 ) {
3451
0
                if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fNarrowAmPms, fSymbols->fNarrowAmPmsCount, NULL, cal)) > 0) {
3452
0
                    return newStart;
3453
0
                }
3454
0
            }
3455
            // no matches for given options
3456
0
            return -start;
3457
0
        }
3458
3459
0
    case UDAT_HOUR1_FIELD:
3460
        // [We computed 'value' above.]
3461
0
        if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
3462
0
            value = 0;
3463
3464
        // fall through to set field
3465
0
        U_FALLTHROUGH;
3466
0
    case UDAT_HOUR0_FIELD:
3467
0
        cal.set(UCAL_HOUR, value);
3468
0
        return pos.getIndex();
3469
3470
0
    case UDAT_QUARTER_FIELD:
3471
0
        if (gotNumber) // i.e., Q or QQ.
3472
0
        {
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
0
            cal.set(UCAL_MONTH, (value - 1) * 3);
3477
0
            return pos.getIndex();
3478
0
        } 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
0
            int32_t newStart = 0;
3483
3484
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3485
0
                if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3486
0
                                      fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)
3487
0
                    return newStart;
3488
0
            }
3489
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3490
0
                if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3491
0
                                          fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0)
3492
0
                    return newStart;
3493
0
            }
3494
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
3495
0
                if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3496
0
                                      fSymbols->fNarrowQuarters, fSymbols->fNarrowQuartersCount, cal)) > 0)
3497
0
                    return newStart;
3498
0
            }
3499
0
            if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
3500
0
                return newStart;
3501
            // else we allowing parsing as number, below
3502
0
            if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))
3503
0
                return -start;
3504
0
        }
3505
0
        break;
3506
3507
0
    case UDAT_STANDALONE_QUARTER_FIELD:
3508
0
        if (gotNumber) // i.e., q or qq.
3509
0
        {
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
0
            cal.set(UCAL_MONTH, (value - 1) * 3);
3514
0
            return pos.getIndex();
3515
0
        } 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
0
            int32_t newStart = 0;
3520
3521
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3522
0
                if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3523
0
                                      fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)
3524
0
                    return newStart;
3525
0
            }
3526
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3527
0
                if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3528
0
                                          fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0)
3529
0
                    return newStart;
3530
0
            }
3531
0
            if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
3532
0
                if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3533
0
                                          fSymbols->fStandaloneNarrowQuarters, fSymbols->fStandaloneNarrowQuartersCount, cal)) > 0)
3534
0
                    return newStart;
3535
0
            }
3536
0
            if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
3537
0
                return newStart;
3538
            // else we allowing parsing as number, below
3539
0
            if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))
3540
0
                return -start;
3541
0
        }
3542
0
        break;
3543
3544
0
    case UDAT_TIMEZONE_FIELD: // 'z'
3545
0
        {
3546
0
            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;
3547
0
            const TimeZoneFormat *tzfmt = tzFormat(status);
3548
0
            if (U_SUCCESS(status)) {
3549
0
                TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3550
0
                if (tz != NULL) {
3551
0
                    cal.adoptTimeZone(tz);
3552
0
                    return pos.getIndex();
3553
0
                }
3554
0
            }
3555
0
            return -start;
3556
0
    }
3557
0
        break;
3558
0
    case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
3559
0
        {
3560
0
            UTimeZoneFormatStyle style = (count < 4) ?
3561
0
                UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT);
3562
0
            const TimeZoneFormat *tzfmt = tzFormat(status);
3563
0
            if (U_SUCCESS(status)) {
3564
0
                TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3565
0
                if (tz != NULL) {
3566
0
                    cal.adoptTimeZone(tz);
3567
0
                    return pos.getIndex();
3568
0
                }
3569
0
            }
3570
0
            return -start;
3571
0
        }
3572
0
    case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
3573
0
        {
3574
0
            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;
3575
0
            const TimeZoneFormat *tzfmt = tzFormat(status);
3576
0
            if (U_SUCCESS(status)) {
3577
0
                TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3578
0
                if (tz != NULL) {
3579
0
                    cal.adoptTimeZone(tz);
3580
0
                    return pos.getIndex();
3581
0
                }
3582
0
            }
3583
0
            return -start;
3584
0
        }
3585
0
    case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
3586
0
        {
3587
0
            UTimeZoneFormatStyle style;
3588
0
            switch (count) {
3589
0
            case 1:
3590
0
                style = UTZFMT_STYLE_ZONE_ID_SHORT;
3591
0
                break;
3592
0
            case 2:
3593
0
                style = UTZFMT_STYLE_ZONE_ID;
3594
0
                break;
3595
0
            case 3:
3596
0
                style = UTZFMT_STYLE_EXEMPLAR_LOCATION;
3597
0
                break;
3598
0
            default:
3599
0
                style = UTZFMT_STYLE_GENERIC_LOCATION;
3600
0
                break;
3601
0
            }
3602
0
            const TimeZoneFormat *tzfmt = tzFormat(status);
3603
0
            if (U_SUCCESS(status)) {
3604
0
                TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3605
0
                if (tz != NULL) {
3606
0
                    cal.adoptTimeZone(tz);
3607
0
                    return pos.getIndex();
3608
0
                }
3609
0
            }
3610
0
            return -start;
3611
0
        }
3612
0
    case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
3613
0
        {
3614
0
            UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT;
3615
0
            const TimeZoneFormat *tzfmt = tzFormat(status);
3616
0
            if (U_SUCCESS(status)) {
3617
0
                TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3618
0
                if (tz != NULL) {
3619
0
                    cal.adoptTimeZone(tz);
3620
0
                    return pos.getIndex();
3621
0
                }
3622
0
            }
3623
0
            return -start;
3624
0
        }
3625
0
    case UDAT_TIMEZONE_ISO_FIELD: // 'X'
3626
0
        {
3627
0
            UTimeZoneFormatStyle style;
3628
0
            switch (count) {
3629
0
            case 1:
3630
0
                style = UTZFMT_STYLE_ISO_BASIC_SHORT;
3631
0
                break;
3632
0
            case 2:
3633
0
                style = UTZFMT_STYLE_ISO_BASIC_FIXED;
3634
0
                break;
3635
0
            case 3:
3636
0
                style = UTZFMT_STYLE_ISO_EXTENDED_FIXED;
3637
0
                break;
3638
0
            case 4:
3639
0
                style = UTZFMT_STYLE_ISO_BASIC_FULL;
3640
0
                break;
3641
0
            default:
3642
0
                style = UTZFMT_STYLE_ISO_EXTENDED_FULL;
3643
0
                break;
3644
0
            }
3645
0
            const TimeZoneFormat *tzfmt = tzFormat(status);
3646
0
            if (U_SUCCESS(status)) {
3647
0
                TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3648
0
                if (tz != NULL) {
3649
0
                    cal.adoptTimeZone(tz);
3650
0
                    return pos.getIndex();
3651
0
                }
3652
0
            }
3653
0
            return -start;
3654
0
        }
3655
0
    case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
3656
0
        {
3657
0
            UTimeZoneFormatStyle style;
3658
0
            switch (count) {
3659
0
            case 1:
3660
0
                style = UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT;
3661
0
                break;
3662
0
            case 2:
3663
0
                style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED;
3664
0
                break;
3665
0
            case 3:
3666
0
                style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED;
3667
0
                break;
3668
0
            case 4:
3669
0
                style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL;
3670
0
                break;
3671
0
            default:
3672
0
                style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL;
3673
0
                break;
3674
0
            }
3675
0
            const TimeZoneFormat *tzfmt = tzFormat(status);
3676
0
            if (U_SUCCESS(status)) {
3677
0
                TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3678
0
                if (tz != NULL) {
3679
0
                    cal.adoptTimeZone(tz);
3680
0
                    return pos.getIndex();
3681
0
                }
3682
0
            }
3683
0
            return -start;
3684
0
        }
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
0
    case UDAT_TIME_SEPARATOR_FIELD:
3688
0
        {
3689
0
            static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;
3690
0
            static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
3691
3692
            // Try matching a time separator.
3693
0
            int32_t count_sep = 1;
3694
0
            UnicodeString data[3];
3695
0
            fSymbols->getTimeSeparatorString(data[0]);
3696
3697
            // Add the default, if different from the locale.
3698
0
            if (data[0].compare(&def_sep, 1) != 0) {
3699
0
                data[count_sep++].setTo(def_sep);
3700
0
            }
3701
3702
            // If lenient, add also the alternate, if different from the locale.
3703
0
            if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
3704
0
                data[count_sep++].setTo(alt_sep);
3705
0
            }
3706
3707
0
            return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count_sep, NULL, cal);
3708
0
        }
3709
3710
0
    case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
3711
0
    {
3712
0
        U_ASSERT(dayPeriod != NULL);
3713
0
        int32_t ampmStart = subParse(text, start, 0x61, count,
3714
0
                           obeyCount, allowNegative, ambiguousYear, saveHebrewMonth, cal,
3715
0
                           patLoc, numericLeapMonthFormatter, tzTimeType);
3716
3717
0
        if (ampmStart > 0) {
3718
0
            return ampmStart;
3719
0
        } else {
3720
0
            int32_t newStart = 0;
3721
3722
            // Only match the first two strings from the day period strings array.
3723
0
            if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3724
0
                if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
3725
0
                                                        2, *dayPeriod)) > 0) {
3726
0
                    return newStart;
3727
0
                }
3728
0
            }
3729
0
            if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
3730
0
                if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
3731
0
                                                        2, *dayPeriod)) > 0) {
3732
0
                    return newStart;
3733
0
                }
3734
0
            }
3735
            // count == 4, but allow other counts
3736
0
            if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)) {
3737
0
                if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
3738
0
                                                        2, *dayPeriod)) > 0) {
3739
0
                    return newStart;
3740
0
                }
3741
0
            }
3742
3743
0
            return -start;
3744
0
        }
3745
0
    }
3746
3747
0
    case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
3748
0
    {
3749
0
        U_ASSERT(dayPeriod != NULL);
3750
0
        int32_t newStart = 0;
3751
3752
0
        if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3753
0
            if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
3754
0
                                fSymbols->fAbbreviatedDayPeriodsCount, *dayPeriod)) > 0) {
3755
0
                return newStart;
3756
0
            }
3757
0
        }
3758
0
        if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
3759
0
            if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
3760
0
                                fSymbols->fNarrowDayPeriodsCount, *dayPeriod)) > 0) {
3761
0
                return newStart;
3762
0
            }
3763
0
        }
3764
0
        if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3765
0
            if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
3766
0
                                fSymbols->fWideDayPeriodsCount, *dayPeriod)) > 0) {
3767
0
                return newStart;
3768
0
            }
3769
0
        }
3770
3771
0
        return -start;
3772
0
    }
3773
3774
0
    default:
3775
        // Handle "generic" fields
3776
        // this is now handled below, outside the switch block
3777
0
        break;
3778
0
    }
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
0
    int32_t parseStart = pos.getIndex();
3784
0
    const UnicodeString* src;
3785
0
    if (obeyCount) {
3786
0
        if ((start+count) > text.length()) {
3787
0
            return -start;
3788
0
        }
3789
0
        text.extractBetween(0, start + count, temp);
3790
0
        src = &temp;
3791
0
    } else {
3792
0
        src = &text;
3793
0
    }
3794
0
    parseInt(*src, number, pos, allowNegative,currentNumberFormat);
3795
0
    if (pos.getIndex() != parseStart) {
3796
0
        int32_t val = number.getLong();
3797
3798
        // Don't need suffix processing here (as in number processing at the beginning of the function);
3799
        // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.
3800
3801
0
        if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) {
3802
            // Check the range of the value
3803
0
            int32_t bias = gFieldRangeBias[patternCharIndex];
3804
0
            if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) {
3805
0
                return -start;
3806
0
            }
3807
0
        }
3808
3809
        // For the following, need to repeat some of the "if (gotNumber)" code above:
3810
        // UDAT_[STANDALONE_]MONTH_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_STANDALONE_DAY_FIELD,
3811
        // UDAT_[STANDALONE_]QUARTER_FIELD
3812
0
        switch (patternCharIndex) {
3813
0
        case UDAT_MONTH_FIELD:
3814
            // See notes under UDAT_MONTH_FIELD case above
3815
0
            if (!strcmp(cal.getType(),"hebrew")) {
3816
0
                HebrewCalendar *hc = (HebrewCalendar*)&cal;
3817
0
                if (cal.isSet(UCAL_YEAR)) {
3818
0
                   UErrorCode monthStatus = U_ZERO_ERROR;
3819
0
                   if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) {
3820
0
                       cal.set(UCAL_MONTH, val);
3821
0
                   } else {
3822
0
                       cal.set(UCAL_MONTH, val - 1);
3823
0
                   }
3824
0
                } else {
3825
0
                    saveHebrewMonth = val;
3826
0
                }
3827
0
            } else {
3828
0
                cal.set(UCAL_MONTH, val - 1);
3829
0
            }
3830
0
            break;
3831
0
        case UDAT_STANDALONE_MONTH_FIELD:
3832
0
            cal.set(UCAL_MONTH, val - 1);
3833
0
            break;
3834
0
        case UDAT_DOW_LOCAL_FIELD:
3835
0
        case UDAT_STANDALONE_DAY_FIELD:
3836
0
            cal.set(UCAL_DOW_LOCAL, val);
3837
0
            break;
3838
0
        case UDAT_QUARTER_FIELD:
3839
0
        case UDAT_STANDALONE_QUARTER_FIELD:
3840
0
             cal.set(UCAL_MONTH, (val - 1) * 3);
3841
0
             break;
3842
0
        case UDAT_RELATED_YEAR_FIELD:
3843
0
            cal.setRelatedYear(val);
3844
0
            break;
3845
0
        default:
3846
0
            cal.set(field, val);
3847
0
            break;
3848
0
        }
3849
0
        return pos.getIndex();
3850
0
    }
3851
0
    return -start;
3852
0
}
3853
3854
/**
3855
 * Parse an integer using fNumberFormat.  This method is semantically
3856
 * const, but actually may modify fNumberFormat.
3857
 */
3858
void SimpleDateFormat::parseInt(const UnicodeString& text,
3859
                                Formattable& number,
3860
                                ParsePosition& pos,
3861
                                UBool allowNegative,
3862
0
                                const NumberFormat *fmt) const {
3863
0
    parseInt(text, number, -1, pos, allowNegative,fmt);
3864
0
}
3865
3866
/**
3867
 * Parse an integer using fNumberFormat up to maxDigits.
3868
 */
3869
void SimpleDateFormat::parseInt(const UnicodeString& text,
3870
                                Formattable& number,
3871
                                int32_t maxDigits,
3872
                                ParsePosition& pos,
3873
                                UBool allowNegative,
3874
0
                                const NumberFormat *fmt) const {
3875
0
    UnicodeString oldPrefix;
3876
0
    auto* fmtAsDF = dynamic_cast<const DecimalFormat*>(fmt);
3877
0
    LocalPointer<DecimalFormat> df;
3878
0
    if (!allowNegative && fmtAsDF != nullptr) {
3879
0
        df.adoptInstead(fmtAsDF->clone());
3880
0
        if (df.isNull()) {
3881
            // Memory allocation error
3882
0
            return;
3883
0
        }
3884
0
        df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
3885
0
        fmt = df.getAlias();
3886
0
    }
3887
0
    int32_t oldPos = pos.getIndex();
3888
0
    fmt->parse(text, number, pos);
3889
3890
0
    if (maxDigits > 0) {
3891
        // adjust the result to fit into
3892
        // the maxDigits and move the position back
3893
0
        int32_t nDigits = pos.getIndex() - oldPos;
3894
0
        if (nDigits > maxDigits) {
3895
0
            int32_t val = number.getLong();
3896
0
            nDigits -= maxDigits;
3897
0
            while (nDigits > 0) {
3898
0
                val /= 10;
3899
0
                nDigits--;
3900
0
            }
3901
0
            pos.setIndex(oldPos + maxDigits);
3902
0
            number.setLong(val);
3903
0
        }
3904
0
    }
3905
0
}
3906
3907
0
int32_t SimpleDateFormat::countDigits(const UnicodeString& text, int32_t start, int32_t end) const {
3908
0
    int32_t numDigits = 0;
3909
0
    int32_t idx = start;
3910
0
    while (idx < end) {
3911
0
        UChar32 cp = text.char32At(idx);
3912
0
        if (u_isdigit(cp)) {
3913
0
            numDigits++;
3914
0
        }
3915
0
        idx += U16_LENGTH(cp);
3916
0
    }
3917
0
    return numDigits;
3918
0
}
3919
3920
//----------------------------------------------------------------------
3921
3922
void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
3923
                                        UnicodeString& translatedPattern,
3924
                                        const UnicodeString& from,
3925
                                        const UnicodeString& to,
3926
                                        UErrorCode& status)
3927
0
{
3928
    // run through the pattern and convert any pattern symbols from the version
3929
    // in "from" to the corresponding character in "to".  This code takes
3930
    // quoted strings into account (it doesn't try to translate them), and it signals
3931
    // an error if a particular "pattern character" doesn't appear in "from".
3932
    // Depending on the values of "from" and "to" this can convert from generic
3933
    // to localized patterns or localized to generic.
3934
0
    if (U_FAILURE(status)) {
3935
0
        return;
3936
0
    }
3937
3938
0
    translatedPattern.remove();
3939
0
    UBool inQuote = FALSE;
3940
0
    for (int32_t i = 0; i < originalPattern.length(); ++i) {
3941
0
        UChar c = originalPattern[i];
3942
0
        if (inQuote) {
3943
0
            if (c == QUOTE) {
3944
0
                inQuote = FALSE;
3945
0
            }
3946
0
        } else {
3947
0
            if (c == QUOTE) {
3948
0
                inQuote = TRUE;
3949
0
            } else if (isSyntaxChar(c)) {
3950
0
                int32_t ci = from.indexOf(c);
3951
0
                if (ci == -1) {
3952
0
                    status = U_INVALID_FORMAT_ERROR;
3953
0
                    return;
3954
0
                }
3955
0
                c = to[ci];
3956
0
            }
3957
0
        }
3958
0
        translatedPattern += c;
3959
0
    }
3960
0
    if (inQuote) {
3961
0
        status = U_INVALID_FORMAT_ERROR;
3962
0
        return;
3963
0
    }
3964
0
}
3965
3966
//----------------------------------------------------------------------
3967
3968
UnicodeString&
3969
SimpleDateFormat::toPattern(UnicodeString& result) const
3970
0
{
3971
0
    result = fPattern;
3972
0
    return result;
3973
0
}
3974
3975
//----------------------------------------------------------------------
3976
3977
UnicodeString&
3978
SimpleDateFormat::toLocalizedPattern(UnicodeString& result,
3979
                                     UErrorCode& status) const
3980
0
{
3981
0
    translatePattern(fPattern, result,
3982
0
                     UnicodeString(DateFormatSymbols::getPatternUChars()),
3983
0
                     fSymbols->fLocalPatternChars, status);
3984
0
    return result;
3985
0
}
3986
3987
//----------------------------------------------------------------------
3988
3989
void
3990
SimpleDateFormat::applyPattern(const UnicodeString& pattern)
3991
0
{
3992
0
    fPattern = pattern;
3993
0
    parsePattern();
3994
3995
    // Hack to update use of Gannen year numbering for ja@calendar=japanese -
3996
    // use only if format is non-numeric (includes 年) and no other fDateOverride.
3997
0
    if (fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
3998
0
            uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
3999
0
        if (fDateOverride==UnicodeString(u"y=jpanyear") && !fHasHanYearChar) {
4000
            // Gannen numbering is set but new pattern should not use it, unset;
4001
            // use procedure from adoptNumberFormat to clear overrides
4002
0
            if (fSharedNumberFormatters) {
4003
0
                freeSharedNumberFormatters(fSharedNumberFormatters);
4004
0
                fSharedNumberFormatters = NULL;
4005
0
            }
4006
0
            fDateOverride.setToBogus(); // record status
4007
0
        } else if (fDateOverride.isBogus() && fHasHanYearChar) {
4008
            // No current override (=> no Gannen numbering) but new pattern needs it;
4009
            // use procedures from initNUmberFormatters / adoptNumberFormat
4010
0
            umtx_lock(&LOCK);
4011
0
            if (fSharedNumberFormatters == NULL) {
4012
0
                fSharedNumberFormatters = allocSharedNumberFormatters();
4013
0
            }
4014
0
            umtx_unlock(&LOCK);
4015
0
            if (fSharedNumberFormatters != NULL) {
4016
0
                Locale ovrLoc(fLocale.getLanguage(),fLocale.getCountry(),fLocale.getVariant(),"numbers=jpanyear");
4017
0
                UErrorCode status = U_ZERO_ERROR;
4018
0
                const SharedNumberFormat *snf = createSharedNumberFormat(ovrLoc, status);
4019
0
                if (U_SUCCESS(status)) {
4020
                    // Now that we have an appropriate number formatter, fill in the
4021
                    // appropriate slot in the number formatters table.
4022
0
                    UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(u'y');
4023
0
                    SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
4024
0
                    snf->deleteIfZeroRefCount();
4025
0
                    fDateOverride.setTo(u"y=jpanyear", -1); // record status
4026
0
                }
4027
0
            }
4028
0
        }
4029
0
    }
4030
0
}
4031
4032
//----------------------------------------------------------------------
4033
4034
void
4035
SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
4036
                                        UErrorCode &status)
4037
0
{
4038
0
    translatePattern(pattern, fPattern,
4039
0
                     fSymbols->fLocalPatternChars,
4040
0
                     UnicodeString(DateFormatSymbols::getPatternUChars()), status);
4041
0
}
4042
4043
//----------------------------------------------------------------------
4044
4045
const DateFormatSymbols*
4046
SimpleDateFormat::getDateFormatSymbols() const
4047
0
{
4048
0
    return fSymbols;
4049
0
}
4050
4051
//----------------------------------------------------------------------
4052
4053
void
4054
SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)
4055
0
{
4056
0
    delete fSymbols;
4057
0
    fSymbols = newFormatSymbols;
4058
0
}
4059
4060
//----------------------------------------------------------------------
4061
void
4062
SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)
4063
0
{
4064
0
    delete fSymbols;
4065
0
    fSymbols = new DateFormatSymbols(newFormatSymbols);
4066
0
}
4067
4068
//----------------------------------------------------------------------
4069
const TimeZoneFormat*
4070
0
SimpleDateFormat::getTimeZoneFormat(void) const {
4071
    // TimeZoneFormat initialization might fail when out of memory.
4072
    // If we always initialize TimeZoneFormat instance, we can return
4073
    // such status there. For now, this implementation lazily instantiates
4074
    // a TimeZoneFormat for performance optimization reasons, but cannot
4075
    // propagate such error (probably just out of memory case) to the caller.
4076
0
    UErrorCode status = U_ZERO_ERROR;
4077
0
    return (const TimeZoneFormat*)tzFormat(status);
4078
0
}
4079
4080
//----------------------------------------------------------------------
4081
void
4082
SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt)
4083
0
{
4084
0
    delete fTimeZoneFormat;
4085
0
    fTimeZoneFormat = timeZoneFormatToAdopt;
4086
0
}
4087
4088
//----------------------------------------------------------------------
4089
void
4090
SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)
4091
0
{
4092
0
    delete fTimeZoneFormat;
4093
0
    fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat);
4094
0
}
4095
4096
//----------------------------------------------------------------------
4097
4098
4099
void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
4100
0
{
4101
0
  UErrorCode status = U_ZERO_ERROR;
4102
0
  Locale calLocale(fLocale);
4103
0
  calLocale.setKeywordValue("calendar", calendarToAdopt->getType(), status);
4104
0
  DateFormatSymbols *newSymbols =
4105
0
          DateFormatSymbols::createForLocale(calLocale, status);
4106
0
  if (U_FAILURE(status)) {
4107
0
      delete calendarToAdopt;
4108
0
      return;
4109
0
  }
4110
0
  DateFormat::adoptCalendar(calendarToAdopt);
4111
0
  delete fSymbols;
4112
0
  fSymbols = newSymbols;
4113
0
  initializeDefaultCentury();  // we need a new century (possibly)
4114
0
}
4115
4116
4117
//----------------------------------------------------------------------
4118
4119
4120
// override the DateFormat implementation in order to
4121
// lazily initialize fCapitalizationBrkIter
4122
void
4123
SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
4124
0
{
4125
0
    DateFormat::setContext(value, status);
4126
0
#if !UCONFIG_NO_BREAK_ITERATION
4127
0
    if (U_SUCCESS(status)) {
4128
0
        if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
4129
0
                value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
4130
0
            status = U_ZERO_ERROR;
4131
0
            fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
4132
0
            if (U_FAILURE(status)) {
4133
0
                delete fCapitalizationBrkIter;
4134
0
                fCapitalizationBrkIter = NULL;
4135
0
            }
4136
0
        }
4137
0
    }
4138
0
#endif
4139
0
}
4140
4141
4142
//----------------------------------------------------------------------
4143
4144
4145
UBool
4146
0
SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
4147
0
    return isFieldUnitIgnored(fPattern, field);
4148
0
}
4149
4150
4151
UBool
4152
SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
4153
0
                                     UCalendarDateFields field) {
4154
0
    int32_t fieldLevel = fgCalendarFieldToLevel[field];
4155
0
    int32_t level;
4156
0
    UChar ch;
4157
0
    UBool inQuote = FALSE;
4158
0
    UChar prevCh = 0;
4159
0
    int32_t count = 0;
4160
4161
0
    for (int32_t i = 0; i < pattern.length(); ++i) {
4162
0
        ch = pattern[i];
4163
0
        if (ch != prevCh && count > 0) {
4164
0
            level = getLevelFromChar(prevCh);
4165
            // the larger the level, the smaller the field unit.
4166
0
            if (fieldLevel <= level) {
4167
0
                return FALSE;
4168
0
            }
4169
0
            count = 0;
4170
0
        }
4171
0
        if (ch == QUOTE) {
4172
0
            if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) {
4173
0
                ++i;
4174
0
            } else {
4175
0
                inQuote = ! inQuote;
4176
0
            }
4177
0
        }
4178
0
        else if (!inQuote && isSyntaxChar(ch)) {
4179
0
            prevCh = ch;
4180
0
            ++count;
4181
0
        }
4182
0
    }
4183
0
    if (count > 0) {
4184
        // last item
4185
0
        level = getLevelFromChar(prevCh);
4186
0
        if (fieldLevel <= level) {
4187
0
            return FALSE;
4188
0
        }
4189
0
    }
4190
0
    return TRUE;
4191
0
}
4192
4193
//----------------------------------------------------------------------
4194
4195
const Locale&
4196
0
SimpleDateFormat::getSmpFmtLocale(void) const {
4197
0
    return fLocale;
4198
0
}
4199
4200
//----------------------------------------------------------------------
4201
4202
int32_t
4203
SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start,
4204
0
                                 int32_t patLoc, UBool isNegative) const {
4205
    // local variables
4206
0
    UnicodeString suf;
4207
0
    int32_t patternMatch;
4208
0
    int32_t textPreMatch;
4209
0
    int32_t textPostMatch;
4210
4211
    // check that we are still in range
4212
0
    if ( (start > text.length()) ||
4213
0
         (start < 0) ||
4214
0
         (patLoc < 0) ||
4215
0
         (patLoc > fPattern.length())) {
4216
        // out of range, don't advance location in text
4217
0
        return start;
4218
0
    }
4219
4220
    // get the suffix
4221
0
    DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
4222
0
    if (decfmt != NULL) {
4223
0
        if (isNegative) {
4224
0
            suf = decfmt->getNegativeSuffix(suf);
4225
0
        }
4226
0
        else {
4227
0
            suf = decfmt->getPositiveSuffix(suf);
4228
0
        }
4229
0
    }
4230
4231
    // check for suffix
4232
0
    if (suf.length() <= 0) {
4233
0
        return start;
4234
0
    }
4235
4236
    // check suffix will be encountered in the pattern
4237
0
    patternMatch = compareSimpleAffix(suf,fPattern,patLoc);
4238
4239
    // check if a suffix will be encountered in the text
4240
0
    textPreMatch = compareSimpleAffix(suf,text,start);
4241
4242
    // check if a suffix was encountered in the text
4243
0
    textPostMatch = compareSimpleAffix(suf,text,start-suf.length());
4244
4245
    // check for suffix match
4246
0
    if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) {
4247
0
        return start;
4248
0
    }
4249
0
    else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) {
4250
0
        return  start - suf.length();
4251
0
    }
4252
4253
    // should not get here
4254
0
    return start;
4255
0
}
4256
4257
//----------------------------------------------------------------------
4258
4259
int32_t
4260
SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
4261
                   const UnicodeString& input,
4262
0
                   int32_t pos) const {
4263
0
    int32_t start = pos;
4264
0
    for (int32_t i=0; i<affix.length(); ) {
4265
0
        UChar32 c = affix.char32At(i);
4266
0
        int32_t len = U16_LENGTH(c);
4267
0
        if (PatternProps::isWhiteSpace(c)) {
4268
            // We may have a pattern like: \u200F \u0020
4269
            //        and input text like: \u200F \u0020
4270
            // Note that U+200F and U+0020 are Pattern_White_Space but only
4271
            // U+0020 is UWhiteSpace.  So we have to first do a direct
4272
            // match of the run of Pattern_White_Space in the pattern,
4273
            // then match any extra characters.
4274
0
            UBool literalMatch = FALSE;
4275
0
            while (pos < input.length() &&
4276
0
                   input.char32At(pos) == c) {
4277
0
                literalMatch = TRUE;
4278
0
                i += len;
4279
0
                pos += len;
4280
0
                if (i == affix.length()) {
4281
0
                    break;
4282
0
                }
4283
0
                c = affix.char32At(i);
4284
0
                len = U16_LENGTH(c);
4285
0
                if (!PatternProps::isWhiteSpace(c)) {
4286
0
                    break;
4287
0
                }
4288
0
            }
4289
4290
            // Advance over run in pattern
4291
0
            i = skipPatternWhiteSpace(affix, i);
4292
4293
            // Advance over run in input text
4294
            // Must see at least one white space char in input,
4295
            // unless we've already matched some characters literally.
4296
0
            int32_t s = pos;
4297
0
            pos = skipUWhiteSpace(input, pos);
4298
0
            if (pos == s && !literalMatch) {
4299
0
                return -1;
4300
0
            }
4301
4302
            // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
4303
            // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
4304
            // is also in the affix.
4305
0
            i = skipUWhiteSpace(affix, i);
4306
0
        } else {
4307
0
            if (pos < input.length() &&
4308
0
                input.char32At(pos) == c) {
4309
0
                i += len;
4310
0
                pos += len;
4311
0
            } else {
4312
0
                return -1;
4313
0
            }
4314
0
        }
4315
0
    }
4316
0
    return pos - start;
4317
0
}
4318
4319
//----------------------------------------------------------------------
4320
4321
int32_t
4322
0
SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const {
4323
0
    const UChar* s = text.getBuffer();
4324
0
    return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
4325
0
}
4326
4327
//----------------------------------------------------------------------
4328
4329
int32_t
4330
0
SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const {
4331
0
    while (pos < text.length()) {
4332
0
        UChar32 c = text.char32At(pos);
4333
0
        if (!u_isUWhiteSpace(c)) {
4334
0
            break;
4335
0
        }
4336
0
        pos += U16_LENGTH(c);
4337
0
    }
4338
0
    return pos;
4339
0
}
4340
4341
//----------------------------------------------------------------------
4342
4343
// Lazy TimeZoneFormat instantiation, semantically const.
4344
TimeZoneFormat *
4345
0
SimpleDateFormat::tzFormat(UErrorCode &status) const {
4346
0
    Mutex m(&LOCK);
4347
0
    if (fTimeZoneFormat == nullptr && U_SUCCESS(status)) {
4348
0
        const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat =
4349
0
                TimeZoneFormat::createInstance(fLocale, status);
4350
0
    }
4351
0
    return fTimeZoneFormat;
4352
0
}
4353
4354
0
void SimpleDateFormat::parsePattern() {
4355
0
    fHasMinute = FALSE;
4356
0
    fHasSecond = FALSE;
4357
0
    fHasHanYearChar = FALSE;
4358
4359
0
    int len = fPattern.length();
4360
0
    UBool inQuote = FALSE;
4361
0
    for (int32_t i = 0; i < len; ++i) {
4362
0
        UChar ch = fPattern[i];
4363
0
        if (ch == QUOTE) {
4364
0
            inQuote = !inQuote;
4365
0
        }
4366
0
        if (ch == 0x5E74) { // don't care whether this is inside quotes
4367
0
            fHasHanYearChar = TRUE;
4368
0
        }
4369
0
        if (!inQuote) {
4370
0
            if (ch == 0x6D) {  // 0x6D == 'm'
4371
0
                fHasMinute = TRUE;
4372
0
            }
4373
0
            if (ch == 0x73) {  // 0x73 == 's'
4374
0
                fHasSecond = TRUE;
4375
0
            }
4376
0
        }
4377
0
    }
4378
0
}
4379
4380
U_NAMESPACE_END
4381
4382
#endif /* #if !UCONFIG_NO_FORMATTING */
4383
4384
//eof