ICU-10336 merge branch into trunk

X-SVN-Rev: 35318
This commit is contained in:
Scott Russell 2014-03-04 14:39:12 +00:00
parent e9bdf144db
commit b0c6d643db
3 changed files with 157 additions and 34 deletions

View File

@ -456,14 +456,21 @@ public abstract class DateFormat extends UFormat {
public enum BooleanAttribute {
/**
* indicates whitespace tolerance. Also included is trailing dot tolerance.
* @internal ICU technology preview
* @draft ICU 53
*/
PARSE_ALLOW_WHITESPACE,
/**
* indicates tolerance of numeric data when String data may be assumed. eg: YEAR_NAME_FIELD
* @internal ICU technology preview
* indicates tolerance of numeric data when String data may be assumed.
* e.g. YEAR_NAME_FIELD
* @draft ICU 53
*/
PARSE_ALLOW_NUMERIC,
/**
* indicates tolerance of pattern mismatch between input data and specified format pattern.
* e.g. accepting "September" for a month pattern of MMM ("Sep")
* @draft ICU 53
*/
PARSE_MULTIPLE_PATTERNS_FOR_MATCH,
/**
* indicates tolerance of a partial literal match
* @draft ICU 53

View File

@ -28,7 +28,6 @@ import com.ibm.icu.impl.ICUCache;
import com.ibm.icu.impl.PatternProps;
import com.ibm.icu.impl.SimpleCache;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.BreakIterator;
import com.ibm.icu.text.TimeZoneFormat.Style;
import com.ibm.icu.text.TimeZoneFormat.TimeType;
import com.ibm.icu.util.BasicTimeZone;
@ -2918,21 +2917,27 @@ public class SimpleDateFormat extends DateFormat {
// count >= 3 // i.e., MMM/MMMM or LLL/LLLL
// Want to be able to parse both short and long forms.
boolean haveMonthPat = (formatData.leapMonthPatterns != null && formatData.leapMonthPatterns.length >= DateFormatSymbols.DT_MONTH_PATTERN_COUNT);
// Try count == 4 first:
int newStart = (patternCharIndex == 2)?
// Try count == 4 first:, unless we're strict
int newStart = 0;
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
newStart = (patternCharIndex == 2)?
matchString(text, start, Calendar.MONTH, formatData.months,
(haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_WIDE]: null, cal):
matchString(text, start, Calendar.MONTH, formatData.standaloneMonths,
(haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_WIDE]: null, cal);
if (newStart > 0) {
return newStart;
} else { // count == 4 failed, now try count == 3
}
}
// count == 4 failed, now try count == 3
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
return (patternCharIndex == 2)?
matchString(text, start, Calendar.MONTH, formatData.shortMonths,
(haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_FORMAT_ABBREV]: null, cal):
matchString(text, start, Calendar.MONTH, formatData.standaloneShortMonths,
(haveMonthPat)? formatData.leapMonthPatterns[DateFormatSymbols.DT_LEAP_MONTH_PATTERN_STANDALONE_ABBREV]: null, cal);
}
return newStart;
}
case 4: // 'k' - HOUR_OF_DAY (1..24)
// [We computed 'value' above.]
@ -2970,20 +2975,28 @@ public class SimpleDateFormat extends DateFormat {
case 9: { // 'E' - DAY_OF_WEEK
// Want to be able to parse at least wide, abbrev, short, and narrow forms.
int newStart = 0;
if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.weekdays, null, cal)) > 0) { // try EEEE wide
return newStart;
}
if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shortWeekdays, null, cal)) > 0) { // try EEE abbrev
return newStart;
}
if (formatData.shorterWeekdays != null) {
if((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shorterWeekdays, null, cal)) > 0) { // try EEEEEE short
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.weekdays, null, cal)) > 0) { // try EEEE wide
return newStart;
}
}
if (formatData.narrowWeekdays != null) {
if((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.narrowWeekdays, null, cal)) > 0) { // try EEEEE narrow
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shortWeekdays, null, cal)) > 0) { // try EEE abbrev
return newStart;
}
}
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 6) {
if (formatData.shorterWeekdays != null) {
if((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.shorterWeekdays, null, cal)) > 0) { // try EEEEEE short
return newStart;
}
}
}
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 5) {
if (formatData.narrowWeekdays != null) {
if((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.narrowWeekdays, null, cal)) > 0) { // try EEEEE narrow
return newStart;
}
}
}
return newStart;
@ -2995,13 +3008,21 @@ public class SimpleDateFormat extends DateFormat {
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) {
return newStart;
} else if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShortWeekdays, null, cal)) > 0) { // try ccc abbrev
return newStart;
} else if (formatData.standaloneShorterWeekdays != null) {
return matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShorterWeekdays, null, cal); // try cccccc short
int newStart = 0;
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneWeekdays, null, cal)) > 0) { // try cccc wide
return newStart;
}
}
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
if ((newStart = matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShortWeekdays, null, cal)) > 0) { // try ccc abbrev
return newStart;
}
}
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 6) {
if (formatData.standaloneShorterWeekdays != null) {
return matchString(text, start, Calendar.DAY_OF_WEEK, formatData.standaloneShorterWeekdays, null, cal); // try cccccc short
}
}
return newStart;
}
@ -3145,14 +3166,18 @@ public class SimpleDateFormat extends DateFormat {
// count >= 3 // i.e., QQQ or QQQQ
// Want to be able to parse both short and long forms.
// Try count == 4 first:
int newStart = matchQuarterString(text, start, Calendar.MONTH,
formatData.quarters, cal);
if (newStart > 0) {
return newStart;
} else { // count == 4 failed, now try count == 3
int newStart = 0;
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
if((newStart = matchQuarterString(text, start, Calendar.MONTH, formatData.quarters, cal)) > 0) {
return newStart;
}
}
// count == 4 failed, now try count == 3
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
return matchQuarterString(text, start, Calendar.MONTH,
formatData.shortQuarters, cal);
}
return newStart;
}
case 28: // 'q' - STANDALONE QUARTER
@ -3167,14 +3192,18 @@ public class SimpleDateFormat extends DateFormat {
// count >= 3 // i.e., qqq or qqqq
// Want to be able to parse both short and long forms.
// Try count == 4 first:
int newStart = matchQuarterString(text, start, Calendar.MONTH,
formatData.standaloneQuarters, cal);
if (newStart > 0) {
return newStart;
} else { // count == 4 failed, now try count == 3
int newStart = 0;
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 4) {
if((newStart = matchQuarterString(text, start, Calendar.MONTH, formatData.standaloneQuarters, cal)) > 0) {
return newStart;
}
}
// count == 4 failed, now try count == 3
if(getBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH) || count == 3) {
return matchQuarterString(text, start, Calendar.MONTH,
formatData.standaloneShortQuarters, cal);
}
return newStart;
}
default:

View File

@ -4499,4 +4499,91 @@ public class DateFormatTest extends com.ibm.icu.dev.test.TestFmwk {
}
}
}
public void TestParseMultiPatternMatch() {
// For details see http://bugs.icu-project.org/trac/ticket/10336
class TestMultiPatternMatchItem {
public boolean leniency;
public String parseString;
public String pattern;
public String expectedResult; // null indicates expected error
// Simple constructor
public TestMultiPatternMatchItem(boolean len, String parString, String patt, String expResult) {
leniency = len;
pattern = patt;
parseString = parString;
expectedResult = expResult;
}
};
final TestMultiPatternMatchItem[] items = {
// leniency parse String pattern expected result
new TestMultiPatternMatchItem(true, "2013-Sep 13", "yyyy-MMM dd", "2013-Sep 13"),
new TestMultiPatternMatchItem(true, "2013-September 14", "yyyy-MMM dd", "2013-Sep 14"),
new TestMultiPatternMatchItem(false, "2013-September 15", "yyyy-MMM dd", null),
new TestMultiPatternMatchItem(false, "2013-September 16", "yyyy-MMMM dd", "2013-September 16"),
new TestMultiPatternMatchItem(true, "2013-Sep 17", "yyyy-LLL dd", "2013-Sep 17"),
new TestMultiPatternMatchItem(true, "2013-September 18", "yyyy-LLL dd", "2013-Sep 18"),
new TestMultiPatternMatchItem(false, "2013-September 19", "yyyy-LLL dd", null),
new TestMultiPatternMatchItem(false, "2013-September 20", "yyyy-LLLL dd", "2013-September 20"),
new TestMultiPatternMatchItem(true, "2013 Sat Sep 21", "yyyy EEE MMM dd", "2013 Sat Sep 21"),
new TestMultiPatternMatchItem(true, "2013 Sunday Sep 22", "yyyy EEE MMM dd", "2013 Sun Sep 22"),
new TestMultiPatternMatchItem(false, "2013 Monday Sep 23", "yyyy EEE MMM dd", null),
new TestMultiPatternMatchItem(false, "2013 Tuesday Sep 24", "yyyy EEEE MMM dd", "2013 Tuesday Sep 24"),
new TestMultiPatternMatchItem(true, "2013 Wed Sep 25", "yyyy eee MMM dd", "2013 Wed Sep 25"),
new TestMultiPatternMatchItem(true, "2013 Thu Sep 26", "yyyy eee MMM dd", "2013 Thu Sep 26"),
new TestMultiPatternMatchItem(false, "2013 Friday Sep 27", "yyyy eee MMM dd", null),
new TestMultiPatternMatchItem(false, "2013 Saturday Sep 28", "yyyy eeee MMM dd", "2013 Saturday Sep 28"),
new TestMultiPatternMatchItem(true, "2013 Sun Sep 29", "yyyy ccc MMM dd", "2013 Sun Sep 29"),
new TestMultiPatternMatchItem(true, "2013 Monday Sep 30", "yyyy ccc MMM dd", "2013 Mon Sep 30"),
new TestMultiPatternMatchItem(false, "2013 Sunday Oct 13", "yyyy ccc MMM dd", null),
new TestMultiPatternMatchItem(false, "2013 Monday Oct 14", "yyyy cccc MMM dd", "2013 Monday Oct 14"),
new TestMultiPatternMatchItem(true, "2013 Oct 15 Q4", "yyyy MMM dd QQQ", "2013 Oct 15 Q4"),
new TestMultiPatternMatchItem(true, "2013 Oct 16 4th quarter", "yyyy MMM dd QQQ", "2013 Oct 16 Q4"),
new TestMultiPatternMatchItem(false, "2013 Oct 17 4th quarter", "yyyy MMM dd QQQ", null),
new TestMultiPatternMatchItem(false, "2013 Oct 18 Q4", "yyyy MMM dd QQQ", "2013 Oct 18 Q4"),
new TestMultiPatternMatchItem(true, "2013 Oct 19 Q4", "yyyy MMM dd qqqq", "2013 Oct 19 4th quarter"),
new TestMultiPatternMatchItem(true, "2013 Oct 20 4th quarter", "yyyy MMM dd qqqq", "2013 Oct 20 4th quarter"),
new TestMultiPatternMatchItem(false, "2013 Oct 21 Q4", "yyyy MMM dd qqqq", null),
new TestMultiPatternMatchItem(false, "2013 Oct 22 4th quarter", "yyyy MMM dd qqqq", "2013 Oct 22 4th quarter"),
};
StringBuffer result = new StringBuffer();
Date d = new Date();
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"), Locale.US);
SimpleDateFormat sdfmt = new SimpleDateFormat();
ParsePosition p = new ParsePosition(0);
for (TestMultiPatternMatchItem item: items) {
cal.clear();
sdfmt.setCalendar(cal);
sdfmt.applyPattern(item.pattern);
sdfmt.setLenient(item.leniency);
sdfmt.setBooleanAttribute(DateFormat.BooleanAttribute.PARSE_MULTIPLE_PATTERNS_FOR_MATCH, item.leniency);
result.setLength(0);
p.setIndex(0);
p.setErrorIndex(-1);
d = sdfmt.parse(item.parseString, p);
if(item.expectedResult == null) {
if(p.getErrorIndex() != -1)
continue;
else
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()+"]");
continue;
}
cal.setTime(d);
result = sdfmt.format(cal, result, new FieldPosition(0));
if(!result.toString().equalsIgnoreCase(item.expectedResult)) {
errln("error: unexpected format result. expected - " + item.expectedResult + " but result was - " + result);
} else {
logln("formatted results match! - " + result.toString());
}
}
}
}