#define ZID_KEY_MAX 128
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/smpdtfmt.h"
#include "unicode/dtfmtsym.h"
#include "unicode/ures.h"
#include "unicode/msgfmt.h"
#include "unicode/calendar.h"
#include "unicode/gregocal.h"
#include "unicode/timezone.h"
#include "unicode/decimfmt.h"
#include "unicode/dcfmtsym.h"
#include "unicode/uchar.h"
#include "unicode/uniset.h"
#include "unicode/ustring.h"
#include "unicode/basictz.h"
#include "unicode/simpleformatter.h"
#include "unicode/simpletz.h"
#include "unicode/rbtz.h"
#include "unicode/tzfmt.h"
#include "unicode/ucasemap.h"
#include "unicode/utf16.h"
#include "unicode/vtzone.h"
#include "unicode/udisplaycontext.h"
#include "unicode/brkiter.h"
#include "unicode/rbnf.h"
#include "unicode/dtptngen.h"
#include "uresimp.h"
#include "olsontz.h"
#include "patternprops.h"
#include "fphdlimp.h"
#include "hebrwcal.h"
#include "cstring.h"
#include "uassert.h"
#include "cmemory.h"
#include "umutex.h"
#include <float.h>
#include "smpdtfst.h"
#include "sharednumberformat.h"
#include "ucasemap_imp.h"
#include "ustr_imp.h"
#include "charstr.h"
#include "uvector.h"
#include "cstr.h"
#include "dayperiodrules.h"
#include "tznames_impl.h" // ZONE_NAME_U16_MAX
#include "number_utypes.h"
#include "dtptngen_impl.h" // for datePatternHasNumericCore()
#define DEBUG_SYNTHETIC_TIMEFMTS 0
#if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL) || DEBUG_SYNTHETIC_TIMEFMTS
#include <stdio.h>
#endif
U_NAMESPACE_BEGIN
typedef enum GmtPatSize {
kGmtLen = 3,
kGmtPatLen = 6,
kNegHmsLen = 9,
kNegHmLen = 6,
kPosHmsLen = 9,
kPosHmLen = 6,
kUtLen = 2,
kUtcLen = 3
} GmtPatSize;
typedef enum OvrStrType {
kOvrStrDate = 0,
kOvrStrTime = 1,
kOvrStrBoth = 2
} OvrStrType;
static const UDateFormatField kDateFields[] = {
UDAT_YEAR_FIELD,
UDAT_MONTH_FIELD,
UDAT_DATE_FIELD,
UDAT_DAY_OF_YEAR_FIELD,
UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
UDAT_WEEK_OF_YEAR_FIELD,
UDAT_WEEK_OF_MONTH_FIELD,
UDAT_YEAR_WOY_FIELD,
UDAT_EXTENDED_YEAR_FIELD,
UDAT_JULIAN_DAY_FIELD,
UDAT_STANDALONE_DAY_FIELD,
UDAT_STANDALONE_MONTH_FIELD,
UDAT_QUARTER_FIELD,
UDAT_STANDALONE_QUARTER_FIELD,
UDAT_YEAR_NAME_FIELD,
UDAT_RELATED_YEAR_FIELD };
static const int8_t kDateFieldsCount = 16;
static const UDateFormatField kTimeFields[] = {
UDAT_HOUR_OF_DAY1_FIELD,
UDAT_HOUR_OF_DAY0_FIELD,
UDAT_MINUTE_FIELD,
UDAT_SECOND_FIELD,
UDAT_FRACTIONAL_SECOND_FIELD,
UDAT_HOUR1_FIELD,
UDAT_HOUR0_FIELD,
UDAT_MILLISECONDS_IN_DAY_FIELD,
UDAT_TIMEZONE_RFC_FIELD,
UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD };
static const int8_t kTimeFieldsCount = 10;
static const UChar gDefaultPattern[] =
{
0x79, 0x79, 0x79, 0x79, 0x4D, 0x4D, 0x64, 0x64, 0x20, 0x68, 0x68, 0x3A, 0x6D, 0x6D, 0x20, 0x61, 0
};
static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0};
static const UChar QUOTE = 0x27;
static const int32_t gFieldRangeBias[] = {
-1, -1, 1, 0, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
-1, #else
-1, #endif
};
static const int32_t gFieldRangeBiasLenient[] = {
-1, -1, 8, 18, -1, -1, 40, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 18, 8, -1, -1, -1, -1, -1, -1, -1, -1, #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
-1, #else
-1, #endif
};
static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
static UMutex LOCK;
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
SimpleDateFormat::NSOverride::~NSOverride() {
if (snf != NULL) {
snf->removeRef();
}
}
void SimpleDateFormat::NSOverride::free() {
NSOverride *cur = this;
while (cur) {
NSOverride *next_temp = cur->next;
delete cur;
cur = next_temp;
}
}
static void fixNumberFormatForDates(NumberFormat &nf) {
nf.setDateSettings(); }
static const SharedNumberFormat *createSharedNumberFormat(
NumberFormat *nfToAdopt) {
fixNumberFormatForDates(*nfToAdopt);
const SharedNumberFormat *result = new SharedNumberFormat(nfToAdopt);
if (result == NULL) {
delete nfToAdopt;
}
return result;
}
static const SharedNumberFormat *createSharedNumberFormat(
const Locale &loc, UErrorCode &status) {
NumberFormat *nf = NumberFormat::createInstance(loc, status);
if (U_FAILURE(status)) {
return NULL;
}
const SharedNumberFormat *result = createSharedNumberFormat(nf);
if (result == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
return result;
}
static const SharedNumberFormat **allocSharedNumberFormatters() {
const SharedNumberFormat **result = (const SharedNumberFormat**)
uprv_malloc(UDAT_FIELD_COUNT * sizeof(const SharedNumberFormat*));
if (result == NULL) {
return NULL;
}
for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
result[i] = NULL;
}
return result;
}
static void freeSharedNumberFormatters(const SharedNumberFormat ** list) {
for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
SharedObject::clearPtr(list[i]);
}
uprv_free(list);
}
const NumberFormat *SimpleDateFormat::getNumberFormatByIndex(
UDateFormatField index) const {
if (fSharedNumberFormatters == NULL ||
fSharedNumberFormatters[index] == NULL) {
return fNumberFormat;
}
return &(**fSharedNumberFormatters[index]);
}
SimpleDateFormat::~SimpleDateFormat()
{
delete fSymbols;
if (fSharedNumberFormatters) {
freeSharedNumberFormatters(fSharedNumberFormatters);
}
if (fTimeZoneFormat) {
delete fTimeZoneFormat;
}
freeFastNumberFormatters();
#if !UCONFIG_NO_BREAK_ITERATION
delete fCapitalizationBrkIter;
#endif
}
SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
: fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
initializeDefaultCentury();
}
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
UErrorCode &status)
: fPattern(pattern),
fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
initializeBooleanAttributes();
initializeCalendar(NULL,fLocale,status);
fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
}
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
const UnicodeString& override,
UErrorCode &status)
: fPattern(pattern),
fLocale(Locale::getDefault()),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setTo(override);
fTimeOverride.setToBogus();
initializeBooleanAttributes();
initializeCalendar(NULL,fLocale,status);
fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
processOverrideString(fLocale,override,kOvrStrBoth,status);
}
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
const Locale& locale,
UErrorCode& status)
: fPattern(pattern),
fLocale(locale),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
initializeBooleanAttributes();
initializeCalendar(NULL,fLocale,status);
fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
}
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
const UnicodeString& override,
const Locale& locale,
UErrorCode& status)
: fPattern(pattern),
fLocale(locale),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setTo(override);
fTimeOverride.setToBogus();
initializeBooleanAttributes();
initializeCalendar(NULL,fLocale,status);
fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
processOverrideString(locale,override,kOvrStrBoth,status);
}
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
DateFormatSymbols* symbolsToAdopt,
UErrorCode& status)
: fPattern(pattern),
fLocale(Locale::getDefault()),
fSymbols(symbolsToAdopt),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
initializeBooleanAttributes();
initializeCalendar(NULL,fLocale,status);
initialize(fLocale, status);
initializeDefaultCentury();
}
SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
const DateFormatSymbols& symbols,
UErrorCode& status)
: fPattern(pattern),
fLocale(Locale::getDefault()),
fSymbols(new DateFormatSymbols(symbols)),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
initializeBooleanAttributes();
initializeCalendar(NULL, fLocale, status);
initialize(fLocale, status);
initializeDefaultCentury();
}
SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
EStyle dateStyle,
const Locale& locale,
UErrorCode& status)
: fLocale(locale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
construct(timeStyle, dateStyle, fLocale, status);
if(U_SUCCESS(status)) {
initializeDefaultCentury();
}
}
SimpleDateFormat::SimpleDateFormat(const Locale& locale,
UErrorCode& status)
: fPattern(gDefaultPattern),
fLocale(locale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
if (U_FAILURE(status)) return;
initializeBooleanAttributes();
initializeCalendar(NULL, fLocale, status);
fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
if (U_FAILURE(status))
{
status = U_ZERO_ERROR;
delete fSymbols;
fSymbols = new DateFormatSymbols(status);
if (fSymbols == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
}
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
initialize(fLocale, status);
if(U_SUCCESS(status)) {
initializeDefaultCentury();
}
}
SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
: DateFormat(other),
fLocale(other.fLocale),
fSymbols(NULL),
fTimeZoneFormat(NULL),
fSharedNumberFormatters(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
*this = other;
}
SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
{
if (this == &other) {
return *this;
}
freeFastNumberFormatters(); DateFormat::operator=(other);
fDateOverride = other.fDateOverride;
fTimeOverride = other.fTimeOverride;
delete fSymbols;
fSymbols = NULL;
if (other.fSymbols)
fSymbols = new DateFormatSymbols(*other.fSymbols);
fDefaultCenturyStart = other.fDefaultCenturyStart;
fDefaultCenturyStartYear = other.fDefaultCenturyStartYear;
fHaveDefaultCentury = other.fHaveDefaultCentury;
fPattern = other.fPattern;
fHasMinute = other.fHasMinute;
fHasSecond = other.fHasSecond;
fLocale = other.fLocale;
delete fTimeZoneFormat;
fTimeZoneFormat = NULL;
if (other.fTimeZoneFormat) {
fTimeZoneFormat = new TimeZoneFormat(*other.fTimeZoneFormat);
}
#if !UCONFIG_NO_BREAK_ITERATION
if (other.fCapitalizationBrkIter != NULL) {
fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();
}
#endif
if (fSharedNumberFormatters != NULL) {
freeSharedNumberFormatters(fSharedNumberFormatters);
fSharedNumberFormatters = NULL;
}
if (other.fSharedNumberFormatters != NULL) {
fSharedNumberFormatters = allocSharedNumberFormatters();
if (fSharedNumberFormatters) {
for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
SharedObject::copyPtr(
other.fSharedNumberFormatters[i],
fSharedNumberFormatters[i]);
}
}
}
UErrorCode localStatus = U_ZERO_ERROR;
initFastNumberFormatters(localStatus);
return *this;
}
SimpleDateFormat*
SimpleDateFormat::clone() const
{
return new SimpleDateFormat(*this);
}
UBool
SimpleDateFormat::operator==(const Format& other) const
{
if (DateFormat::operator==(other)) {
SimpleDateFormat* that = (SimpleDateFormat*)&other;
return (fPattern == that->fPattern &&
fSymbols != NULL && that->fSymbols != NULL && *fSymbols == *that->fSymbols &&
fHaveDefaultCentury == that->fHaveDefaultCentury &&
fDefaultCenturyStart == that->fDefaultCenturyStart &&
((fTimeZoneFormat == NULL && that->fTimeZoneFormat == NULL) ||
(fTimeZoneFormat != NULL && that->fTimeZoneFormat != NULL && *fTimeZoneFormat == *that->fTimeZoneFormat)) &&
fDateOverride == that->fDateOverride &&
fTimeOverride == that->fTimeOverride);
}
return FALSE;
}
static const UChar* timeSkeletons[4] = {
u"jmmsszzzz", u"jmmssz", u"jmmss", u"jmm", };
enum { kBaseNameMax = ULOC_LANG_CAPACITY + ULOC_SCRIPT_CAPACITY + ULOC_COUNTRY_CAPACITY };
void SimpleDateFormat::construct(EStyle timeStyle,
EStyle dateStyle,
const Locale& locale,
UErrorCode& status)
{
if (U_FAILURE(status)) return;
initializeCalendar(NULL, locale, status);
if (U_FAILURE(status)) return;
const char* cType = fCalendar ? fCalendar->getType() : NULL;
UBool fallingBackByCountry = FALSE;
LocalUResourceBundlePointer bundle(ures_open(NULL, locale.getBaseName(), &status));
LocalUResourceBundlePointer countryBundle(ures_openWithCountryFallback(NULL, locale.getBaseName(), &fallingBackByCountry, &status));
if (U_FAILURE(status)) return;
if (fallingBackByCountry) {
int32_t dummy = -1;
const UChar* languageLocaleNumbers = ures_getStringByKeyWithFallback(bundle.getAlias(), "NumberElements/default", &dummy, &status);
const UChar* countryLocaleNumbers = ures_getStringByKeyWithFallback(countryBundle.getAlias(), "NumberElements/default", &dummy, &status);
if (U_FAILURE(status) || u_strcmp(languageLocaleNumbers, countryLocaleNumbers) != 0) {
fallingBackByCountry = FALSE;
}
}
UBool cTypeIsGregorian = TRUE;
LocalUResourceBundlePointer dateTimePatterns;
LocalUResourceBundlePointer countryDateTimePatterns;
if (cType != NULL && uprv_strcmp(cType, "gregorian") != 0) {
CharString resourcePath("calendar/", status);
resourcePath.append(cType, status).append("/DateTimePatterns", status);
dateTimePatterns.adoptInstead(
ures_getByKeyWithFallback(bundle.getAlias(), resourcePath.data(),
(UResourceBundle*)NULL, &status));
countryDateTimePatterns.adoptInstead(
ures_getByKeyWithFallback(countryBundle.getAlias(), resourcePath.data(),
(UResourceBundle*)NULL, &status));
cTypeIsGregorian = FALSE;
}
if (cTypeIsGregorian || status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
dateTimePatterns.adoptInstead(
ures_getByKeyWithFallback(bundle.getAlias(),
"calendar/gregorian/DateTimePatterns",
(UResourceBundle*)NULL, &status));
countryDateTimePatterns.adoptInstead(
ures_getByKeyWithFallback(countryBundle.getAlias(),
"calendar/gregorian/DateTimePatterns",
(UResourceBundle*)NULL, &status));
}
if (U_FAILURE(status)) return;
if (ures_getSize(dateTimePatterns.getAlias()) <= kDateTime)
{
status = U_INVALID_FORMAT_ERROR;
return;
}
setLocaleIDs(ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_VALID_LOCALE, &status),
ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_ACTUAL_LOCALE, &status));
fSymbols = DateFormatSymbols::createForLocale(locale, status);
if (U_FAILURE(status)) return;
if (fSymbols == 0) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
if ((timeStyle != kNone) && (dateStyle != kNone))
{
UnicodeString ovrStr;
UnicodeString tempus1 = getPatternForTimeStyle(timeStyle, locale, dateTimePatterns.getAlias(), ovrStr, status);
if (!ovrStr.isEmpty()) {
fTimeOverride = ovrStr;
}
UnicodeString tempus2 = getPatternForDateStyle(dateStyle, dateTimePatterns.getAlias(), countryDateTimePatterns.getAlias(), fallingBackByCountry, ovrStr, status);
if (!ovrStr.isEmpty()) {
fDateOverride = ovrStr;
}
int32_t glueIndex = kDateTime;
int32_t patternsSize = ures_getSize(dateTimePatterns.getAlias());
if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset));
}
UnicodeString resStr(ures_getUnicodeStringByIndex(dateTimePatterns.getAlias(), glueIndex, &status));
SimpleFormatter(resStr, 2, 2, status).
format(tempus1, tempus2, fPattern, status);
}
else if (timeStyle != kNone) {
UnicodeString ovrStr;
UnicodeString timePattern = getPatternForTimeStyle(timeStyle, locale, dateTimePatterns.getAlias(), ovrStr, status);
if (!ovrStr.isEmpty()) {
fDateOverride = ovrStr; }
fPattern = timePattern;
}
else if (dateStyle != kNone) {
UnicodeString ovrStr;
UnicodeString datePattern = getPatternForDateStyle(dateStyle, dateTimePatterns.getAlias(), countryDateTimePatterns.getAlias(), fallingBackByCountry, ovrStr, status);
if (!ovrStr.isEmpty()) {
fDateOverride = ovrStr;
}
fPattern = datePattern;
}
else
status = U_INVALID_FORMAT_ERROR;
initialize(locale, status);
}
UnicodeString
SimpleDateFormat::getPatternForTimeStyle(EStyle timeStyle,
const Locale& locale,
UResourceBundle* dateTimePatterns,
UnicodeString& ovrStr,
UErrorCode& status) {
UnicodeString timePattern;
if (timeStyle >= kFull && timeStyle <= kShort) {
const char* baseLoc = locale.getBaseName();
if (baseLoc!=NULL && baseLoc[0]!=0 && uprv_strcmp(baseLoc,"und")!=0) {
UErrorCode useStatus = U_ZERO_ERROR;
const char* validLoc = getLocaleID(ULOC_VALID_LOCALE, useStatus);
if (U_SUCCESS(useStatus) && uprv_strcmp(validLoc,baseLoc)!=0) {
char minLoc[kBaseNameMax];
uloc_minimizeSubtags(baseLoc, minLoc, kBaseNameMax, &useStatus);
minLoc[kBaseNameMax-1] = 0; const char* actualLoc = getLocaleID(ULOC_ACTUAL_LOCALE, useStatus);
if (U_SUCCESS(useStatus) && uprv_strcmp(actualLoc,minLoc)!=0) {
LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstance(locale, useStatus, TRUE));
if (U_SUCCESS(useStatus)) {
UnicodeString timeSkeleton(TRUE, timeSkeletons[timeStyle], -1);
timePattern = dtpg->getBestPattern(timeSkeleton, useStatus);
#if DEBUG_SYNTHETIC_TIMEFMTS
if (timePattern.length() != 0) {
char bbuf[32];
timePattern.extract(0,timePattern.length(),bbuf,32);
printf("\n## for locale %s, validLoc %s, minLoc %s, actualLoc %s, synth timePat %s\n", locale.getName(), validLoc, minLoc, actualLoc, bbuf);
}
#endif
}
}
}
}
}
if (timePattern.isEmpty()) {
timePattern = getPatternString((int32_t)timeStyle, dateTimePatterns, ovrStr, status);
}
return timePattern;
}
UnicodeString
SimpleDateFormat::getPatternForDateStyle(EStyle dateStyle,
UResourceBundle* languageDateTimePatterns,
UResourceBundle* countryDateTimePatterns,
UBool& fallingBackByCountry,
UnicodeString& ovrStr,
UErrorCode& status) {
UnicodeString languageOverride;
UnicodeString languagePattern = getPatternString((int32_t)dateStyle, languageDateTimePatterns, languageOverride, status);
UnicodeString result = languagePattern;
ovrStr = languageOverride;
if (fallingBackByCountry) {
fallingBackByCountry = FALSE;
if ((dateStyle == kDateOffset + kMedium || dateStyle == kDateOffset + kShort)) {
UnicodeString countryOverride;
UnicodeString countryPattern = getPatternString((int32_t)dateStyle, countryDateTimePatterns, countryOverride, status);
UBool stripRTLmarks = uloc_isRightToLeft(ures_getLocaleByType(countryDateTimePatterns, ULOC_ACTUAL_LOCALE, &status)) && !uloc_isRightToLeft(ures_getLocaleByType(languageDateTimePatterns, ULOC_ACTUAL_LOCALE, &status));
if (U_SUCCESS(status)) {
if (datePatternHasNumericCore(countryPattern)) {
ovrStr = countryOverride;
result = countryPattern;
fallingBackByCountry = TRUE;
if (stripRTLmarks) {
result.findAndReplace(UnicodeString(u'\u200f'), UnicodeString());
}
} else if (dateStyle == kDateOffset + kMedium && datePatternHasNumericCore(languagePattern)) {
countryPattern = getPatternString(kDateOffset + kShort, countryDateTimePatterns, countryOverride, status);
if (datePatternHasNumericCore(countryPattern)) {
ovrStr = countryOverride;
result = countryPattern;
fallingBackByCountry = TRUE;
if (stripRTLmarks) {
result.findAndReplace(UnicodeString(u'\u200f'), UnicodeString());
}
}
}
}
}
}
return result;
}
UnicodeString
SimpleDateFormat::getPatternString(int32_t index,
UResourceBundle* dateTimePatterns,
UnicodeString& ovrStr,
UErrorCode& status) {
UnicodeString resStr;
LocalUResourceBundlePointer currentBundle(ures_getByIndex(dateTimePatterns, index, NULL, &status));
ovrStr.remove();
if (U_FAILURE(status)) {
status = U_INVALID_FORMAT_ERROR;
return resStr;
}
switch (ures_getType(currentBundle.getAlias())) {
case URES_STRING: {
resStr = ures_getUnicodeString(currentBundle.getAlias(), &status);
break;
}
case URES_ARRAY: {
resStr = ures_getUnicodeStringByIndex(currentBundle.getAlias(), 0, &status);
ovrStr = ures_getUnicodeStringByIndex(currentBundle.getAlias(), 1, &status);
break;
}
default: {
status = U_INVALID_FORMAT_ERROR;
return resStr;
}
}
return resStr;
}
Calendar*
SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)
{
if(!U_FAILURE(status)) {
fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
}
return fCalendar;
}
void
SimpleDateFormat::initialize(const Locale& locale,
UErrorCode& status)
{
if (U_FAILURE(status)) return;
parsePattern();
static const UChar hanidaysOverride[] = {0x64,0x3D,0x68,0x61,0x6E,0x69,0x64,0x61,0x79,0x73,0}; char numbersValue[ULOC_KEYWORDS_CAPACITY];
UErrorCode numbersStatus = U_ZERO_ERROR;
Locale localeNoHanidays(locale);
int32_t numbersLen = localeNoHanidays.getKeywordValue("numbers", numbersValue, ULOC_KEYWORDS_CAPACITY, numbersStatus);
if ( U_SUCCESS(numbersStatus) && numbersLen > 0 ) {
if ( uprv_strcmp(numbersValue, "hanidays") == 0 ) {
localeNoHanidays.setKeywordValue("numbers", NULL, numbersStatus);
fDateOverride.setTo(hanidaysOverride,-1);
}
}
if (fDateOverride.isBogus() && fHasHanYearChar &&
fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
fDateOverride.setTo(u"y=jpanyear", -1);
}
fNumberFormat = NumberFormat::createInstance(localeNoHanidays, status);
if (fNumberFormat != NULL && U_SUCCESS(status))
{
fixNumberFormatForDates(*fNumberFormat);
initNumberFormatters(locale, status);
initFastNumberFormatters(status);
}
else if (U_SUCCESS(status))
{
status = U_MISSING_RESOURCE_ERROR;
}
}
void SimpleDateFormat::initializeDefaultCentury()
{
if(fCalendar) {
fHaveDefaultCentury = fCalendar->haveDefaultCentury();
if(fHaveDefaultCentury) {
fDefaultCenturyStart = fCalendar->defaultCenturyStart();
fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear();
} else {
fDefaultCenturyStart = DBL_MIN;
fDefaultCenturyStartYear = -1;
}
}
}
void SimpleDateFormat::initializeBooleanAttributes()
{
UErrorCode status = U_ZERO_ERROR;
setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status);
setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status);
setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, true, status);
setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, true, status);
}
void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)
{
if(U_FAILURE(status)) {
return;
}
if(!fCalendar) {
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
fCalendar->setTime(startDate, status);
if(U_SUCCESS(status)) {
fHaveDefaultCentury = TRUE;
fDefaultCenturyStart = startDate;
fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status);
}
}
UnicodeString&
SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const
{
UErrorCode status = U_ZERO_ERROR;
FieldPositionOnlyHandler handler(pos);
return _format(cal, appendTo, handler, status);
}
UnicodeString&
SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,
FieldPositionIterator* posIter, UErrorCode& status) const
{
FieldPositionIteratorHandler handler(posIter, status);
return _format(cal, appendTo, handler, status);
}
UnicodeString&
SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
FieldPositionHandler& handler, UErrorCode& status) const
{
if ( U_FAILURE(status) ) {
return appendTo;
}
Calendar* workCal = &cal;
Calendar* calClone = NULL;
if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
calClone = fCalendar->clone();
if (calClone != NULL) {
UDate t = cal.getTime(status);
calClone->setTime(t, status);
calClone->setTimeZone(cal.getTimeZone());
workCal = calClone;
} else {
status = U_MEMORY_ALLOCATION_ERROR;
return appendTo;
}
}
UBool inQuote = FALSE;
UChar prevCh = 0;
int32_t count = 0;
int32_t fieldNum = 0;
UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
UChar ch = fPattern[i];
if (ch != prevCh && count > 0) {
subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
count = 0;
}
if (ch == QUOTE) {
if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) {
appendTo += (UChar)QUOTE;
++i;
} else {
inQuote = ! inQuote;
}
}
else if (!inQuote && isSyntaxChar(ch)) {
prevCh = ch;
++count;
}
else {
appendTo += ch;
}
}
if (count > 0) {
subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
}
if (calClone != NULL) {
delete calClone;
}
return appendTo;
}
const int32_t
SimpleDateFormat::fgCalendarFieldToLevel[] =
{
0, 10, 20,
20, 30,
30, 20, 30, 30,
40, 50, 50, 60,
70, 80,
0, 0, 10,
30, 10, 0,
40, 0, 0
};
int32_t SimpleDateFormat::getLevelFromChar(UChar ch) {
static const int32_t mapCharToLevel[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1,
#else
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
#endif
-1, 40, -1, -1, 20, 30, 30, 0, 50, -1, -1, 50, 20, 20, -1, 0,
-1, 20, -1, 80, -1, 10, 0, 30, 0, 10, 0, -1, -1, -1, -1, -1,
-1, 40, -1, 30, 30, 30, -1, 0, 50, -1, -1, 50, 0, 60, -1, -1,
-1, 20, 10, 70, -1, 10, 0, 20, 0, 10, 0, -1, -1, -1, -1, -1
};
return ch < UPRV_LENGTHOF(mapCharToLevel) ? mapCharToLevel[ch] : -1;
}
UBool SimpleDateFormat::isSyntaxChar(UChar ch) {
static const UBool mapCharToIsSyntax[] = {
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
#else
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
#endif
FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE
};
return ch < UPRV_LENGTHOF(mapCharToIsSyntax) ? mapCharToIsSyntax[ch] : FALSE;
}
const UCalendarDateFields
SimpleDateFormat::fgPatternIndexToCalendarField[] =
{
UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY,
UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND,
UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH,
UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM,
UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET,
UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR,
UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET,
UCAL_ZONE_OFFSET,
UCAL_DOW_LOCAL,
UCAL_MONTH,
UCAL_MONTH,
UCAL_MONTH,
UCAL_ZONE_OFFSET,
UCAL_YEAR,
UCAL_ZONE_OFFSET,
UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,
UCAL_EXTENDED_YEAR,
UCAL_FIELD_COUNT, UCAL_FIELD_COUNT, #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
UCAL_FIELD_COUNT,
#else
UCAL_FIELD_COUNT,
#endif
};
const UDateFormatField
SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD,
UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD,
UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD,
UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD,
UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD,
UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD,
UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD,
UDAT_TIMEZONE_GENERIC_FIELD,
UDAT_STANDALONE_DAY_FIELD,
UDAT_STANDALONE_MONTH_FIELD,
UDAT_QUARTER_FIELD,
UDAT_STANDALONE_QUARTER_FIELD,
UDAT_TIMEZONE_SPECIAL_FIELD,
UDAT_YEAR_NAME_FIELD,
UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD,
UDAT_RELATED_YEAR_FIELD,
UDAT_AM_PM_MIDNIGHT_NOON_FIELD, UDAT_FLEXIBLE_DAY_PERIOD_FIELD,
#if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
UDAT_TIME_SEPARATOR_FIELD,
#else
UDAT_TIME_SEPARATOR_FIELD,
#endif
};
static inline void
_appendSymbol(UnicodeString& dst,
int32_t value,
const UnicodeString* symbols,
int32_t symbolsCount) {
U_ASSERT(0 <= value && value < symbolsCount);
if (0 <= value && value < symbolsCount) {
dst += symbols[value];
}
}
static inline void
_appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount,
const UnicodeString* monthPattern, UErrorCode& status) {
U_ASSERT(0 <= value && value < symbolsCount);
if (0 <= value && value < symbolsCount) {
if (monthPattern == NULL) {
dst += symbols[value];
} else {
SimpleFormatter(*monthPattern, 1, 1, status).format(symbols[value], dst, status);
}
}
}
static number::LocalizedNumberFormatter*
createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt, UErrorCode& status) {
const number::LocalizedNumberFormatter* lnfBase = df->toNumberFormatter(status);
if (U_FAILURE(status)) {
return nullptr;
}
return lnfBase->integerWidth(
number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt)
).clone().orphan();
}
void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
auto* df = dynamic_cast<DecimalFormat*>(fNumberFormat);
if (df == nullptr) {
return;
}
df->setDFSShallowCopy(TRUE);
fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10, status);
fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10, status);
fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10, status);
fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10, status);
fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2, status);
df->setDFSShallowCopy(FALSE);
}
void SimpleDateFormat::freeFastNumberFormatters() {
delete fFastNumberFormatters[SMPDTFMT_NF_1x10];
delete fFastNumberFormatters[SMPDTFMT_NF_2x10];
delete fFastNumberFormatters[SMPDTFMT_NF_3x10];
delete fFastNumberFormatters[SMPDTFMT_NF_4x10];
delete fFastNumberFormatters[SMPDTFMT_NF_2x2];
fFastNumberFormatters[SMPDTFMT_NF_1x10] = nullptr;
fFastNumberFormatters[SMPDTFMT_NF_2x10] = nullptr;
fFastNumberFormatters[SMPDTFMT_NF_3x10] = nullptr;
fFastNumberFormatters[SMPDTFMT_NF_4x10] = nullptr;
fFastNumberFormatters[SMPDTFMT_NF_2x2] = nullptr;
}
void
SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
if (U_FAILURE(status)) {
return;
}
if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
return;
}
umtx_lock(&LOCK);
if (fSharedNumberFormatters == NULL) {
fSharedNumberFormatters = allocSharedNumberFormatters();
if (fSharedNumberFormatters == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
umtx_unlock(&LOCK);
if (U_FAILURE(status)) {
return;
}
processOverrideString(locale,fDateOverride,kOvrStrDate,status);
processOverrideString(locale,fTimeOverride,kOvrStrTime,status);
}
void
SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) {
if (str.isBogus() || U_FAILURE(status)) {
return;
}
int32_t start = 0;
int32_t len;
UnicodeString nsName;
UnicodeString ovrField;
UBool moreToProcess = TRUE;
NSOverride *overrideList = NULL;
while (moreToProcess) {
int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
if (delimiterPosition == -1) {
moreToProcess = FALSE;
len = str.length() - start;
} else {
len = delimiterPosition - start;
}
UnicodeString currentString(str,start,len);
int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0);
if (equalSignPosition == -1) { nsName.setTo(currentString);
ovrField.setToBogus();
} else { nsName.setTo(currentString,equalSignPosition+1);
ovrField.setTo(currentString,0,1); }
int32_t nsNameHash = nsName.hashCode();
NSOverride *curr = overrideList;
const SharedNumberFormat *snf = NULL;
UBool found = FALSE;
while ( curr && !found ) {
if ( curr->hash == nsNameHash ) {
snf = curr->snf;
found = TRUE;
}
curr = curr->next;
}
if (!found) {
LocalPointer<NSOverride> cur(new NSOverride);
if (!cur.isNull()) {
char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
uprv_strcpy(kw,"numbers=");
nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);
cur->hash = nsNameHash;
cur->next = overrideList;
SharedObject::copyPtr(
createSharedNumberFormat(ovrLoc, status), cur->snf);
if (U_FAILURE(status)) {
if (overrideList) {
overrideList->free();
}
return;
}
snf = cur->snf;
overrideList = cur.orphan();
} else {
status = U_MEMORY_ALLOCATION_ERROR;
if (overrideList) {
overrideList->free();
}
return;
}
}
if (ovrField.isBogus()) {
switch (type) {
case kOvrStrDate:
case kOvrStrBoth: {
for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
SharedObject::copyPtr(snf, fSharedNumberFormatters[kDateFields[i]]);
}
if (type==kOvrStrDate) {
break;
}
U_FALLTHROUGH;
}
case kOvrStrTime : {
for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
SharedObject::copyPtr(snf, fSharedNumberFormatters[kTimeFields[i]]);
}
break;
}
}
} else {
UDateFormatField patternCharIndex =
DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0));
if (patternCharIndex == UDAT_FIELD_COUNT) {
status = U_INVALID_FORMAT_ERROR;
if (overrideList) {
overrideList->free();
}
return;
}
SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
}
start = delimiterPosition + 1;
}
if (overrideList) {
overrideList->free();
}
}
void
SimpleDateFormat::subFormat(UnicodeString &appendTo,
UChar ch,
int32_t count,
UDisplayContext capitalizationContext,
int32_t fieldNum,
FieldPositionHandler& handler,
Calendar& cal,
UErrorCode& status) const
{
if (U_FAILURE(status)) {
return;
}
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
const int32_t maxIntCount = 10;
int32_t beginOffset = appendTo.length();
const NumberFormat *currentNumberFormat;
DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;
UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0);
UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);
if (patternCharIndex == UDAT_FIELD_COUNT)
{
if (ch != 0x6C) { status = U_INVALID_FORMAT_ERROR;
}
return;
}
UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
int32_t value = 0;
if (field < UCAL_FIELD_COUNT) {
value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status);
}
if (U_FAILURE(status)) {
return;
}
currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
if (currentNumberFormat == NULL) {
status = U_INTERNAL_PROGRAM_ERROR;
return;
}
UnicodeString hebr("hebr", 4, US_INV);
switch (patternCharIndex) {
case UDAT_ERA_FIELD:
if (isChineseCalendar) {
zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); } else {
if (count == 5) {
_appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow;
} else if (count == 4) {
_appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide;
} else {
_appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev;
}
}
break;
case UDAT_YEAR_NAME_FIELD:
if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) {
_appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount);
break;
}
U_FALLTHROUGH;
case UDAT_YEAR_FIELD:
case UDAT_YEAR_WOY_FIELD:
if (fDateOverride.compare(hebr)==0 && value>HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value<HEBREW_CAL_CUR_MILLENIUM_END_YEAR) {
value-=HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
}
if(count == 2)
zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2);
else
zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount);
break;
case UDAT_MONTH_FIELD:
case UDAT_STANDALONE_MONTH_FIELD:
if ( isHebrewCalendar ) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
value = 13; if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
value--; }
{
int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)?
cal.get(UCAL_IS_LEAP_MONTH, status): 0;
if (count == 5) {
if (patternCharIndex == UDAT_MONTH_FIELD) {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): NULL, status);
} else {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): NULL, status);
}
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow;
} else if (count == 4) {
if (patternCharIndex == UDAT_MONTH_FIELD) {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): NULL, status);
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
} else {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): NULL, status);
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
}
} else if (count == 3) {
if (patternCharIndex == UDAT_MONTH_FIELD) {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): NULL, status);
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
} else {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): NULL, status);
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
}
} else {
UnicodeString monthNumber;
zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount);
_appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): NULL, status);
}
}
break;
case UDAT_HOUR_OF_DAY1_FIELD:
if (value == 0)
zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
else
zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
break;
case UDAT_FRACTIONAL_SECOND_FIELD:
{
int32_t minDigits = (count > 3) ? 3 : count;
if (count == 1) {
value /= 100;
} else if (count == 2) {
value /= 10;
}
zeroPaddingNumber(currentNumberFormat, appendTo, value, minDigits, maxIntCount);
if (count > 3) {
zeroPaddingNumber(currentNumberFormat, appendTo, 0, count - 3, maxIntCount);
}
}
break;
case UDAT_DOW_LOCAL_FIELD:
if ( count < 3 ) {
zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
break;
}
value = cal.get(UCAL_DAY_OF_WEEK, status);
if (U_FAILURE(status)) {
return;
}
U_FALLTHROUGH;
case UDAT_DAY_OF_WEEK_FIELD:
if (count == 5) {
_appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
fSymbols->fNarrowWeekdaysCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
} else if (count == 4) {
_appendSymbol(appendTo, value, fSymbols->fWeekdays,
fSymbols->fWeekdaysCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
} else if (count == 6) {
_appendSymbol(appendTo, value, fSymbols->fShorterWeekdays,
fSymbols->fShorterWeekdaysCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
} else {
_appendSymbol(appendTo, value, fSymbols->fShortWeekdays,
fSymbols->fShortWeekdaysCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
}
break;
case UDAT_STANDALONE_DAY_FIELD:
if ( count < 3 ) {
zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount);
break;
}
value = cal.get(UCAL_DAY_OF_WEEK, status);
if (U_FAILURE(status)) {
return;
}
if (count == 5) {
_appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,
fSymbols->fStandaloneNarrowWeekdaysCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
} else if (count == 4) {
_appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
fSymbols->fStandaloneWeekdaysCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
} else if (count == 6) {
_appendSymbol(appendTo, value, fSymbols->fStandaloneShorterWeekdays,
fSymbols->fStandaloneShorterWeekdaysCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
} else { _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,
fSymbols->fStandaloneShortWeekdaysCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
}
break;
case UDAT_AM_PM_FIELD:
if (count < 5) {
_appendSymbol(appendTo, value, fSymbols->fAmPms,
fSymbols->fAmPmsCount);
} else {
_appendSymbol(appendTo, value, fSymbols->fNarrowAmPms,
fSymbols->fNarrowAmPmsCount);
}
break;
case UDAT_TIME_SEPARATOR_FIELD:
{
UnicodeString separator;
appendTo += fSymbols->getTimeSeparatorString(separator);
}
break;
case UDAT_HOUR1_FIELD:
if (value == 0)
zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
else
zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
break;
case UDAT_TIMEZONE_FIELD: case UDAT_TIMEZONE_RFC_FIELD: case UDAT_TIMEZONE_GENERIC_FIELD: case UDAT_TIMEZONE_SPECIAL_FIELD: case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: case UDAT_TIMEZONE_ISO_FIELD: case UDAT_TIMEZONE_ISO_LOCAL_FIELD: {
UChar zsbuf[ZONE_NAME_U16_MAX];
UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf));
const TimeZone& tz = cal.getTimeZone();
UDate date = cal.getTime(status);
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
if (count < 4) {
tzfmt->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
} else {
tzfmt->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
}
}
else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) {
if (count < 4) {
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
} else if (count == 5) {
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
} else {
tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
}
}
else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
if (count == 1) {
tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
} else if (count == 4) {
tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
}
}
else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) {
if (count == 1) {
tzfmt->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
} else if (count == 2) {
tzfmt->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
} else if (count == 3) {
tzfmt->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
} else if (count == 4) {
tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;
}
}
else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) {
if (count == 1) {
tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
} else if (count == 4) {
tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
}
}
else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) {
if (count == 1) {
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
} else if (count == 2) {
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
} else if (count == 3) {
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
} else if (count == 4) {
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
} else if (count == 5) {
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
}
}
else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) {
if (count == 1) {
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString);
} else if (count == 2) {
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString);
} else if (count == 3) {
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString);
} else if (count == 4) {
tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
} else if (count == 5) {
tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
}
}
else {
UPRV_UNREACHABLE;
}
}
appendTo += zoneString;
}
break;
case UDAT_QUARTER_FIELD:
if (count >= 4)
_appendSymbol(appendTo, value/3, fSymbols->fQuarters,
fSymbols->fQuartersCount);
else if (count == 3)
_appendSymbol(appendTo, value/3, fSymbols->fShortQuarters,
fSymbols->fShortQuartersCount);
else
zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
break;
case UDAT_STANDALONE_QUARTER_FIELD:
if (count >= 4)
_appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,
fSymbols->fStandaloneQuartersCount);
else if (count == 3)
_appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters,
fSymbols->fStandaloneShortQuartersCount);
else
zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
break;
case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
{
const UnicodeString *toAppend = NULL;
int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
if (( hour == 12) &&
(!fHasMinute || cal.get(UCAL_MINUTE, status) == 0) &&
(!fHasSecond || cal.get(UCAL_SECOND, status) == 0)) {
int32_t val = cal.get(UCAL_AM_PM, status);
if (count <= 3) {
toAppend = &fSymbols->fAbbreviatedDayPeriods[val];
} else if (count == 4 || count > 5) {
toAppend = &fSymbols->fWideDayPeriods[val];
} else { toAppend = &fSymbols->fNarrowDayPeriods[val];
}
}
if (toAppend == NULL || toAppend->isBogus()) {
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, status);
} else {
appendTo += *toAppend;
}
break;
}
case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
{
const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
if (U_FAILURE(status)) {
break;
}
if (ruleSet == NULL) {
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, status);
break;
}
int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
int32_t minute = 0;
if (fHasMinute) {
minute = cal.get(UCAL_MINUTE, status);
}
int32_t second = 0;
if (fHasSecond) {
second = cal.get(UCAL_SECOND, status);
}
DayPeriodRules::DayPeriod periodType;
if (hour == 0 && minute == 0 && second == 0 && ruleSet->hasMidnight()) {
periodType = DayPeriodRules::DAYPERIOD_MIDNIGHT;
} else if (hour == 12 && minute == 0 && second == 0 && ruleSet->hasNoon()) {
periodType = DayPeriodRules::DAYPERIOD_NOON;
} else {
periodType = ruleSet->getDayPeriodForHour(hour);
}
U_ASSERT(periodType != DayPeriodRules::DAYPERIOD_UNKNOWN);
UnicodeString *toAppend = NULL;
int32_t index;
if (periodType != DayPeriodRules::DAYPERIOD_AM &&
periodType != DayPeriodRules::DAYPERIOD_PM &&
periodType != DayPeriodRules::DAYPERIOD_MIDNIGHT) {
index = (int32_t)periodType;
if (count <= 3) {
toAppend = &fSymbols->fAbbreviatedDayPeriods[index]; } else if (count == 4 || count > 5) {
toAppend = &fSymbols->fWideDayPeriods[index];
} else { toAppend = &fSymbols->fNarrowDayPeriods[index];
}
}
if ((toAppend == NULL || toAppend->isBogus()) &&
(periodType == DayPeriodRules::DAYPERIOD_MIDNIGHT ||
periodType == DayPeriodRules::DAYPERIOD_NOON)) {
periodType = ruleSet->getDayPeriodForHour(hour);
index = (int32_t)periodType;
if (count <= 3) {
toAppend = &fSymbols->fAbbreviatedDayPeriods[index]; } else if (count == 4 || count > 5) {
toAppend = &fSymbols->fWideDayPeriods[index];
} else { toAppend = &fSymbols->fNarrowDayPeriods[index];
}
}
if (periodType == DayPeriodRules::DAYPERIOD_AM ||
periodType == DayPeriodRules::DAYPERIOD_PM ||
toAppend->isBogus()) {
subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
handler, cal, status);
}
else {
appendTo += *toAppend;
}
break;
}
default:
zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
break;
}
#if !UCONFIG_NO_BREAK_ITERATION
if (fieldNum == 0 && fCapitalizationBrkIter != NULL && appendTo.length() > beginOffset &&
u_islower(appendTo.char32At(beginOffset))) {
UBool titlecase = FALSE;
switch (capitalizationContext) {
case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
titlecase = TRUE;
break;
case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU:
titlecase = fSymbols->fCapitalization[capContextUsageType][0];
break;
case UDISPCTX_CAPITALIZATION_FOR_STANDALONE:
titlecase = fSymbols->fCapitalization[capContextUsageType][1];
break;
default:
break;
}
if (titlecase) {
BreakIterator* const mutableCapitalizationBrkIter = fCapitalizationBrkIter->clone();
UnicodeString firstField(appendTo, beginOffset);
firstField.toTitle(mutableCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);
delete mutableCapitalizationBrkIter;
}
}
#endif
handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length());
}
void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
fixNumberFormatForDates(*formatToAdopt);
freeFastNumberFormatters(); delete fNumberFormat;
fNumberFormat = formatToAdopt;
if (fSharedNumberFormatters) {
freeSharedNumberFormatters(fSharedNumberFormatters);
fSharedNumberFormatters = NULL;
}
UErrorCode localStatus = U_ZERO_ERROR;
initFastNumberFormatters(localStatus);
}
void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){
fixNumberFormatForDates(*formatToAdopt);
LocalPointer<NumberFormat> fmt(formatToAdopt);
if (U_FAILURE(status)) {
return;
}
if (fSharedNumberFormatters == NULL) {
fSharedNumberFormatters = allocSharedNumberFormatters();
if (fSharedNumberFormatters == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
}
const SharedNumberFormat *newFormat = createSharedNumberFormat(fmt.orphan());
if (newFormat == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
return;
}
for (int i=0; i<fields.length(); i++) {
UChar field = fields.charAt(i);
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(field);
if (patternCharIndex == UDAT_FIELD_COUNT) {
status = U_INVALID_FORMAT_ERROR;
newFormat->deleteIfZeroRefCount();
return;
}
SharedObject::copyPtr(
newFormat, fSharedNumberFormatters[patternCharIndex]);
}
newFormat->deleteIfZeroRefCount();
}
const NumberFormat *
SimpleDateFormat::getNumberFormatForField(UChar field) const {
UDateFormatField index = DateFormatSymbols::getPatternCharIndex(field);
if (index == UDAT_FIELD_COUNT) {
return NULL;
}
return getNumberFormatByIndex(index);
}
void
SimpleDateFormat::zeroPaddingNumber(
const NumberFormat *currentNumberFormat,
UnicodeString &appendTo,
int32_t value, int32_t minDigits, int32_t maxDigits) const
{
const number::LocalizedNumberFormatter* fastFormatter = nullptr;
if (currentNumberFormat == fNumberFormat) {
if (maxDigits == 10) {
if (minDigits == 1) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_1x10];
} else if (minDigits == 2) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x10];
} else if (minDigits == 3) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_3x10];
} else if (minDigits == 4) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_4x10];
}
} else if (maxDigits == 2) {
if (minDigits == 2) {
fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x2];
}
}
}
if (fastFormatter != nullptr) {
number::impl::UFormattedNumberData result;
result.quantity.setToInt(value);
UErrorCode localStatus = U_ZERO_ERROR;
fastFormatter->formatImpl(&result, localStatus);
if (U_FAILURE(localStatus)) {
return;
}
appendTo.append(result.getStringRef().toTempUnicodeString());
return;
}
auto* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(currentNumberFormat);
if (rbnf != nullptr) {
FieldPosition pos(FieldPosition::DONT_CARE);
rbnf->format(value, appendTo, pos); return;
}
if (currentNumberFormat != nullptr) {
FieldPosition pos(FieldPosition::DONT_CARE);
LocalPointer<NumberFormat> nf(currentNumberFormat->clone());
nf->setMinimumIntegerDigits(minDigits);
nf->setMaximumIntegerDigits(maxDigits);
nf->format(value, appendTo, pos); }
}
UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) {
return DateFormatSymbols::isNumericPatternChar(formatChar, count);
}
UBool
SimpleDateFormat::isAtNumericField(const UnicodeString &pattern, int32_t patternOffset) {
if (patternOffset >= pattern.length()) {
return FALSE;
}
UChar ch = pattern.charAt(patternOffset);
UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
if (f == UDAT_FIELD_COUNT) {
return FALSE;
}
int32_t i = patternOffset;
while (pattern.charAt(++i) == ch) {}
return DateFormatSymbols::isNumericField(f, i - patternOffset);
}
UBool
SimpleDateFormat::isAfterNonNumericField(const UnicodeString &pattern, int32_t patternOffset) {
if (patternOffset <= 0) {
return FALSE;
}
UChar ch = pattern.charAt(--patternOffset);
UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
if (f == UDAT_FIELD_COUNT) {
return FALSE;
}
int32_t i = patternOffset;
while (pattern.charAt(--i) == ch) {}
return !DateFormatSymbols::isNumericField(f, patternOffset - i);
}
void
SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const
{
UErrorCode status = U_ZERO_ERROR;
int32_t pos = parsePos.getIndex();
if(parsePos.getIndex() < 0) {
parsePos.setErrorIndex(0);
return;
}
int32_t start = pos;
int32_t dayPeriodInt = -1;
UBool ambiguousYear[] = { FALSE };
int32_t saveHebrewMonth = -1;
int32_t count = 0;
UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
int32_t abutPat = -1; int32_t abutStart = 0;
int32_t abutPass = 0;
UBool inQuote = FALSE;
MessageFormat * numericLeapMonthFormatter = NULL;
Calendar* calClone = NULL;
Calendar *workCal = &cal;
if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
calClone = fCalendar->clone();
if (calClone != NULL) {
calClone->setTime(cal.getTime(status),status);
if (U_FAILURE(status)) {
goto ExitParse;
}
calClone->setTimeZone(cal.getTimeZone());
workCal = calClone;
} else {
status = U_MEMORY_ALLOCATION_ERROR;
goto ExitParse;
}
}
if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status);
if (numericLeapMonthFormatter == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
goto ExitParse;
} else if (U_FAILURE(status)) {
goto ExitParse; }
}
for (int32_t i=0; i<fPattern.length(); ++i) {
UChar ch = fPattern.charAt(i);
if (!inQuote && isSyntaxChar(ch)) {
int32_t fieldPat = i;
count = 1;
while ((i+1)<fPattern.length() &&
fPattern.charAt(i+1) == ch) {
++count;
++i;
}
if (isNumeric(ch, count)) {
if (abutPat < 0) {
if (isAtNumericField(fPattern, i + 1)) {
abutPat = fieldPat;
abutStart = pos;
abutPass = 0;
}
}
} else {
abutPat = -1; }
if (abutPat >= 0) {
if (fieldPat == abutPat) {
count -= abutPass++;
if (count == 0) {
status = U_PARSE_ERROR;
goto ExitParse;
}
}
pos = subParse(text, pos, ch, count,
TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType);
if (pos < 0) {
i = abutPat - 1;
pos = abutStart;
continue;
}
}
else if (ch != 0x6C) { int32_t s = subParse(text, pos, ch, count,
FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, &dayPeriodInt);
if (s == -pos-1) {
s = pos;
if (i+1 < fPattern.length()) {
UChar c = fPattern.charAt(i+1);
if (PatternProps::isWhiteSpace(c)) {
i++;
while ((i+1)<fPattern.length() &&
PatternProps::isWhiteSpace(fPattern.charAt(i+1))) {
++i;
}
}
}
}
else if (s <= 0) {
status = U_PARSE_ERROR;
goto ExitParse;
}
pos = s;
}
}
else {
abutPat = -1;
if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status), isLenient())) {
status = U_PARSE_ERROR;
goto ExitParse;
}
}
}
if (text.charAt(pos) == 0x2e && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) {
if (isAfterNonNumericField(fPattern, fPattern.length())) {
pos++; }
}
if (dayPeriodInt >= 0) {
DayPeriodRules::DayPeriod dayPeriod = (DayPeriodRules::DayPeriod)dayPeriodInt;
const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
if (!cal.isSet(UCAL_HOUR) && !cal.isSet(UCAL_HOUR_OF_DAY)) {
double midPoint = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
if (U_SUCCESS(status)) {
int32_t midPointHour = (int32_t) midPoint;
int32_t midPointMinute = (midPoint - midPointHour) > 0 ? 30 : 0;
cal.set(UCAL_HOUR_OF_DAY, midPointHour);
cal.set(UCAL_MINUTE, midPointMinute);
}
} else {
int hourOfDay;
if (cal.isSet(UCAL_HOUR_OF_DAY)) { hourOfDay = cal.get(UCAL_HOUR_OF_DAY, status);
} else { hourOfDay = cal.get(UCAL_HOUR, status);
if (hourOfDay == 0) { hourOfDay = 12; }
}
U_ASSERT(0 <= hourOfDay && hourOfDay <= 23);
if (hourOfDay == 0 || (13 <= hourOfDay && hourOfDay <= 23)) {
cal.set(UCAL_HOUR_OF_DAY, hourOfDay);
} else {
if (hourOfDay == 12) { hourOfDay = 0; }
double currentHour = hourOfDay + (cal.get(UCAL_MINUTE, status)) / 60.0;
double midPointHour = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
if (U_SUCCESS(status)) {
double hoursAheadMidPoint = currentHour - midPointHour;
if (-6 <= hoursAheadMidPoint && hoursAheadMidPoint < 6) {
cal.set(UCAL_AM_PM, 0);
} else {
cal.set(UCAL_AM_PM, 1);
}
}
}
}
}
parsePos.setIndex(pos);
if (ambiguousYear[0] || tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) {
Calendar *copy;
if (ambiguousYear[0]) {
copy = cal.clone();
if (copy == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
goto ExitParse;
}
UDate parsedDate = copy->getTime(status);
if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) {
cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100);
}
delete copy;
}
if (tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) {
copy = cal.clone();
if (copy == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
goto ExitParse;
}
const TimeZone & tz = cal.getTimeZone();
BasicTimeZone *btz = NULL;
if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL
|| dynamic_cast<const SimpleTimeZone *>(&tz) != NULL
|| dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL
|| dynamic_cast<const VTimeZone *>(&tz) != NULL) {
btz = (BasicTimeZone*)&tz;
}
copy->set(UCAL_ZONE_OFFSET, 0);
copy->set(UCAL_DST_OFFSET, 0);
UDate localMillis = copy->getTime(status);
int32_t raw, dst;
if (btz != NULL) {
if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) {
btz->getOffsetFromLocal(localMillis,
BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status);
} else {
btz->getOffsetFromLocal(localMillis,
BasicTimeZone::kDaylight, BasicTimeZone::kDaylight, raw, dst, status);
}
} else {
tz.getOffset(localMillis, TRUE, raw, dst, status);
}
int32_t resolvedSavings = dst;
if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) {
if (dst != 0) {
resolvedSavings = 0;
}
} else { if (dst == 0) {
if (btz != NULL) {
UDate time = localMillis + raw;
TimeZoneTransition beforeTrs, afterTrs;
UDate beforeT = time, afterT = time;
int32_t beforeSav = 0, afterSav = 0;
UBool beforeTrsAvail, afterTrsAvail;
while (TRUE) {
beforeTrsAvail = btz->getPreviousTransition(beforeT, TRUE, beforeTrs);
if (!beforeTrsAvail) {
break;
}
beforeT = beforeTrs.getTime() - 1;
beforeSav = beforeTrs.getFrom()->getDSTSavings();
if (beforeSav != 0) {
break;
}
}
while (TRUE) {
afterTrsAvail = btz->getNextTransition(afterT, FALSE, afterTrs);
if (!afterTrsAvail) {
break;
}
afterT = afterTrs.getTime();
afterSav = afterTrs.getTo()->getDSTSavings();
if (afterSav != 0) {
break;
}
}
if (beforeTrsAvail && afterTrsAvail) {
if (time - beforeT > afterT - time) {
resolvedSavings = afterSav;
} else {
resolvedSavings = beforeSav;
}
} else if (beforeTrsAvail && beforeSav != 0) {
resolvedSavings = beforeSav;
} else if (afterTrsAvail && afterSav != 0) {
resolvedSavings = afterSav;
} else {
resolvedSavings = btz->getDSTSavings();
}
} else {
resolvedSavings = tz.getDSTSavings();
}
if (resolvedSavings == 0) {
resolvedSavings = U_MILLIS_PER_HOUR;
}
}
}
cal.set(UCAL_ZONE_OFFSET, raw);
cal.set(UCAL_DST_OFFSET, resolvedSavings);
delete copy;
}
}
ExitParse:
if (U_SUCCESS(status) && workCal != &cal) {
cal.setTimeZone(workCal->getTimeZone());
cal.setTime(workCal->getTime(status), status);
}
if (numericLeapMonthFormatter != NULL) {
delete numericLeapMonthFormatter;
}
if (calClone != NULL) {
delete calClone;
}
if (U_FAILURE(status)) {
parsePos.setErrorIndex(pos);
parsePos.setIndex(start);
}
}
static int32_t
matchStringWithOptionalDot(const UnicodeString &text,
int32_t index,
const UnicodeString &data);
int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
int32_t start,
UCalendarDateFields field,
const UnicodeString* data,
int32_t dataCount,
Calendar& cal) const
{
int32_t i = 0;
int32_t count = dataCount;
int32_t bestMatchLength = 0, bestMatch = -1;
UnicodeString bestMatchName;
for (; i < count; ++i) {
int32_t matchLength = 0;
if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
bestMatchLength = matchLength;
bestMatch = i;
}
}
if (bestMatch >= 0) {
cal.set(field, bestMatch * 3);
return start + bestMatchLength;
}
return -start;
}
int32_t SimpleDateFormat::matchDayPeriodStrings(const UnicodeString& text, int32_t start,
const UnicodeString* data, int32_t dataCount,
int32_t &dayPeriod) const
{
int32_t bestMatchLength = 0, bestMatch = -1;
for (int32_t i = 0; i < dataCount; ++i) {
int32_t matchLength = 0;
if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
bestMatchLength = matchLength;
bestMatch = i;
}
}
if (bestMatch >= 0) {
dayPeriod = bestMatch;
return start + bestMatchLength;
}
return -start;
}
#define IS_BIDI_MARK(c) (c==0x200E || c==0x200F || c==0x061C)
UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
int32_t &patternOffset,
const UnicodeString &text,
int32_t &textOffset,
UBool whitespaceLenient,
UBool partialMatchLenient,
UBool oldLeniency)
{
UBool inQuote = FALSE;
UnicodeString literal;
int32_t i = patternOffset;
for ( ; i < pattern.length(); i += 1) {
UChar ch = pattern.charAt(i);
if (!inQuote && isSyntaxChar(ch)) {
break;
}
if (ch == QUOTE) {
if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) {
i += 1;
} else {
inQuote = !inQuote;
continue;
}
}
if (!IS_BIDI_MARK(ch)) {
literal += ch;
}
}
int32_t p;
int32_t t = textOffset;
if (whitespaceLenient) {
literal.trim();
while (t < text.length()) {
UChar ch = text.charAt(t);
if (!u_isWhitespace(ch) && !IS_BIDI_MARK(ch)) {
break;
}
t += 1;
}
}
const UnicodeSet *ignorables = NULL;
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(pattern.charAt(i));
if (patternCharIndex != UDAT_FIELD_COUNT) {
ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
}
for (p = 0; p < literal.length() && t < text.length();) {
UBool needWhitespace = FALSE;
while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
needWhitespace = TRUE;
p += 1;
}
if (needWhitespace) {
UBool whitespaceInText = FALSE;
while (t < text.length()) {
UChar tch = text.charAt(t);
if (u_isUWhiteSpace(tch) || PatternProps::isWhiteSpace(tch)) {
whitespaceInText = TRUE;
} else if (!IS_BIDI_MARK(tch)) {
break;
}
t += 1;
}
if (!whitespaceLenient && !whitespaceInText) {
return FALSE;
}
if (p >= literal.length()) {
break;
}
} else {
while (t < text.length() && IS_BIDI_MARK(text.charAt(t))) {
++t;
}
}
if (t >= text.length() || literal.charAt(p) != text.charAt(t)) {
if (whitespaceLenient) {
if (t == textOffset && text.charAt(t) == 0x2e &&
isAfterNonNumericField(pattern, patternOffset)) {
++t;
continue; }
UChar wsc = text.charAt(t);
if(PatternProps::isWhiteSpace(wsc)) {
++t;
continue; }
}
if( partialMatchLenient && ( oldLeniency ||
( ignorables != NULL && ignorables->contains(literal.charAt(p)) && (ignorables->contains(text.charAt(t)) || u_isalpha(text.charAt(t))) ) )
) {
break;
}
return FALSE;
}
++p;
++t;
}
if (p <= 0) {
for (t = textOffset; t < text.length(); t += 1) {
UChar ch = text.charAt(t);
if (!IS_BIDI_MARK(ch) && (ignorables == NULL || !ignorables->contains(ch))) {
break;
}
}
}
patternOffset = i - 1;
textOffset = t;
return TRUE;
}
int32_t SimpleDateFormat::matchString(const UnicodeString& text,
int32_t start,
UCalendarDateFields field,
const UnicodeString* data,
int32_t dataCount,
const UnicodeString* monthPattern,
Calendar& cal) const
{
int32_t i = 0;
int32_t count = dataCount;
if (field == UCAL_DAY_OF_WEEK) i = 1;
int32_t bestMatchLength = 0, bestMatch = -1;
UnicodeString bestMatchName;
int32_t isLeapMonth = 0;
for (; i < count; ++i) {
int32_t matchLen = 0;
if ((matchLen = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
bestMatch = i;
bestMatchLength = matchLen;
}
if (monthPattern != NULL) {
UErrorCode status = U_ZERO_ERROR;
UnicodeString leapMonthName;
SimpleFormatter(*monthPattern, 1, 1, status).format(data[i], leapMonthName, status);
if (U_SUCCESS(status)) {
if ((matchLen = matchStringWithOptionalDot(text, start, leapMonthName)) > bestMatchLength) {
bestMatch = i;
bestMatchLength = matchLen;
isLeapMonth = 1;
}
}
}
}
if (bestMatch >= 0) {
if (field < UCAL_FIELD_COUNT) {
if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
cal.set(field,6);
} else {
if (field == UCAL_YEAR) {
bestMatch++; }
cal.set(field, bestMatch);
}
if (monthPattern != NULL) {
cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth);
}
}
return start + bestMatchLength;
}
return -start;
}
static int32_t
matchStringWithOptionalDot(const UnicodeString &text,
int32_t index,
const UnicodeString &data) {
UErrorCode sts = U_ZERO_ERROR;
int32_t matchLenText = 0;
int32_t matchLenData = 0;
u_caseInsensitivePrefixMatch(text.getBuffer() + index, text.length() - index,
data.getBuffer(), data.length(),
0 ,
&matchLenText, &matchLenData,
&sts);
U_ASSERT (U_SUCCESS(sts));
if (matchLenData == data.length()
|| (data.charAt(data.length() - 1) == 0x2e
&& matchLenData == data.length() - 1 )) {
return matchLenText;
}
return 0;
}
void
SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
{
parseAmbiguousDatesAsAfter(d, status);
}
int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType,
int32_t *dayPeriod) const
{
Formattable number;
int32_t value = 0;
int32_t i;
int32_t ps = 0;
UErrorCode status = U_ZERO_ERROR;
ParsePosition pos(0);
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
const NumberFormat *currentNumberFormat;
UnicodeString temp;
int32_t tzParseOptions = (isLenient())? UTZFMT_PARSE_OPTION_ALL_STYLES: UTZFMT_PARSE_OPTION_NONE;
UBool gotNumber = FALSE;
#if defined (U_DEBUG_CAL)
#endif
if (patternCharIndex == UDAT_FIELD_COUNT) {
return -start;
}
currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
if (currentNumberFormat == NULL) {
return -start;
}
UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; UnicodeString hebr("hebr", 4, US_INV);
if (numericLeapMonthFormatter != NULL) {
numericLeapMonthFormatter->setFormats((const Format **)¤tNumberFormat, 1);
}
UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);
for (;;) {
if (start >= text.length()) {
return -start;
}
UChar32 c = text.char32At(start);
if (!u_isUWhiteSpace(c) && !PatternProps::isWhiteSpace(c)) {
break;
}
start += U16_LENGTH(c);
}
pos.setIndex(start);
if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD || patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD || patternCharIndex == UDAT_HOUR1_FIELD || patternCharIndex == UDAT_HOUR0_FIELD || (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) || (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) || (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) || (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) || (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) || (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || patternCharIndex == UDAT_YEAR_FIELD || patternCharIndex == UDAT_YEAR_WOY_FIELD || patternCharIndex == UDAT_YEAR_NAME_FIELD || (patternCharIndex == UDAT_ERA_FIELD && isChineseCalendar) || patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD) {
int32_t parseStart = pos.getIndex();
const UnicodeString* src;
UBool parsedNumericLeapMonth = FALSE;
if (numericLeapMonthFormatter != NULL && (patternCharIndex == UDAT_MONTH_FIELD || patternCharIndex == UDAT_STANDALONE_MONTH_FIELD)) {
int32_t argCount;
Formattable * args = numericLeapMonthFormatter->parse(text, pos, argCount);
if (args != NULL && argCount == 1 && pos.getIndex() > parseStart && args[0].isNumeric()) {
parsedNumericLeapMonth = TRUE;
number.setLong(args[0].getLong());
cal.set(UCAL_IS_LEAP_MONTH, 1);
delete[] args;
} else {
pos.setIndex(parseStart);
cal.set(UCAL_IS_LEAP_MONTH, 0);
}
}
if (!parsedNumericLeapMonth) {
if (obeyCount) {
if ((start+count) > text.length()) {
return -start;
}
text.extractBetween(0, start + count, temp);
src = &temp;
} else {
src = &text;
}
parseInt(*src, number, pos, allowNegative,currentNumberFormat);
}
int32_t txtLoc = pos.getIndex();
if (txtLoc > parseStart) {
value = number.getLong();
gotNumber = TRUE;
if (value < 0 ) {
txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
if (txtLoc != pos.getIndex()) {
value *= -1;
}
}
else {
txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);
}
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) {
int32_t bias = gFieldRangeBias[patternCharIndex];
if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
return -start;
}
} else {
int32_t bias = gFieldRangeBiasLenient[patternCharIndex];
if (bias >= 0 && (value > cal.getMaximum(field) + bias)) {
return -start;
}
}
pos.setIndex(txtLoc);
}
}
switch (patternCharIndex) {
case UDAT_HOUR_OF_DAY1_FIELD:
case UDAT_HOUR_OF_DAY0_FIELD:
case UDAT_HOUR1_FIELD:
case UDAT_HOUR0_FIELD:
if (value < 0 || value > 24) {
return -start;
}
U_FALLTHROUGH;
case UDAT_YEAR_FIELD:
case UDAT_YEAR_WOY_FIELD:
case UDAT_FRACTIONAL_SECOND_FIELD:
if (! gotNumber) {
return -start;
}
break;
default:
break;
}
switch (patternCharIndex) {
case UDAT_ERA_FIELD:
if (isChineseCalendar) {
if (!gotNumber) {
return -start;
}
cal.set(UCAL_ERA, value);
return pos.getIndex();
}
if (count == 5) {
ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, NULL, cal);
} else if (count == 4) {
ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, NULL, cal);
} else {
ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, NULL, cal);
}
if (ps == -start)
ps--;
return ps;
case UDAT_YEAR_FIELD:
if (fDateOverride.compare(hebr)==0 && value < 1000) {
value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
} else if (text.moveIndex32(start, 2) == pos.getIndex() && !isChineseCalendar
&& u_isdigit(text.char32At(start))
&& u_isdigit(text.char32At(text.moveIndex32(start, 1))))
{
if(count < 3) {
if(fHaveDefaultCentury) { int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
ambiguousYear[0] = (value == ambiguousTwoDigitYear);
value += (fDefaultCenturyStartYear/100)*100 +
(value < ambiguousTwoDigitYear ? 100 : 0);
}
}
}
cal.set(UCAL_YEAR, value);
if (saveHebrewMonth >= 0) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) {
cal.set(UCAL_MONTH,saveHebrewMonth);
} else {
cal.set(UCAL_MONTH,saveHebrewMonth-1);
}
saveHebrewMonth = -1;
}
return pos.getIndex();
case UDAT_YEAR_WOY_FIELD:
if (fDateOverride.compare(hebr)==0 && value < 1000) {
value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
} else if (text.moveIndex32(start, 2) == pos.getIndex()
&& u_isdigit(text.char32At(start))
&& u_isdigit(text.char32At(text.moveIndex32(start, 1)))
&& fHaveDefaultCentury )
{
int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
ambiguousYear[0] = (value == ambiguousTwoDigitYear);
value += (fDefaultCenturyStartYear/100)*100 +
(value < ambiguousTwoDigitYear ? 100 : 0);
}
cal.set(UCAL_YEAR_WOY, value);
return pos.getIndex();
case UDAT_YEAR_NAME_FIELD:
if (fSymbols->fShortYearNames != NULL) {
int32_t newStart = matchString(text, start, UCAL_YEAR, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount, NULL, cal);
if (newStart > 0) {
return newStart;
}
}
if (gotNumber && (getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC,status) || value > fSymbols->fShortYearNamesCount)) {
cal.set(UCAL_YEAR, value);
return pos.getIndex();
}
return -start;
case UDAT_MONTH_FIELD:
case UDAT_STANDALONE_MONTH_FIELD:
if (gotNumber) {
if (!strcmp(cal.getType(),"hebrew")) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (cal.isSet(UCAL_YEAR)) {
UErrorCode monthStatus = U_ZERO_ERROR;
if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) {
cal.set(UCAL_MONTH, value);
} else {
cal.set(UCAL_MONTH, value - 1);
}
} else {
saveHebrewMonth = value;
}
} else {
cal.set(UCAL_MONTH, value - 1);
}
return pos.getIndex();
} else {
UnicodeString * wideMonthPat = NULL;
UnicodeString * shortMonthPat = NULL;
if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
if (patternCharIndex==UDAT_MONTH_FIELD) {
wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide];
shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev];
} else {
wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide];
shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev];
}
}
int32_t newStart = 0;
if (patternCharIndex==UDAT_MONTH_FIELD) {
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
newStart = matchString(text, start, UCAL_MONTH, fSymbols->fMonths, fSymbols->fMonthsCount, wideMonthPat, cal); if (newStart > 0) {
return newStart;
}
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
newStart = matchString(text, start, UCAL_MONTH, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, shortMonthPat, cal); }
} else {
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, wideMonthPat, cal); if (newStart > 0) {
return newStart;
}
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, shortMonthPat, cal); }
}
if (newStart > 0 || !getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) return newStart;
}
break;
case UDAT_HOUR_OF_DAY1_FIELD:
if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
value = 0;
U_FALLTHROUGH;
case UDAT_HOUR_OF_DAY0_FIELD:
cal.set(UCAL_HOUR_OF_DAY, value);
return pos.getIndex();
case UDAT_FRACTIONAL_SECOND_FIELD:
i = countDigits(text, start, pos.getIndex());
if (i < 3) {
while (i < 3) {
value *= 10;
i++;
}
} else {
int32_t a = 1;
while (i > 3) {
a *= 10;
i--;
}
value /= a;
}
cal.set(UCAL_MILLISECOND, value);
return pos.getIndex();
case UDAT_DOW_LOCAL_FIELD:
if (gotNumber) {
cal.set(UCAL_DOW_LOCAL, value);
return pos.getIndex();
}
U_FALLTHROUGH;
case UDAT_DAY_OF_WEEK_FIELD:
{
int32_t newStart = 0;
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
fSymbols->fWeekdays, fSymbols->fWeekdaysCount, NULL, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, NULL, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) {
if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
fSymbols->fShorterWeekdays, fSymbols->fShorterWeekdaysCount, NULL, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, NULL, cal)) > 0)
return newStart;
}
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status) || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD)
return newStart;
}
break;
case UDAT_STANDALONE_DAY_FIELD:
{
if (gotNumber) {
cal.set(UCAL_DOW_LOCAL, value);
return pos.getIndex();
}
int32_t newStart = 0;
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, NULL, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, NULL, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) {
if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
fSymbols->fStandaloneShorterWeekdays, fSymbols->fStandaloneShorterWeekdaysCount, NULL, cal)) > 0)
return newStart;
}
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
return newStart;
}
break;
case UDAT_AM_PM_FIELD:
{
int32_t newStart = 0;
if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count < 5 ) {
if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal)) > 0) {
return newStart;
}
}
if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count >= 5 ) {
if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fNarrowAmPms, fSymbols->fNarrowAmPmsCount, NULL, cal)) > 0) {
return newStart;
}
}
return -start;
}
case UDAT_HOUR1_FIELD:
if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
value = 0;
U_FALLTHROUGH;
case UDAT_HOUR0_FIELD:
cal.set(UCAL_HOUR, value);
return pos.getIndex();
case UDAT_QUARTER_FIELD:
if (gotNumber) {
cal.set(UCAL_MONTH, (value - 1) * 3);
return pos.getIndex();
} else {
int32_t newStart = 0;
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0)
return newStart;
}
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
return newStart;
if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))
return -start;
}
break;
case UDAT_STANDALONE_QUARTER_FIELD:
if (gotNumber) {
cal.set(UCAL_MONTH, (value - 1) * 3);
return pos.getIndex();
} else {
int32_t newStart = 0;
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)
return newStart;
}
if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0)
return newStart;
}
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
return newStart;
if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))
return -start;
}
break;
case UDAT_TIMEZONE_FIELD: {
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzParseOptions, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
break;
case UDAT_TIMEZONE_RFC_FIELD: {
UTimeZoneFormatStyle style = (count < 4) ?
UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT);
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
case UDAT_TIMEZONE_GENERIC_FIELD: {
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzParseOptions, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
case UDAT_TIMEZONE_SPECIAL_FIELD: {
UTimeZoneFormatStyle style;
switch (count) {
case 1:
style = UTZFMT_STYLE_ZONE_ID_SHORT;
break;
case 2:
style = UTZFMT_STYLE_ZONE_ID;
break;
case 3:
style = UTZFMT_STYLE_EXEMPLAR_LOCATION;
break;
default:
style = UTZFMT_STYLE_GENERIC_LOCATION;
break;
}
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: {
UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT;
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
case UDAT_TIMEZONE_ISO_FIELD: {
UTimeZoneFormatStyle style;
switch (count) {
case 1:
style = UTZFMT_STYLE_ISO_BASIC_SHORT;
break;
case 2:
style = UTZFMT_STYLE_ISO_BASIC_FIXED;
break;
case 3:
style = UTZFMT_STYLE_ISO_EXTENDED_FIXED;
break;
case 4:
style = UTZFMT_STYLE_ISO_BASIC_FULL;
break;
default:
style = UTZFMT_STYLE_ISO_EXTENDED_FULL;
break;
}
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
case UDAT_TIMEZONE_ISO_LOCAL_FIELD: {
UTimeZoneFormatStyle style;
switch (count) {
case 1:
style = UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT;
break;
case 2:
style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED;
break;
case 3:
style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED;
break;
case 4:
style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL;
break;
default:
style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL;
break;
}
const TimeZoneFormat *tzfmt = tzFormat(status);
if (U_SUCCESS(status)) {
TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
if (tz != NULL) {
cal.adoptTimeZone(tz);
return pos.getIndex();
}
}
return -start;
}
case UDAT_TIME_SEPARATOR_FIELD:
{
static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;
static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
int32_t count_sep = 1;
UnicodeString data[3];
fSymbols->getTimeSeparatorString(data[0]);
if (data[0].compare(&def_sep, 1) != 0) {
data[count_sep++].setTo(def_sep);
}
if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
data[count_sep++].setTo(alt_sep);
}
return matchString(text, start, UCAL_FIELD_COUNT , data, count_sep, NULL, cal);
}
case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
{
U_ASSERT(dayPeriod != NULL);
int32_t ampmStart = subParse(text, start, 0x61, count,
obeyCount, allowNegative, ambiguousYear, saveHebrewMonth, cal,
patLoc, numericLeapMonthFormatter, tzTimeType);
if (ampmStart > 0) {
return ampmStart;
} else {
int32_t newStart = 0;
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
2, *dayPeriod)) > 0) {
return newStart;
}
}
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
2, *dayPeriod)) > 0) {
return newStart;
}
}
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
2, *dayPeriod)) > 0) {
return newStart;
}
}
return -start;
}
}
case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
{
U_ASSERT(dayPeriod != NULL);
int32_t newStart = 0;
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
fSymbols->fAbbreviatedDayPeriodsCount, *dayPeriod)) > 0) {
return newStart;
}
}
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
fSymbols->fNarrowDayPeriodsCount, *dayPeriod)) > 0) {
return newStart;
}
}
if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
fSymbols->fWideDayPeriodsCount, *dayPeriod)) > 0) {
return newStart;
}
}
return -start;
}
default:
break;
}
int32_t parseStart = pos.getIndex();
const UnicodeString* src;
if (obeyCount) {
if ((start+count) > text.length()) {
return -start;
}
text.extractBetween(0, start + count, temp);
src = &temp;
} else {
src = &text;
}
parseInt(*src, number, pos, allowNegative,currentNumberFormat);
if (pos.getIndex() != parseStart) {
int32_t val = number.getLong();
if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) {
int32_t bias = gFieldRangeBias[patternCharIndex];
if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) {
return -start;
}
} else {
int32_t bias = gFieldRangeBiasLenient[patternCharIndex];
if (bias >= 0 && (value > cal.getMaximum(field) + bias)) {
return -start;
}
}
switch (patternCharIndex) {
case UDAT_MONTH_FIELD:
if (!strcmp(cal.getType(),"hebrew")) {
HebrewCalendar *hc = (HebrewCalendar*)&cal;
if (cal.isSet(UCAL_YEAR)) {
UErrorCode monthStatus = U_ZERO_ERROR;
if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) {
cal.set(UCAL_MONTH, val);
} else {
cal.set(UCAL_MONTH, val - 1);
}
} else {
saveHebrewMonth = val;
}
} else {
cal.set(UCAL_MONTH, val - 1);
}
break;
case UDAT_STANDALONE_MONTH_FIELD:
cal.set(UCAL_MONTH, val - 1);
break;
case UDAT_DOW_LOCAL_FIELD:
case UDAT_STANDALONE_DAY_FIELD:
cal.set(UCAL_DOW_LOCAL, val);
break;
case UDAT_QUARTER_FIELD:
case UDAT_STANDALONE_QUARTER_FIELD:
cal.set(UCAL_MONTH, (val - 1) * 3);
break;
case UDAT_RELATED_YEAR_FIELD:
cal.setRelatedYear(val);
break;
default:
cal.set(field, val);
break;
}
return pos.getIndex();
}
return -start;
}
void SimpleDateFormat::parseInt(const UnicodeString& text,
Formattable& number,
ParsePosition& pos,
UBool allowNegative,
const NumberFormat *fmt) const {
parseInt(text, number, -1, pos, allowNegative,fmt);
}
void SimpleDateFormat::parseInt(const UnicodeString& text,
Formattable& number,
int32_t maxDigits,
ParsePosition& pos,
UBool allowNegative,
const NumberFormat *fmt) const {
UnicodeString oldPrefix;
auto* fmtAsDF = dynamic_cast<const DecimalFormat*>(fmt);
LocalPointer<DecimalFormat> df;
if (!allowNegative && fmtAsDF != nullptr) {
df.adoptInstead(fmtAsDF->clone());
if (df.isNull()) {
return;
}
df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
fmt = df.getAlias();
}
int32_t oldPos = pos.getIndex();
fmt->parse(text, number, pos);
if (maxDigits > 0) {
int32_t nDigits = pos.getIndex() - oldPos;
if (nDigits > maxDigits) {
int32_t val = number.getLong();
nDigits -= maxDigits;
while (nDigits > 0) {
val /= 10;
nDigits--;
}
pos.setIndex(oldPos + maxDigits);
number.setLong(val);
}
}
}
int32_t SimpleDateFormat::countDigits(const UnicodeString& text, int32_t start, int32_t end) const {
int32_t numDigits = 0;
int32_t idx = start;
while (idx < end) {
UChar32 cp = text.char32At(idx);
if (u_isdigit(cp)) {
numDigits++;
}
idx += U16_LENGTH(cp);
}
return numDigits;
}
void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
UnicodeString& translatedPattern,
const UnicodeString& from,
const UnicodeString& to,
UErrorCode& status)
{
if (U_FAILURE(status)) {
return;
}
translatedPattern.remove();
UBool inQuote = FALSE;
for (int32_t i = 0; i < originalPattern.length(); ++i) {
UChar c = originalPattern[i];
if (inQuote) {
if (c == QUOTE) {
inQuote = FALSE;
}
} else {
if (c == QUOTE) {
inQuote = TRUE;
} else if (isSyntaxChar(c)) {
int32_t ci = from.indexOf(c);
if (ci == -1) {
status = U_INVALID_FORMAT_ERROR;
return;
}
c = to[ci];
}
}
translatedPattern += c;
}
if (inQuote) {
status = U_INVALID_FORMAT_ERROR;
return;
}
}
UnicodeString&
SimpleDateFormat::toPattern(UnicodeString& result) const
{
result = fPattern;
return result;
}
UnicodeString&
SimpleDateFormat::toLocalizedPattern(UnicodeString& result,
UErrorCode& status) const
{
translatePattern(fPattern, result,
UnicodeString(DateFormatSymbols::getPatternUChars()),
fSymbols->fLocalPatternChars, status);
return result;
}
void
SimpleDateFormat::applyPattern(const UnicodeString& pattern)
{
fPattern = pattern;
parsePattern();
if (fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
if (fDateOverride==UnicodeString(u"y=jpanyear") && !fHasHanYearChar) {
if (fSharedNumberFormatters) {
freeSharedNumberFormatters(fSharedNumberFormatters);
fSharedNumberFormatters = NULL;
}
fDateOverride.setToBogus(); } else if (fDateOverride.isBogus() && fHasHanYearChar) {
umtx_lock(&LOCK);
if (fSharedNumberFormatters == NULL) {
fSharedNumberFormatters = allocSharedNumberFormatters();
}
umtx_unlock(&LOCK);
if (fSharedNumberFormatters != NULL) {
Locale ovrLoc(fLocale.getLanguage(),fLocale.getCountry(),fLocale.getVariant(),"numbers=jpanyear");
UErrorCode status = U_ZERO_ERROR;
const SharedNumberFormat *snf = createSharedNumberFormat(ovrLoc, status);
if (U_SUCCESS(status)) {
UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(u'y');
SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
snf->deleteIfZeroRefCount();
fDateOverride.setTo(u"y=jpanyear", -1); }
}
}
}
}
void
SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
UErrorCode &status)
{
translatePattern(pattern, fPattern,
fSymbols->fLocalPatternChars,
UnicodeString(DateFormatSymbols::getPatternUChars()), status);
}
const DateFormatSymbols*
SimpleDateFormat::getDateFormatSymbols() const
{
return fSymbols;
}
void
SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)
{
delete fSymbols;
fSymbols = newFormatSymbols;
}
void
SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)
{
delete fSymbols;
fSymbols = new DateFormatSymbols(newFormatSymbols);
}
const TimeZoneFormat*
SimpleDateFormat::getTimeZoneFormat(void) const {
UErrorCode status = U_ZERO_ERROR;
return (const TimeZoneFormat*)tzFormat(status);
}
void
SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt)
{
delete fTimeZoneFormat;
fTimeZoneFormat = timeZoneFormatToAdopt;
}
void
SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)
{
delete fTimeZoneFormat;
fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat);
}
void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
{
UErrorCode status = U_ZERO_ERROR;
Locale calLocale(fLocale);
DateFormatSymbols *newSymbols = fSymbols;
if (!newSymbols || fCalendar->getType() != calendarToAdopt->getType()) {
calLocale.setKeywordValue("calendar", calendarToAdopt->getType(), status);
newSymbols = DateFormatSymbols::createForLocale(calLocale, status);
if (U_FAILURE(status)) {
delete calendarToAdopt;
return;
}
}
DateFormat::adoptCalendar(calendarToAdopt);
if (fSymbols != newSymbols) {
delete fSymbols;
fSymbols = newSymbols;
}
initializeDefaultCentury(); }
void
SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
{
DateFormat::setContext(value, status);
#if !UCONFIG_NO_BREAK_ITERATION
if (U_SUCCESS(status)) {
if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
status = U_ZERO_ERROR;
fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
if (U_FAILURE(status)) {
delete fCapitalizationBrkIter;
fCapitalizationBrkIter = NULL;
}
}
}
#endif
}
UBool
SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
return isFieldUnitIgnored(fPattern, field);
}
UBool
SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
UCalendarDateFields field) {
int32_t fieldLevel = fgCalendarFieldToLevel[field];
int32_t level;
UChar ch;
UBool inQuote = FALSE;
UChar prevCh = 0;
int32_t count = 0;
for (int32_t i = 0; i < pattern.length(); ++i) {
ch = pattern[i];
if (ch != prevCh && count > 0) {
level = getLevelFromChar(prevCh);
if (fieldLevel <= level) {
return FALSE;
}
count = 0;
}
if (ch == QUOTE) {
if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) {
++i;
} else {
inQuote = ! inQuote;
}
}
else if (!inQuote && isSyntaxChar(ch)) {
prevCh = ch;
++count;
}
}
if (count > 0) {
level = getLevelFromChar(prevCh);
if (fieldLevel <= level) {
return FALSE;
}
}
return TRUE;
}
const Locale&
SimpleDateFormat::getSmpFmtLocale(void) const {
return fLocale;
}
int32_t
SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start,
int32_t patLoc, UBool isNegative) const {
UnicodeString suf;
int32_t patternMatch;
int32_t textPreMatch;
int32_t textPostMatch;
if ( (start > text.length()) ||
(start < 0) ||
(patLoc < 0) ||
(patLoc > fPattern.length())) {
return start;
}
DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
if (decfmt != NULL) {
if (isNegative) {
suf = decfmt->getNegativeSuffix(suf);
}
else {
suf = decfmt->getPositiveSuffix(suf);
}
}
if (suf.length() <= 0) {
return start;
}
patternMatch = compareSimpleAffix(suf,fPattern,patLoc);
textPreMatch = compareSimpleAffix(suf,text,start);
textPostMatch = compareSimpleAffix(suf,text,start-suf.length());
if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) {
return start;
}
else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) {
return start - suf.length();
}
return start;
}
int32_t
SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
const UnicodeString& input,
int32_t pos) const {
int32_t start = pos;
for (int32_t i=0; i<affix.length(); ) {
UChar32 c = affix.char32At(i);
int32_t len = U16_LENGTH(c);
if (PatternProps::isWhiteSpace(c)) {
UBool literalMatch = FALSE;
while (pos < input.length() &&
input.char32At(pos) == c) {
literalMatch = TRUE;
i += len;
pos += len;
if (i == affix.length()) {
break;
}
c = affix.char32At(i);
len = U16_LENGTH(c);
if (!PatternProps::isWhiteSpace(c)) {
break;
}
}
i = skipPatternWhiteSpace(affix, i);
int32_t s = pos;
pos = skipUWhiteSpace(input, pos);
if (pos == s && !literalMatch) {
return -1;
}
i = skipUWhiteSpace(affix, i);
} else {
if (pos < input.length() &&
input.char32At(pos) == c) {
i += len;
pos += len;
} else {
return -1;
}
}
}
return pos - start;
}
int32_t
SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const {
const UChar* s = text.getBuffer();
return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
}
int32_t
SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const {
while (pos < text.length()) {
UChar32 c = text.char32At(pos);
if (!u_isUWhiteSpace(c)) {
break;
}
pos += U16_LENGTH(c);
}
return pos;
}
TimeZoneFormat *
SimpleDateFormat::tzFormat(UErrorCode &status) const {
if (fTimeZoneFormat == NULL) {
umtx_lock(&LOCK);
{
if (fTimeZoneFormat == NULL) {
TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
if (U_FAILURE(status)) {
return NULL;
}
const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
}
}
umtx_unlock(&LOCK);
}
return fTimeZoneFormat;
}
void SimpleDateFormat::parsePattern() {
fHasMinute = FALSE;
fHasSecond = FALSE;
fHasHanYearChar = FALSE;
int len = fPattern.length();
UBool inQuote = FALSE;
for (int32_t i = 0; i < len; ++i) {
UChar ch = fPattern[i];
if (ch == QUOTE) {
inQuote = !inQuote;
}
if (ch == 0x5E74) { fHasHanYearChar = TRUE;
}
if (!inQuote) {
if (ch == 0x6D) { fHasMinute = TRUE;
}
if (ch == 0x73) { fHasSecond = TRUE;
}
}
}
}
U_NAMESPACE_END
#endif