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;
// 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.]
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;
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;
}
// 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
// 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:
}
}
}
+
+ 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());
+ }
+ }
+
+ }
+
+
}