ICU-10334 C vs. J differences when in lenient mode

X-SVN-Rev: 34791
This commit is contained in:
Scott Russell 2013-12-18 19:47:13 +00:00
parent 876d3ee9a9
commit 59dde192b7
4 changed files with 126 additions and 12 deletions

View File

@ -452,6 +452,8 @@ public abstract class DateFormat extends UFormat {
* PARSE_ALLOW_WHITESPACE - indicates whitespace tolerance. Also included is trailing dot tolerance.
* <br/>
* PARSE_ALLOW_NUMERIC - indicates tolerance of numeric data when String data may be assumed. eg: YEAR_NAME_FIELD
* <br/>
* PRASE_PARTIAL_MATCH - indicates tolerance of partial matches against pattern literals
*
* @internal ICU technology preview
*/
@ -465,7 +467,12 @@ public abstract class DateFormat extends UFormat {
* indicates tolerance of numeric data when String data may be assumed. eg: YEAR_NAME_FIELD
* @internal ICU technology preview
*/
PARSE_ALLOW_NUMERIC
PARSE_ALLOW_NUMERIC,
/**
* indicates tolerance of a partial literal match
* @draft ICU 53
*/
PARSE_PARTIAL_MATCH
};
/**
@ -1472,7 +1479,7 @@ public abstract class DateFormat extends UFormat {
return calendar.isLenient();
}
/**
/**
* set a boolean attribute for this instance. Aspects of DateFormat leniency are controlled by
* boolean attributes.
*

View File

@ -2438,6 +2438,9 @@ public class SimpleDateFormat extends DateFormat {
} else if ((pch == ' ' || pch == '.') && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_WHITESPACE)) {
++idx;
continue;
} else if (pos != originalPos && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_MATCH)) {
++idx;
continue;
}
break;
}
@ -2731,11 +2734,14 @@ public class SimpleDateFormat extends DateFormat {
if (patternCharIndex == 4 /*'k' HOUR_OF_DAY1_FIELD*/ ||
patternCharIndex == 15 /*'h' HOUR1_FIELD*/ ||
(patternCharIndex == 2 /*'M' MONTH_FIELD*/ && count <= 2) ||
(patternCharIndex == 26 /*'L' STAND_ALONE_MONTH*/ && count <= 2) ||
(patternCharIndex == 19 /*'e' DOW_LOCAL*/ && count <= 2) ||
patternCharIndex == 26 /*'L' STAND_ALONE_MONTH*/ ||
patternCharIndex == 19 /*'e' DOW_LOCAL*/ ||
patternCharIndex == 25 /*'c' STAND_ALONE_DAY_OF_WEEK*/ ||
patternCharIndex == 1 /*'y' YEAR */ || patternCharIndex == 18 /*'Y' YEAR_WOY */ ||
patternCharIndex == 30 /*'U' YEAR_NAME_FIELD, falls back to numeric */ ||
(patternCharIndex == 0 /*'G' ERA */ && isChineseCalendar) ||
patternCharIndex == 27 /* 'Q' - QUARTER*/ ||
patternCharIndex == 28 /* 'q' - STANDALONE QUARTER*/ ||
patternCharIndex == 8 /*'S' FRACTIONAL_SECOND */ )
{
// It would be good to unify this with the obeyCount logic below,
@ -2764,7 +2770,8 @@ public class SimpleDateFormat extends DateFormat {
} else {
number = parseInt(text, pos, allowNegative,currentNumberFormat);
}
if (number == null && patternCharIndex != 30) {
if (number == null && !allowNumericFallback(patternCharIndex)) {
// only return if pattern is NOT one that allows numeric fallback
return ~start;
}
}
@ -2853,7 +2860,8 @@ public class SimpleDateFormat extends DateFormat {
return ~start;
case 2: // 'M' - MONTH
case 26: // 'L' - STAND_ALONE_MONTH
if (count <= 2) { // i.e., M/MM, L/LL
if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
// i.e., M/MM, L/LL or lenient & have a number
// Don't want to parse the month if it is a string
// while pattern uses numeric style: M/MM, L/LL.
// [We computed 'value' above.]
@ -2918,7 +2926,8 @@ public class SimpleDateFormat extends DateFormat {
cal.set(Calendar.MILLISECOND, value);
return pos.getIndex();
case 19: // 'e' - DOW_LOCAL
if(count <= 2) { // i.e. e/ee
if(count <= 2 || (number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) ) {
// i.e. e/ee or lenient and have a number
cal.set(field, value);
return pos.getIndex();
}
@ -2946,6 +2955,11 @@ public class SimpleDateFormat extends DateFormat {
return newStart;
}
case 25: { // 'c' - STAND_ALONE_DAY_OF_WEEK
if(count == 1 || (number != null && (getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) ) {
// i.e. c or lenient and have a number
cal.set(field, value);
return pos.getIndex();
}
// Want to be able to parse at least wide, abbrev, short forms.
int newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneWeekdays, null, cal); // try cccc wide
if (newStart > 0) {
@ -3100,7 +3114,8 @@ public class SimpleDateFormat extends DateFormat {
return ~start;
}
case 27: // 'Q' - QUARTER
if (count <= 2) { // i.e., Q or QQ.
if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
// i.e., Q or QQ. or lenient & have number
// Don't want to parse the quarter if it is a string
// while pattern uses numeric style: Q or QQ.
// [We computed 'value' above.]
@ -3121,7 +3136,8 @@ public class SimpleDateFormat extends DateFormat {
}
case 28: // 'q' - STANDALONE QUARTER
if (count <= 2) { // i.e., q or qq.
if (count <= 2 || (number != null && getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC))) {
// i.e., q or qq. or lenient & have number
// Don't want to parse the quarter if it is a string
// while pattern uses numeric style: q or qq.
// [We computed 'value' above.]
@ -3170,6 +3186,22 @@ public class SimpleDateFormat extends DateFormat {
}
}
/**
* return true if the pattern specified by patternCharIndex is one that allows
* numeric fallback regardless of actual pattern size.
*/
private boolean allowNumericFallback(int patternCharIndex) {
if (patternCharIndex == 26 /*'L' STAND_ALONE_MONTH*/ ||
patternCharIndex == 19 /*'e' DOW_LOCAL*/ ||
patternCharIndex == 25 /*'c' STAND_ALONE_DAY_OF_WEEK*/ ||
patternCharIndex == 30 /*'U' YEAR_NAME_FIELD*/ ||
patternCharIndex == 27 /* 'Q' - QUARTER*/ ||
patternCharIndex == 28 /* 'q' - STANDALONE QUARTER*/) {
return true;
}
return false;
}
/**
* Parse an integer using numberFormat. This method is semantically
* const, but actually may modify fNumberFormat.

View File

@ -1275,5 +1275,80 @@ public class DateFormatRegressionTest extends com.ibm.icu.dev.test.TestFmwk {
}
}
}
public void TestT10334() {
String pattern = new String("'--: 'EEE-WW-MMMM-yyyy");
String text = new String("--mon-02-march-2011");
SimpleDateFormat format = new SimpleDateFormat(pattern);
format.setBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_MATCH, false);
try {
format.parse(text);
errln("parse partial match did NOT fail in strict mode!");
} catch (ParseException pe) {
// expected
}
format.setBooleanAttribute(DateFormat.BooleanAttribute.PARSE_PARTIAL_MATCH, true);
try {
format.parse(text);
} catch (ParseException pe) {
errln("parse partial match failure in lenient mode: " + pe.getLocalizedMessage());
}
pattern = new String("YYYY MM dd");
text = new String("2013 12 10");
format.applyPattern(pattern);
Date referenceDate = null;
try {
referenceDate = format.parse(text);
} catch (ParseException pe) {
errln("unable to instantiate reference date: " + pe.getLocalizedMessage());
}
FieldPosition fp = new FieldPosition(0);
pattern = new String("YYYY LL dd ee cc qq QQ");
format.applyPattern(pattern);
StringBuffer formattedString = new StringBuffer();
formattedString = format.format(referenceDate, formattedString, fp);
logln("ref date: " + formattedString);
pattern = new String("YYYY LLL dd eee ccc qqq QQQ");
text = new String("2013 12 10 03 3 04 04");
format.applyPattern(pattern);
logln(format.format(referenceDate));
format.setBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC, true);
ParsePosition pp = new ParsePosition(0);
format.parse(text, pp);
int errorIdx = pp.getErrorIndex();
if (errorIdx != -1) {
errln("numeric parse error at["+errorIdx+"] on char["+pattern.substring(errorIdx, errorIdx+1)+"] in pattern["+pattern+"]");
}
format.setBooleanAttribute(DateFormat.BooleanAttribute.PARSE_ALLOW_NUMERIC, false);
try {
format.parse(text);
errln("numeric parse did NOT fail in strict mode!");
} catch (ParseException pe) {
// expected
}
/*
* test to verify new code (and improve code coverage) for normal quarter processing
*/
text = new String("2013 Dec 10 Thu Thu Q4 Q4");
try {
format.parse(text);
} catch (ParseException pe) {
errln("normal quarter processing failed");
}
}
}

View File

@ -4320,7 +4320,7 @@ public class DateFormatTest extends com.ibm.icu.dev.test.TestFmwk {
if(p.getErrorIndex() != -1)
continue;
else
errln("error: unexpected parse success..."+item.parseString + " w/ lenient="+item.leniency+" should have faile");
errln("error: unexpected parse success..."+item.parseString + " w/ lenient="+item.leniency+" should have failed");
}
if(p.getErrorIndex() != -1) {
errln("error: parse error for string " +item.parseString + " -- idx["+p.getIndex()+"] errIdx["+p.getErrorIndex()+"]");
@ -4335,5 +4335,5 @@ public class DateFormatTest extends com.ibm.icu.dev.test.TestFmwk {
}
}
}
}