| Index: source/i18n/smpdtfmt.cpp
|
| diff --git a/source/i18n/smpdtfmt.cpp b/source/i18n/smpdtfmt.cpp
|
| index 01c9f7c7981b40e3e62b06091baa559c8c2909a5..85cc162a11f39f5e76732bf1140a09e7a3687953 100644
|
| --- a/source/i18n/smpdtfmt.cpp
|
| +++ b/source/i18n/smpdtfmt.cpp
|
| @@ -1,6 +1,8 @@
|
| +// Copyright (C) 2016 and later: Unicode, Inc. and others.
|
| +// License & terms of use: http://www.unicode.org/copyright.html
|
| /*
|
| *******************************************************************************
|
| -* Copyright (C) 1997-2015, International Business Machines Corporation and *
|
| +* Copyright (C) 1997-2016, International Business Machines Corporation and *
|
| * others. All Rights Reserved. *
|
| *******************************************************************************
|
| *
|
| @@ -17,7 +19,7 @@
|
| * Removed getZoneIndex (added in DateFormatSymbols)
|
| * Removed subParseLong
|
| * Removed chk
|
| -* 02/22/99 stephen Removed character literals for EBCDIC safety
|
| +* 02/22/99 stephen Removed character literals for EBCDIC safety
|
| * 10/14/99 aliu Updated 2-digit year parsing so that only "00" thru
|
| * "99" are recognized. {j28 4182066}
|
| * 11/15/99 weiv Added support for week of year/day of week format
|
| @@ -42,6 +44,7 @@
|
| #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"
|
| @@ -49,10 +52,10 @@
|
| #include "unicode/vtzone.h"
|
| #include "unicode/udisplaycontext.h"
|
| #include "unicode/brkiter.h"
|
| +#include "uresimp.h"
|
| #include "olsontz.h"
|
| #include "patternprops.h"
|
| #include "fphdlimp.h"
|
| -#include "gregoimp.h"
|
| #include "hebrwcal.h"
|
| #include "cstring.h"
|
| #include "uassert.h"
|
| @@ -62,6 +65,10 @@
|
| #include "smpdtfst.h"
|
| #include "sharednumberformat.h"
|
| #include "ustr_imp.h"
|
| +#include "charstr.h"
|
| +#include "uvector.h"
|
| +#include "cstr.h"
|
| +#include "dayperiodrules.h"
|
|
|
| #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
|
| #include <stdio.h>
|
| @@ -159,9 +166,6 @@ static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0};
|
| * These are the tags we expect to see in normal resource bundle files associated
|
| * with a locale.
|
| */
|
| -static const char gDateTimePatternsTag[]="DateTimePatterns";
|
| -
|
| -//static const UChar gEtcUTC[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x54, 0x43, 0x00}; // "Etc/UTC"
|
| static const UChar QUOTE = 0x27; // Single quote
|
|
|
| /*
|
| @@ -621,6 +625,8 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
|
| fHaveDefaultCentury = other.fHaveDefaultCentury;
|
|
|
| fPattern = other.fPattern;
|
| + fHasMinute = other.fHasMinute;
|
| + fHasSecond = other.fHasSecond;
|
|
|
| // TimeZoneFormat in ICU4C only depends on a locale for now
|
| if (fLocale != other.fLocale) {
|
| @@ -695,20 +701,42 @@ void SimpleDateFormat::construct(EStyle timeStyle,
|
| initializeCalendar(NULL, locale, status);
|
| if (U_FAILURE(status)) return;
|
|
|
| - CalendarData calData(locale, fCalendar?fCalendar->getType():NULL, status);
|
| - UResourceBundle *dateTimePatterns = calData.getByKey(gDateTimePatternsTag, status);
|
| - UResourceBundle *currentBundle;
|
| + // Load date time patterns directly from resources.
|
| + const char* cType = fCalendar ? fCalendar->getType() : NULL;
|
| + LocalUResourceBundlePointer bundle(ures_open(NULL, locale.getBaseName(), &status));
|
| + if (U_FAILURE(status)) return;
|
| +
|
| + UBool cTypeIsGregorian = TRUE;
|
| + LocalUResourceBundlePointer dateTimePatterns;
|
| + 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));
|
| + cTypeIsGregorian = FALSE;
|
| + }
|
|
|
| + // Check for "gregorian" fallback.
|
| + if (cTypeIsGregorian || status == U_MISSING_RESOURCE_ERROR) {
|
| + status = U_ZERO_ERROR;
|
| + dateTimePatterns.adoptInstead(
|
| + ures_getByKeyWithFallback(bundle.getAlias(),
|
| + "calendar/gregorian/DateTimePatterns",
|
| + (UResourceBundle*)NULL, &status));
|
| + }
|
| if (U_FAILURE(status)) return;
|
|
|
| - if (ures_getSize(dateTimePatterns) <= kDateTime)
|
| + LocalUResourceBundlePointer currentBundle;
|
| +
|
| + if (ures_getSize(dateTimePatterns.getAlias()) <= kDateTime)
|
| {
|
| status = U_INVALID_FORMAT_ERROR;
|
| return;
|
| }
|
|
|
| - setLocaleIDs(ures_getLocaleByType(dateTimePatterns, ULOC_VALID_LOCALE, &status),
|
| - ures_getLocaleByType(dateTimePatterns, ULOC_ACTUAL_LOCALE, &status));
|
| + setLocaleIDs(ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_VALID_LOCALE, &status),
|
| + ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_ACTUAL_LOCALE, &status));
|
|
|
| // create a symbols object from the locale
|
| fSymbols = DateFormatSymbols::createForLocale(locale, status);
|
| @@ -726,144 +754,122 @@ void SimpleDateFormat::construct(EStyle timeStyle,
|
|
|
| // if the pattern should include both date and time information, use the date/time
|
| // pattern string as a guide to tell use how to glue together the appropriate date
|
| - // and time pattern strings. The actual gluing-together is handled by a convenience
|
| - // method on MessageFormat.
|
| + // and time pattern strings.
|
| if ((timeStyle != kNone) && (dateStyle != kNone))
|
| {
|
| - Formattable timeDateArray[2];
|
| -
|
| - // use Formattable::adoptString() so that we can use fastCopyFrom()
|
| - // instead of Formattable::setString()'s unaware, safe, deep string clone
|
| - // see Jitterbug 2296
|
| -
|
| - currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status);
|
| + currentBundle.adoptInstead(
|
| + ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)timeStyle, NULL, &status));
|
| if (U_FAILURE(status)) {
|
| status = U_INVALID_FORMAT_ERROR;
|
| return;
|
| }
|
| - switch (ures_getType(currentBundle)) {
|
| + switch (ures_getType(currentBundle.getAlias())) {
|
| case URES_STRING: {
|
| - resStr = ures_getString(currentBundle, &resStrLen, &status);
|
| + resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
|
| break;
|
| }
|
| case URES_ARRAY: {
|
| - resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
|
| - ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
|
| + resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
|
| + ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
|
| fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen);
|
| break;
|
| }
|
| default: {
|
| status = U_INVALID_FORMAT_ERROR;
|
| - ures_close(currentBundle);
|
| return;
|
| }
|
| }
|
| - ures_close(currentBundle);
|
|
|
| - UnicodeString *tempus1 = new UnicodeString(TRUE, resStr, resStrLen);
|
| - // NULL pointer check
|
| - if (tempus1 == NULL) {
|
| - status = U_MEMORY_ALLOCATION_ERROR;
|
| - return;
|
| - }
|
| - timeDateArray[0].adoptString(tempus1);
|
| + UnicodeString tempus1(TRUE, resStr, resStrLen);
|
|
|
| - currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status);
|
| + currentBundle.adoptInstead(
|
| + ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)dateStyle, NULL, &status));
|
| if (U_FAILURE(status)) {
|
| status = U_INVALID_FORMAT_ERROR;
|
| return;
|
| }
|
| - switch (ures_getType(currentBundle)) {
|
| + switch (ures_getType(currentBundle.getAlias())) {
|
| case URES_STRING: {
|
| - resStr = ures_getString(currentBundle, &resStrLen, &status);
|
| + resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
|
| break;
|
| }
|
| case URES_ARRAY: {
|
| - resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
|
| - ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
|
| + resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
|
| + ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
|
| fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
|
| break;
|
| }
|
| default: {
|
| status = U_INVALID_FORMAT_ERROR;
|
| - ures_close(currentBundle);
|
| return;
|
| }
|
| }
|
| - ures_close(currentBundle);
|
|
|
| - UnicodeString *tempus2 = new UnicodeString(TRUE, resStr, resStrLen);
|
| - // Null pointer check
|
| - if (tempus2 == NULL) {
|
| - status = U_MEMORY_ALLOCATION_ERROR;
|
| - return;
|
| - }
|
| - timeDateArray[1].adoptString(tempus2);
|
| + UnicodeString tempus2(TRUE, resStr, resStrLen);
|
|
|
| int32_t glueIndex = kDateTime;
|
| - int32_t patternsSize = ures_getSize(dateTimePatterns);
|
| + int32_t patternsSize = ures_getSize(dateTimePatterns.getAlias());
|
| if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
|
| // Get proper date time format
|
| glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset));
|
| }
|
|
|
| - resStr = ures_getStringByIndex(dateTimePatterns, glueIndex, &resStrLen, &status);
|
| - MessageFormat::format(UnicodeString(TRUE, resStr, resStrLen), timeDateArray, 2, fPattern, status);
|
| + resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), glueIndex, &resStrLen, &status);
|
| + SimpleFormatter(UnicodeString(TRUE, resStr, resStrLen), 2, 2, status).
|
| + format(tempus1, tempus2, fPattern, status);
|
| }
|
| // if the pattern includes just time data or just date date, load the appropriate
|
| // pattern string from the resources
|
| // setTo() - see DateFormatSymbols::assignArray comments
|
| else if (timeStyle != kNone) {
|
| - currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)timeStyle, NULL, &status);
|
| + currentBundle.adoptInstead(
|
| + ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)timeStyle, NULL, &status));
|
| if (U_FAILURE(status)) {
|
| status = U_INVALID_FORMAT_ERROR;
|
| return;
|
| }
|
| - switch (ures_getType(currentBundle)) {
|
| + switch (ures_getType(currentBundle.getAlias())) {
|
| case URES_STRING: {
|
| - resStr = ures_getString(currentBundle, &resStrLen, &status);
|
| + resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
|
| break;
|
| }
|
| case URES_ARRAY: {
|
| - resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
|
| - ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
|
| + resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
|
| + ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
|
| fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
|
| break;
|
| }
|
| default: {
|
| status = U_INVALID_FORMAT_ERROR;
|
| - ures_close(currentBundle);
|
| return;
|
| }
|
| }
|
| fPattern.setTo(TRUE, resStr, resStrLen);
|
| - ures_close(currentBundle);
|
| }
|
| else if (dateStyle != kNone) {
|
| - currentBundle = ures_getByIndex(dateTimePatterns, (int32_t)dateStyle, NULL, &status);
|
| + currentBundle.adoptInstead(
|
| + ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)dateStyle, NULL, &status));
|
| if (U_FAILURE(status)) {
|
| status = U_INVALID_FORMAT_ERROR;
|
| return;
|
| }
|
| - switch (ures_getType(currentBundle)) {
|
| + switch (ures_getType(currentBundle.getAlias())) {
|
| case URES_STRING: {
|
| - resStr = ures_getString(currentBundle, &resStrLen, &status);
|
| + resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
|
| break;
|
| }
|
| case URES_ARRAY: {
|
| - resStr = ures_getStringByIndex(currentBundle, 0, &resStrLen, &status);
|
| - ovrStr = ures_getStringByIndex(currentBundle, 1, &ovrStrLen, &status);
|
| + resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
|
| + ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
|
| fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
|
| break;
|
| }
|
| default: {
|
| status = U_INVALID_FORMAT_ERROR;
|
| - ures_close(currentBundle);
|
| return;
|
| }
|
| }
|
| fPattern.setTo(TRUE, resStr, resStrLen);
|
| - ures_close(currentBundle);
|
| }
|
|
|
| // and if it includes _neither_, that's an error
|
| @@ -906,6 +912,8 @@ SimpleDateFormat::initialize(const Locale& locale,
|
| {
|
| status = U_MISSING_RESOURCE_ERROR;
|
| }
|
| +
|
| + parsePattern();
|
| }
|
|
|
| /* Initialize the fields we use to disambiguate ambiguous years. Separate
|
| @@ -986,7 +994,7 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
|
| FieldPositionHandler& handler, UErrorCode& status) const
|
| {
|
| if ( U_FAILURE(status) ) {
|
| - return appendTo;
|
| + return appendTo;
|
| }
|
| Calendar* workCal = &cal;
|
| Calendar* calClone = NULL;
|
| @@ -1178,6 +1186,7 @@ SimpleDateFormat::fgPatternIndexToCalendarField[] =
|
| /*O*/ UCAL_ZONE_OFFSET,
|
| /*Xx*/ UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,
|
| /*r*/ UCAL_EXTENDED_YEAR,
|
| + /*bB*/ UCAL_FIELD_COUNT, UCAL_FIELD_COUNT, // no mappings to calendar fields
|
| #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
|
| /*:*/ UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */
|
| #else
|
| @@ -1206,6 +1215,7 @@ SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
|
| /*O*/ UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
|
| /*Xx*/ UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD,
|
| /*r*/ UDAT_RELATED_YEAR_FIELD,
|
| + /*bB*/ UDAT_AM_PM_MIDNIGHT_NOON_FIELD, UDAT_FLEXIBLE_DAY_PERIOD_FIELD,
|
| #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
|
| /*:*/ UDAT_TIME_SEPARATOR_FIELD,
|
| #else
|
| @@ -1238,8 +1248,7 @@ _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeSt
|
| if (monthPattern == NULL) {
|
| dst += symbols[value];
|
| } else {
|
| - Formattable monthName((const UnicodeString&)(symbols[value]));
|
| - MessageFormat::format(*monthPattern, &monthName, 1, dst, status);
|
| + SimpleFormatter(*monthPattern, 1, 1, status).format(symbols[value], dst, status);
|
| }
|
| }
|
| }
|
| @@ -1355,6 +1364,7 @@ SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeStrin
|
| if (type==kOvrStrDate) {
|
| break;
|
| }
|
| + U_FALLTHROUGH;
|
| }
|
| case kOvrStrTime : {
|
| for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
|
| @@ -1437,7 +1447,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
| return;
|
| }
|
| UnicodeString hebr("hebr", 4, US_INV);
|
| -
|
| +
|
| switch (patternCharIndex) {
|
|
|
| // for any "G" symbol, write out the appropriate era string
|
| @@ -1466,6 +1476,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
| break;
|
| }
|
| // else fall through to numeric year handling, do not break here
|
| + U_FALLTHROUGH;
|
|
|
| // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits
|
| // NEW: UTS#35:
|
| @@ -1559,7 +1570,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
| } else if (count == 2) {
|
| value /= 10;
|
| }
|
| - FieldPosition p(0);
|
| + FieldPosition p(FieldPosition::DONT_CARE);
|
| currentNumberFormat->format(value, appendTo, p);
|
| if (count > 3) {
|
| currentNumberFormat->setMinimumIntegerDigits(count - 3);
|
| @@ -1585,6 +1596,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
| return;
|
| }
|
| // fall through, do not break here
|
| + U_FALLTHROUGH;
|
| case UDAT_DAY_OF_WEEK_FIELD:
|
| if (count == 5) {
|
| _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
|
| @@ -1806,6 +1818,140 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
|
| 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);
|
| +
|
| + // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
|
| + // For ICU 57 output of "midnight" is temporarily suppressed.
|
| +
|
| + // For "midnight" and "noon":
|
| + // Time, as displayed, must be exactly noon or midnight.
|
| + // This means minutes and seconds, if present, must be zero.
|
| + if ((/*hour == 0 ||*/ hour == 12) &&
|
| + (!fHasMinute || cal.get(UCAL_MINUTE, status) == 0) &&
|
| + (!fHasSecond || cal.get(UCAL_SECOND, status) == 0)) {
|
| + // Stealing am/pm value to use as our array index.
|
| + // It works out: am/midnight are both 0, pm/noon are both 1,
|
| + // 12 am is 12 midnight, and 12 pm is 12 noon.
|
| + int32_t value = cal.get(UCAL_AM_PM, status);
|
| +
|
| + if (count <= 3) {
|
| + toAppend = &fSymbols->fAbbreviatedDayPeriods[value];
|
| + } else if (count == 4 || count > 5) {
|
| + toAppend = &fSymbols->fWideDayPeriods[value];
|
| + } else { // count == 5
|
| + toAppend = &fSymbols->fNarrowDayPeriods[value];
|
| + }
|
| + }
|
| +
|
| + // toAppend is NULL if time isn't exactly midnight or noon (as displayed).
|
| + // toAppend is bogus if time is midnight or noon, but no localized string exists.
|
| + // In either case, fall back to am/pm.
|
| + if (toAppend == NULL || toAppend->isBogus()) {
|
| + // Reformat with identical arguments except ch, now changed to 'a'.
|
| + subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
|
| + handler, cal, mutableNFs, status);
|
| + } else {
|
| + appendTo += *toAppend;
|
| + }
|
| +
|
| + break;
|
| + }
|
| +
|
| + case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
|
| + {
|
| + // TODO: Maybe fetch the DayperiodRules during initialization (instead of at the first
|
| + // loading of an instance) if a relevant pattern character (b or B) is used.
|
| + const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
|
| + if (U_FAILURE(status)) {
|
| + // Data doesn't conform to spec, therefore loading failed.
|
| + break;
|
| + }
|
| + if (ruleSet == NULL) {
|
| + // Data doesn't exist for the locale we're looking for.
|
| + // Falling back to am/pm.
|
| + subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
|
| + handler, cal, mutableNFs, status);
|
| + break;
|
| + }
|
| +
|
| + // Get current display time.
|
| + 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);
|
| + }
|
| +
|
| + // Determine day period.
|
| + 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);
|
| + }
|
| +
|
| + // Rule set exists, therefore periodType can't be UNKNOWN.
|
| + // Get localized string.
|
| + U_ASSERT(periodType != DayPeriodRules::DAYPERIOD_UNKNOWN);
|
| + UnicodeString *toAppend = NULL;
|
| + int32_t index;
|
| +
|
| + // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
|
| + // For ICU 57 output of "midnight" is temporarily suppressed.
|
| +
|
| + if (periodType != DayPeriodRules::DAYPERIOD_AM &&
|
| + periodType != DayPeriodRules::DAYPERIOD_PM &&
|
| + periodType != DayPeriodRules::DAYPERIOD_MIDNIGHT) {
|
| + index = (int32_t)periodType;
|
| + if (count <= 3) {
|
| + toAppend = &fSymbols->fAbbreviatedDayPeriods[index]; // i.e. short
|
| + } else if (count == 4 || count > 5) {
|
| + toAppend = &fSymbols->fWideDayPeriods[index];
|
| + } else { // count == 5
|
| + toAppend = &fSymbols->fNarrowDayPeriods[index];
|
| + }
|
| + }
|
| +
|
| + // Fallback schedule:
|
| + // Midnight/Noon -> General Periods -> AM/PM.
|
| +
|
| + // Midnight/Noon -> General Periods.
|
| + 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]; // i.e. short
|
| + } else if (count == 4 || count > 5) {
|
| + toAppend = &fSymbols->fWideDayPeriods[index];
|
| + } else { // count == 5
|
| + toAppend = &fSymbols->fNarrowDayPeriods[index];
|
| + }
|
| + }
|
| +
|
| + // General Periods -> AM/PM.
|
| + if (periodType == DayPeriodRules::DAYPERIOD_AM ||
|
| + periodType == DayPeriodRules::DAYPERIOD_PM ||
|
| + toAppend->isBogus()) {
|
| + subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
|
| + handler, cal, mutableNFs, status);
|
| + }
|
| + else {
|
| + appendTo += *toAppend;
|
| + }
|
| +
|
| + break;
|
| + }
|
|
|
| // all of the other pattern symbols can be formatted as simple numbers with
|
| // appropriate zero padding
|
| @@ -1848,7 +1994,7 @@ void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
|
| fixNumberFormatForDates(*formatToAdopt);
|
| delete fNumberFormat;
|
| fNumberFormat = formatToAdopt;
|
| -
|
| +
|
| // We successfully set the default number format. Now delete the overrides
|
| // (can't fail).
|
| if (fSharedNumberFormatters) {
|
| @@ -1911,7 +2057,7 @@ SimpleDateFormat::zeroPaddingNumber(
|
| int32_t value, int32_t minDigits, int32_t maxDigits) const
|
| {
|
| if (currentNumberFormat!=NULL) {
|
| - FieldPosition pos(0);
|
| + FieldPosition pos(FieldPosition::DONT_CARE);
|
|
|
| currentNumberFormat->setMinimumIntegerDigits(minDigits);
|
| currentNumberFormat->setMaximumIntegerDigits(maxDigits);
|
| @@ -1974,6 +2120,9 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
|
| }
|
| int32_t start = pos;
|
|
|
| + // Hold the day period until everything else is parsed, because we need
|
| + // the hour to interpret time correctly.
|
| + int32_t dayPeriodInt = -1;
|
|
|
| UBool ambiguousYear[] = { FALSE };
|
| int32_t saveHebrewMonth = -1;
|
| @@ -2012,7 +2161,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
|
| goto ExitParse;
|
| }
|
| }
|
| -
|
| +
|
| if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
|
| numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status);
|
| if (numericLeapMonthFormatter == NULL) {
|
| @@ -2088,7 +2237,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
|
| // fields.
|
| else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
|
| int32_t s = subParse(text, pos, ch, count,
|
| - FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs);
|
| + FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs, &dayPeriodInt);
|
|
|
| if (s == -pos-1) {
|
| // era not present, in special cases allow this to continue
|
| @@ -2124,7 +2273,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
|
| else {
|
|
|
| abutPat = -1; // End of any abutting fields
|
| -
|
| +
|
| 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;
|
| @@ -2140,6 +2289,76 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
|
| }
|
| }
|
|
|
| + // If dayPeriod is set, use it in conjunction with hour-of-day to determine am/pm.
|
| + 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)) {
|
| + // If hour is not set, set time to the midpoint of current day period, overwriting
|
| + // minutes if it's set.
|
| + double midPoint = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
|
| +
|
| + // If we can't get midPoint we do nothing.
|
| + if (U_SUCCESS(status)) {
|
| + // Truncate midPoint toward zero to get the hour.
|
| + // Any leftover means it was a half-hour.
|
| + int32_t midPointHour = (int32_t) midPoint;
|
| + int32_t midPointMinute = (midPoint - midPointHour) > 0 ? 30 : 0;
|
| +
|
| + // No need to set am/pm because hour-of-day is set last therefore takes precedence.
|
| + cal.set(UCAL_HOUR_OF_DAY, midPointHour);
|
| + cal.set(UCAL_MINUTE, midPointMinute);
|
| + }
|
| + } else {
|
| + int hourOfDay;
|
| +
|
| + if (cal.isSet(UCAL_HOUR_OF_DAY)) { // Hour is parsed in 24-hour format.
|
| + hourOfDay = cal.get(UCAL_HOUR_OF_DAY, status);
|
| + } else { // Hour is parsed in 12-hour format.
|
| + hourOfDay = cal.get(UCAL_HOUR, status);
|
| + // cal.get() turns 12 to 0 for 12-hour time; change 0 to 12
|
| + // so 0 unambiguously means a 24-hour time from above.
|
| + if (hourOfDay == 0) { hourOfDay = 12; }
|
| + }
|
| + U_ASSERT(0 <= hourOfDay && hourOfDay <= 23);
|
| +
|
| +
|
| + // If hour-of-day is 0 or 13 thru 23 then input time in unambiguously in 24-hour format.
|
| + if (hourOfDay == 0 || (13 <= hourOfDay && hourOfDay <= 23)) {
|
| + // Make hour-of-day take precedence over (hour + am/pm) by setting it again.
|
| + cal.set(UCAL_HOUR_OF_DAY, hourOfDay);
|
| + } else {
|
| + // We have a 12-hour time and need to choose between am and pm.
|
| + // Behave as if dayPeriod spanned 6 hours each way from its center point.
|
| + // This will parse correctly for consistent time + period (e.g. 10 at night) as
|
| + // well as provide a reasonable recovery for inconsistent time + period (e.g.
|
| + // 9 in the afternoon).
|
| +
|
| + // Assume current time is in the AM.
|
| + // - Change 12 back to 0 for easier handling of 12am.
|
| + // - Append minutes as fractional hours because e.g. 8:15 and 8:45 could be parsed
|
| + // into different half-days if center of dayPeriod is at 14:30.
|
| + // - cal.get(MINUTE) will return 0 if MINUTE is unset, which works.
|
| + 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;
|
| +
|
| + // Assume current time is in the AM.
|
| + if (-6 <= hoursAheadMidPoint && hoursAheadMidPoint < 6) {
|
| + // Assumption holds; set time as such.
|
| + cal.set(UCAL_AM_PM, 0);
|
| + } else {
|
| + cal.set(UCAL_AM_PM, 1);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| // At this point the fields of Calendar have been set. Calendar
|
| // will fill in default values for missing fields when the time
|
| // is computed.
|
| @@ -2364,6 +2583,29 @@ int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
|
| 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;
|
| +}
|
| +
|
| //----------------------------------------------------------------------
|
| UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
|
| int32_t &patternOffset,
|
| @@ -2374,17 +2616,17 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
|
| UBool oldLeniency)
|
| {
|
| UBool inQuote = FALSE;
|
| - UnicodeString literal;
|
| + UnicodeString literal;
|
| int32_t i = patternOffset;
|
|
|
| // scan pattern looking for contiguous literal characters
|
| for ( ; i < pattern.length(); i += 1) {
|
| UChar ch = pattern.charAt(i);
|
| -
|
| +
|
| if (!inQuote && isSyntaxChar(ch)) {
|
| break;
|
| }
|
| -
|
| +
|
| if (ch == QUOTE) {
|
| // Match a quote literal ('') inside OR outside of quotes
|
| if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) {
|
| @@ -2394,47 +2636,47 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
|
| continue;
|
| }
|
| }
|
| -
|
| +
|
| literal += ch;
|
| }
|
| -
|
| +
|
| // at this point, literal contains the literal text
|
| // and i is the index of the next non-literal pattern character.
|
| int32_t p;
|
| int32_t t = textOffset;
|
| -
|
| +
|
| if (whitespaceLenient) {
|
| // trim leading, trailing whitespace from
|
| // the literal text
|
| literal.trim();
|
| -
|
| +
|
| // ignore any leading whitespace in the text
|
| while (t < text.length() && u_isWhitespace(text.charAt(t))) {
|
| t += 1;
|
| }
|
| }
|
| -
|
| +
|
| 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) {
|
| int32_t tStart = t;
|
| -
|
| +
|
| while (t < text.length()) {
|
| UChar tch = text.charAt(t);
|
| -
|
| +
|
| if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) {
|
| break;
|
| }
|
| -
|
| +
|
| t += 1;
|
| }
|
| -
|
| +
|
| // TODO: should we require internal spaces
|
| // in lenient mode? (There won't be any
|
| // leading or trailing spaces)
|
| @@ -2443,7 +2685,7 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
|
| // an error in strict mode
|
| return FALSE;
|
| }
|
| -
|
| +
|
| // In strict mode, this run of whitespace
|
| // may have been at the end.
|
| if (p >= literal.length()) {
|
| @@ -2461,26 +2703,26 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
|
| ++t;
|
| continue; // Do not update p.
|
| }
|
| - // if it is actual whitespace and we're whitespace lenient it's OK
|
| -
|
| + // if it is actual whitespace and we're whitespace lenient it's OK
|
| +
|
| UChar wsc = text.charAt(t);
|
| if(PatternProps::isWhiteSpace(wsc)) {
|
| // Lenient mode and it's just whitespace we skip it
|
| ++t;
|
| continue; // Do not update p.
|
| }
|
| - }
|
| + }
|
| // hack around oldleniency being a bit of a catch-all bucket and we're just adding support specifically for paritial matches
|
| - if(partialMatchLenient && oldLeniency) {
|
| + if(partialMatchLenient && oldLeniency) {
|
| break;
|
| }
|
| -
|
| +
|
| return FALSE;
|
| }
|
| ++p;
|
| ++t;
|
| }
|
| -
|
| +
|
| // At this point if we're in strict mode we have a complete match.
|
| // If we're in lenient mode we may have a partial match, or no
|
| // match at all.
|
| @@ -2492,20 +2734,20 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
|
| if (patternCharIndex != UDAT_FIELD_COUNT) {
|
| ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
|
| }
|
| -
|
| +
|
| for (t = textOffset; t < text.length(); t += 1) {
|
| UChar ch = text.charAt(t);
|
| -
|
| +
|
| if (ignorables == NULL || !ignorables->contains(ch)) {
|
| break;
|
| }
|
| }
|
| }
|
| -
|
| +
|
| // if we get here, we've got a complete match.
|
| patternOffset = i - 1;
|
| textOffset = t;
|
| -
|
| +
|
| return TRUE;
|
| }
|
|
|
| @@ -2542,8 +2784,7 @@ int32_t SimpleDateFormat::matchString(const UnicodeString& text,
|
| if (monthPattern != NULL) {
|
| UErrorCode status = U_ZERO_ERROR;
|
| UnicodeString leapMonthName;
|
| - Formattable monthName((const UnicodeString&)(data[i]));
|
| - MessageFormat::format(*monthPattern, &monthName, 1, leapMonthName, status);
|
| + SimpleFormatter(*monthPattern, 1, 1, status).format(data[i], leapMonthName, status);
|
| if (U_SUCCESS(status)) {
|
| if ((matchLen = matchStringWithOptionalDot(text, start, leapMonthName)) > bestMatchLength) {
|
| bestMatch = i;
|
| @@ -2614,7 +2855,8 @@ SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& 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, SimpleDateFormatMutableNFs &mutableNFs) const
|
| + int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs,
|
| + int32_t *dayPeriod) const
|
| {
|
| Formattable number;
|
| int32_t value = 0;
|
| @@ -2721,7 +2963,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| if (txtLoc > parseStart) {
|
| value = number.getLong();
|
| gotNumber = TRUE;
|
| -
|
| +
|
| // suffix processing
|
| if (value < 0 ) {
|
| txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
|
| @@ -2744,7 +2986,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| pos.setIndex(txtLoc);
|
| }
|
| }
|
| -
|
| +
|
| // Make sure that we got a number if
|
| // we want one, and didn't get one
|
| // if we don't want one.
|
| @@ -2757,9 +2999,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| if (value < 0 || value > 24) {
|
| return -start;
|
| }
|
| -
|
| +
|
| // fall through to gotNumber check
|
| -
|
| + U_FALLTHROUGH;
|
| case UDAT_YEAR_FIELD:
|
| case UDAT_YEAR_WOY_FIELD:
|
| case UDAT_FRACTIONAL_SECOND_FIELD:
|
| @@ -2767,9 +3009,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| if (! gotNumber) {
|
| return -start;
|
| }
|
| -
|
| +
|
| break;
|
| -
|
| +
|
| default:
|
| // we check the rest of the fields below.
|
| break;
|
| @@ -2948,9 +3190,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| // [We computed 'value' above.]
|
| if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
|
| value = 0;
|
| -
|
| +
|
| // fall through to set field
|
| -
|
| + U_FALLTHROUGH;
|
| case UDAT_HOUR_OF_DAY0_FIELD:
|
| cal.set(UCAL_HOUR_OF_DAY, value);
|
| return pos.getIndex();
|
| @@ -2983,6 +3225,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| }
|
| // else for eee-eeeee fall through to handling of EEE-EEEEE
|
| // fall through, do not break here
|
| + U_FALLTHROUGH;
|
| case UDAT_DAY_OF_WEEK_FIELD:
|
| {
|
| // Want to be able to parse both short and long forms.
|
| @@ -3073,9 +3316,9 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| // [We computed 'value' above.]
|
| if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
|
| value = 0;
|
| -
|
| +
|
| // fall through to set field
|
| -
|
| + U_FALLTHROUGH;
|
| case UDAT_HOUR0_FIELD:
|
| cal.set(UCAL_HOUR, value);
|
| return pos.getIndex();
|
| @@ -3265,7 +3508,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| }
|
| // currently no pattern character is defined for UDAT_TIME_SEPARATOR_FIELD
|
| // so we should not get here. Leave support in for future definition.
|
| - case UDAT_TIME_SEPARATOR_FIELD: //
|
| + case UDAT_TIME_SEPARATOR_FIELD:
|
| {
|
| static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;
|
| static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
|
| @@ -3288,6 +3531,70 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
|
| return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count, 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, mutableNFs);
|
| +
|
| + if (ampmStart > 0) {
|
| + return ampmStart;
|
| + } else {
|
| + int32_t newStart = 0;
|
| +
|
| + // Only match the first two strings from the day period strings array.
|
| + 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;
|
| + }
|
| + }
|
| + // count == 4, but allow other counts
|
| + 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:
|
| // Handle "generic" fields
|
| // this is now handled below, outside the switch block
|
| @@ -3427,7 +3734,7 @@ void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
|
| UErrorCode& status)
|
| {
|
| // run through the pattern and convert any pattern symbols from the version
|
| - // in "from" to the corresponding character ion "to". This code takes
|
| + // in "from" to the corresponding character in "to". This code takes
|
| // quoted strings into account (it doesn't try to translate them), and it signals
|
| // an error if a particular "pattern character" doesn't appear in "from".
|
| // Depending on the values of "from" and "to" this can convert from generic
|
| @@ -3491,6 +3798,7 @@ void
|
| SimpleDateFormat::applyPattern(const UnicodeString& pattern)
|
| {
|
| fPattern = pattern;
|
| + parsePattern();
|
| }
|
|
|
| //----------------------------------------------------------------------
|
| @@ -3818,6 +4126,28 @@ SimpleDateFormat::tzFormat() const {
|
| return fTimeZoneFormat;
|
| }
|
|
|
| +void SimpleDateFormat::parsePattern() {
|
| + fHasMinute = FALSE;
|
| + fHasSecond = 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 (!inQuote) {
|
| + if (ch == 0x6D) { // 0x6D == 'm'
|
| + fHasMinute = TRUE;
|
| + }
|
| + if (ch == 0x73) { // 0x73 == 's'
|
| + fHasSecond = TRUE;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| U_NAMESPACE_END
|
|
|
| #endif /* #if !UCONFIG_NO_FORMATTING */
|
|
|