ICU-10334 C vs. J differences when in lenient mode
X-SVN-Rev: 34791
This commit is contained in:
parent
876d3ee9a9
commit
59dde192b7
@ -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.
|
||||
*
|
||||
|
@ -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.
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user