diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp index 28fd78f982d..30ab46082b2 100644 --- a/icu4c/source/i18n/smpdtfmt.cpp +++ b/icu4c/source/i18n/smpdtfmt.cpp @@ -248,7 +248,7 @@ SimpleDateFormat::SimpleDateFormat(UErrorCode& status) fOverrideList(NULL), fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) { - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status); initializeDefaultCentury(); } @@ -267,7 +267,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, { fDateOverride.setToBogus(); fTimeOverride.setToBogus(); - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); initialize(fLocale, status); initializeDefaultCentury(); @@ -288,7 +288,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, { fDateOverride.setTo(override); fTimeOverride.setToBogus(); - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); initialize(fLocale, status); initializeDefaultCentury(); @@ -312,7 +312,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, fDateOverride.setToBogus(); fTimeOverride.setToBogus(); - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); initialize(fLocale, status); @@ -335,7 +335,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, fDateOverride.setTo(override); fTimeOverride.setToBogus(); - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); initializeSymbols(fLocale, initializeCalendar(NULL,fLocale,status), status); initialize(fLocale, status); @@ -361,7 +361,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, fDateOverride.setToBogus(); fTimeOverride.setToBogus(); - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); initializeCalendar(NULL,fLocale,status); initialize(fLocale, status); @@ -384,7 +384,7 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern, fDateOverride.setToBogus(); fTimeOverride.setToBogus(); - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); initializeCalendar(NULL, fLocale, status); initialize(fLocale, status); @@ -405,7 +405,7 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle, fOverrideList(NULL), fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) { - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); construct(timeStyle, dateStyle, fLocale, status); if(U_SUCCESS(status)) { initializeDefaultCentury(); @@ -446,7 +446,7 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale, fDateOverride.setToBogus(); fTimeOverride.setToBogus(); - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); initialize(fLocale, status); if(U_SUCCESS(status)) { @@ -466,7 +466,7 @@ SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other) fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) { UErrorCode status = U_ZERO_ERROR; - setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status); + setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status).setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status).setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, true, status); *this = other; } @@ -1847,7 +1847,7 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& abutPat = -1; // End of any abutting fields - if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status))) { + if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, status))) { status = U_PARSE_ERROR; goto ExitParse; } @@ -2129,7 +2129,8 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern, int32_t &patternOffset, const UnicodeString &text, int32_t &textOffset, - UBool lenient) + UBool whitespaceLenient, + UBool partialMatchLenient) { UBool inQuote = FALSE; UnicodeString literal; @@ -2161,7 +2162,7 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern, int32_t p; int32_t t = textOffset; - if (lenient) { + if (whitespaceLenient) { // trim leading, trailing whitespace from // the literal text literal.trim(); @@ -2196,7 +2197,7 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern, // TODO: should we require internal spaces // in lenient mode? (There won't be any // leading or trailing spaces) - if (!lenient && t == tStart) { + if (!whitespaceLenient && t == tStart) { // didn't find matching whitespace: // an error in strict mode return FALSE; @@ -2212,7 +2213,7 @@ UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern, if (t >= text.length() || literal.charAt(p) != text.charAt(t)) { // Ran out of text, or found a non-matching character: // OK in lenient mode, an error in strict mode. - if (lenient) { + if (partialMatchLenient) { if (t == textOffset && text.charAt(t) == 0x2e && isAfterNonNumericField(pattern, patternOffset)) { // Lenient mode and the literal input text begins with a "." and diff --git a/icu4c/source/i18n/unicode/smpdtfmt.h b/icu4c/source/i18n/unicode/smpdtfmt.h index 0ce2161efc5..42f430d5d21 100644 --- a/icu4c/source/i18n/unicode/smpdtfmt.h +++ b/icu4c/source/i18n/unicode/smpdtfmt.h @@ -1340,12 +1340,14 @@ private: * @param text the text being parsed * @param textOffset the starting offset into the text. On output * will be set to the offset of the character after the match - * @param lenient TRUE if the parse is lenient, FALSE otherwise. + * @param whitespaceLenient TRUE if whitespace parse is lenient, FALSE otherwise. + * @param partialMatchLenient TRUE if partial match parse is lenient, FALSE otherwise. * * @return TRUE if the literal text could be matched, FALSE otherwise. */ static UBool matchLiterals(const UnicodeString &pattern, int32_t &patternOffset, - const UnicodeString &text, int32_t &textOffset, UBool lenient); + const UnicodeString &text, int32_t &textOffset, + UBool whitespaceLenient, UBool partialMatchLenient); /** * Private member function that converts the parsed date strings into diff --git a/icu4c/source/i18n/unicode/udat.h b/icu4c/source/i18n/unicode/udat.h index e8f0664e591..4437743f6b3 100644 --- a/icu4c/source/i18n/unicode/udat.h +++ b/icu4c/source/i18n/unicode/udat.h @@ -851,6 +851,11 @@ typedef enum UDateFormatBooleanAttribute { * @internal ICU technology preview */ UDAT_PARSE_ALLOW_NUMERIC, + /** + * indicates tolerance of a partial literal match + * @draft ICU 53 + */ + UDAT_PARSE_PARTIAL_MATCH, /** * count boolean date format constants * @internal ICU technology preview diff --git a/icu4c/source/test/intltest/dtfmrgts.cpp b/icu4c/source/test/intltest/dtfmrgts.cpp index a72976fe92a..8ffecd501df 100644 --- a/icu4c/source/test/intltest/dtfmrgts.cpp +++ b/icu4c/source/test/intltest/dtfmrgts.cpp @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2012, International Business Machines Corporation and + * Copyright (c) 1997-2013, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -57,6 +57,7 @@ DateFormatRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* CASE(26,Test5554) CASE(27,Test9237) CASE(28,TestParsing) + CASE(29,TestT10334) default: name = ""; break; } } @@ -1525,6 +1526,63 @@ void DateFormatRegressionTest::TestParsing(void) { delete cal; } +void DateFormatRegressionTest::TestT10334(void) { + UErrorCode status = U_ZERO_ERROR; + UnicodeString pattern("'--: 'EEE-WW-MMMM-yyyy"); + UnicodeString text("--mon-02-march-2011"); + SimpleDateFormat format(pattern, status); + + format.setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, FALSE, status); + format.parse(text, status); + if (!U_FAILURE(status)) { + errln("parse partial match did NOT fail in strict mode", u_errorName(status)); + } + + status = U_ZERO_ERROR; + format.setBooleanAttribute(UDAT_PARSE_PARTIAL_MATCH, TRUE, status); + format.parse(text, status); + if (U_FAILURE(status)) { + errln("parse partial match failure in lenient mode", u_errorName(status)); + } + + status = U_ZERO_ERROR; + pattern = UnicodeString("YYYY MM dd"); + text = UnicodeString("2013 12 10"); + format.applyPattern(pattern); + UDate referenceDate = format.parse(text, status); + + FieldPosition fp(0); + UnicodeString formattedString(""); + pattern = UnicodeString("YYYY LL dd ee cc qq QQ"); + format.applyPattern(pattern); + format.format(referenceDate, formattedString, fp, status); + logln("ref date: " + formattedString); + + + char patternArray[] = "YYYY LLL dd eee ccc qqq QQQ"; + pattern = UnicodeString(patternArray); + text = UnicodeString("2013 12 10 03 3 04 04"); + status = U_ZERO_ERROR; + format.setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, TRUE, status); + format.applyPattern(pattern); + ParsePosition pp(0); + format.parse(text, pp); + int32_t errorIdx = pp.getErrorIndex(); + if (errorIdx != -1) { + char buffer[256]; + _snprintf(buffer, 256, "numeric parse error at[%d] on pattern char[%s]", errorIdx, &patternArray[errorIdx]); + errln(buffer); + } + + status = U_ZERO_ERROR; + format.setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, FALSE, status); + format.parse(text, status); + if (!U_FAILURE(status)) { + errln("numeric parse did NOT fail in strict mode", u_errorName(status)); + } + +} + #endif /* #if !UCONFIG_NO_FORMATTING */ //eof diff --git a/icu4c/source/test/intltest/dtfmrgts.h b/icu4c/source/test/intltest/dtfmrgts.h index 21e2db015ce..1d5ed01b7c1 100644 --- a/icu4c/source/test/intltest/dtfmrgts.h +++ b/icu4c/source/test/intltest/dtfmrgts.h @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 1997-2012, International Business Machines Corporation and + * Copyright (c) 1997-2013, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -53,6 +53,7 @@ public: void Test5554(void); void Test9237(void); void TestParsing(void); + void TestT10334(void); }; #endif /* #if !UCONFIG_NO_FORMATTING */