mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-16 02:07:15 +00:00
ICU-11706 (and #11726) Fix DateIntervalFormat handling of (1) skeletons with seconds, (2) FieldPosition (J)
X-SVN-Rev: 37615
This commit is contained in:
parent
a8325d335c
commit
a1b8a08bf7
3 changed files with 336 additions and 36 deletions
icu4j/main
classes/core/src/com/ibm/icu/text
tests/core/src/com/ibm/icu/dev/test/format
|
@ -85,9 +85,11 @@ import com.ibm.icu.util.ULocale.Category;
|
|||
*
|
||||
* <P>
|
||||
* The calendar fields we support for interval formatting are:
|
||||
* year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
|
||||
* year, month, date, day-of-week, am-pm, hour, hour-of-day, minute, and
|
||||
* second (though we do not currently have specific intervalFormat data for
|
||||
* skeletons with seconds).
|
||||
* Those calendar fields can be defined in the following order:
|
||||
* year > month > date > hour (in day) > minute
|
||||
* year > month > date > hour (in day) > minute > second
|
||||
*
|
||||
* The largest different calendar fields between 2 calendars is the
|
||||
* first different calendar field in above order.
|
||||
|
@ -216,7 +218,8 @@ import com.ibm.icu.util.ULocale.Category;
|
|||
* dtitvinf = new DateIntervalInfo();
|
||||
*
|
||||
* // a series of set interval patterns.
|
||||
* // Only ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE are supported.
|
||||
* // Only ERA, YEAR, MONTH, DATE, DAY_OF_MONTH, DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY,
|
||||
* MINUTE and SECOND are supported.
|
||||
* dtitvinf.setIntervalPattern("yMMMd", Calendar.YEAR, "'y ~ y'");
|
||||
* dtitvinf.setIntervalPattern("yMMMd", Calendar.MONTH, "yyyy 'diff' MMM d - MMM d");
|
||||
* dtitvinf.setIntervalPattern("yMMMd", Calendar.DATE, "yyyy MMM d ~ d");
|
||||
|
@ -307,7 +310,7 @@ public class DateIntervalFormat extends UFormat {
|
|||
|
||||
/*
|
||||
* Following are transient interval information
|
||||
* relavent (locale) to this formatter.
|
||||
* relevant (locale) to this formatter.
|
||||
*/
|
||||
private String fSkeleton = null;
|
||||
|
||||
|
@ -321,6 +324,13 @@ public class DateIntervalFormat extends UFormat {
|
|||
* Interval patterns for this instance's locale.
|
||||
*/
|
||||
private transient Map<String, PatternInfo> fIntervalPatterns = null;
|
||||
|
||||
/*
|
||||
* Patterns for fallback formatting.
|
||||
*/
|
||||
private String fDatePattern = null;
|
||||
private String fTimePattern = null;
|
||||
private String fDateTimeFormat = null;
|
||||
|
||||
|
||||
/*
|
||||
|
@ -556,6 +566,9 @@ public class DateIntervalFormat extends UFormat {
|
|||
other.fInfo = (DateIntervalInfo) fInfo.clone();
|
||||
other.fFromCalendar = (Calendar) fFromCalendar.clone();
|
||||
other.fToCalendar = (Calendar) fToCalendar.clone();
|
||||
other.fDatePattern = fDatePattern;
|
||||
other.fTimePattern = fTimePattern;
|
||||
other.fDateTimeFormat = fDateTimeFormat;
|
||||
return other;
|
||||
}
|
||||
|
||||
|
@ -572,6 +585,9 @@ public class DateIntervalFormat extends UFormat {
|
|||
* Result is appended to existing contents.
|
||||
* @param fieldPosition On input: an alignment field, if desired.
|
||||
* On output: the offsets of the alignment field.
|
||||
* There may be multiple instances of a given field type
|
||||
* in an interval format; in this case the fieldPosition
|
||||
* offsets refer to the first instance.
|
||||
* @return Reference to 'appendTo' parameter.
|
||||
* @throws IllegalArgumentException if the formatted object is not
|
||||
* DateInterval object
|
||||
|
@ -596,6 +612,9 @@ public class DateIntervalFormat extends UFormat {
|
|||
* Result is appended to existing contents.
|
||||
* @param fieldPosition On input: an alignment field, if desired.
|
||||
* On output: the offsets of the alignment field.
|
||||
* There may be multiple instances of a given field type
|
||||
* in an interval format; in this case the fieldPosition
|
||||
* offsets refer to the first instance.
|
||||
* @return Reference to 'appendTo' parameter.
|
||||
* @stable ICU 4.0
|
||||
*/
|
||||
|
@ -638,6 +657,9 @@ public class DateIntervalFormat extends UFormat {
|
|||
} else if ( fromCalendar.get(Calendar.MINUTE) !=
|
||||
toCalendar.get(Calendar.MINUTE) ) {
|
||||
field = Calendar.MINUTE;
|
||||
} else if ( fromCalendar.get(Calendar.SECOND) !=
|
||||
toCalendar.get(Calendar.SECOND) ) {
|
||||
field = Calendar.SECOND;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
@ -657,6 +679,9 @@ public class DateIntervalFormat extends UFormat {
|
|||
* Result is appended to existing contents.
|
||||
* @param pos On input: an alignment field, if desired.
|
||||
* On output: the offsets of the alignment field.
|
||||
* There may be multiple instances of a given field type
|
||||
* in an interval format; in this case the fieldPosition
|
||||
* offsets refer to the first instance.
|
||||
* @return Reference to 'appendTo' parameter.
|
||||
* @throws IllegalArgumentException if the two calendars are not equivalent.
|
||||
* @stable ICU 4.0
|
||||
|
@ -694,12 +719,16 @@ public class DateIntervalFormat extends UFormat {
|
|||
} else if ( fromCalendar.get(Calendar.MINUTE) !=
|
||||
toCalendar.get(Calendar.MINUTE) ) {
|
||||
field = Calendar.MINUTE;
|
||||
} else {
|
||||
/* ignore the second/millisecond etc. small fields' difference.
|
||||
} else if ( fromCalendar.get(Calendar.SECOND) !=
|
||||
toCalendar.get(Calendar.SECOND) ) {
|
||||
field = Calendar.SECOND;
|
||||
} else {
|
||||
/* ignore the millisecond etc. small fields' difference.
|
||||
* use single date when all the above are the same.
|
||||
*/
|
||||
return fDateFormat.format(fromCalendar, appendTo, pos);
|
||||
}
|
||||
boolean fromToOnSameDay = (field==Calendar.AM_PM || field==Calendar.HOUR || field==Calendar.MINUTE || field==Calendar.SECOND);
|
||||
|
||||
// get interval pattern
|
||||
PatternInfo intervalPattern = fIntervalPatterns.get(
|
||||
|
@ -714,7 +743,7 @@ public class DateIntervalFormat extends UFormat {
|
|||
return fDateFormat.format(fromCalendar, appendTo, pos);
|
||||
}
|
||||
|
||||
return fallbackFormat(fromCalendar, toCalendar, appendTo, pos);
|
||||
return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos);
|
||||
}
|
||||
|
||||
// If the first part in interval pattern is empty,
|
||||
|
@ -722,7 +751,7 @@ public class DateIntervalFormat extends UFormat {
|
|||
// For a 'real' interval pattern, the first part will never be empty.
|
||||
if ( intervalPattern.getFirstPart() == null ) {
|
||||
// fall back
|
||||
return fallbackFormat(fromCalendar, toCalendar, appendTo, pos,
|
||||
return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos,
|
||||
intervalPattern.getSecondPart());
|
||||
}
|
||||
Calendar firstCal;
|
||||
|
@ -741,12 +770,48 @@ public class DateIntervalFormat extends UFormat {
|
|||
fDateFormat.format(firstCal, appendTo, pos);
|
||||
if ( intervalPattern.getSecondPart() != null ) {
|
||||
fDateFormat.applyPattern(intervalPattern.getSecondPart());
|
||||
fDateFormat.format(secondCal, appendTo, pos);
|
||||
FieldPosition otherPos = new FieldPosition(pos.getField());
|
||||
fDateFormat.format(secondCal, appendTo, otherPos);
|
||||
if (pos.getEndIndex() == 0 && otherPos.getEndIndex() > 0) {
|
||||
pos = otherPos;
|
||||
}
|
||||
}
|
||||
fDateFormat.applyPattern(originalPattern);
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
private void adjustPosition(String combiningPattern, // has {0} and {1} in it
|
||||
String pat0, FieldPosition pos0, // pattern and pos corresponding to {0}
|
||||
String pat1, FieldPosition pos1, // pattern and pos corresponding to {1}
|
||||
FieldPosition posResult) {
|
||||
int index0 = combiningPattern.indexOf("{0}");
|
||||
int index1 = combiningPattern.indexOf("{1}");
|
||||
if (index0 < 0 || index1 < 0) {
|
||||
return;
|
||||
}
|
||||
int placeholderLen = 3; // length of "{0}" or "{1}"
|
||||
if (index0 < index1) {
|
||||
if (pos0.getEndIndex() > 0) {
|
||||
posResult.setBeginIndex(pos0.getBeginIndex() + index0);
|
||||
posResult.setEndIndex(pos0.getEndIndex() + index0);
|
||||
} else if (pos1.getEndIndex() > 0) {
|
||||
// here index1 >= 3
|
||||
index1 += pat0.length() - placeholderLen; // adjust for pat0 replacing {0}
|
||||
posResult.setBeginIndex(pos1.getBeginIndex() + index1);
|
||||
posResult.setEndIndex(pos1.getEndIndex() + index1);
|
||||
}
|
||||
} else {
|
||||
if (pos1.getEndIndex() > 0) {
|
||||
posResult.setBeginIndex(pos1.getBeginIndex() + index1);
|
||||
posResult.setEndIndex(pos1.getEndIndex() + index1);
|
||||
} else if (pos0.getEndIndex() > 0) {
|
||||
// here index0 >= 3
|
||||
index0 += pat1.length() - placeholderLen; // adjust for pat1 replacing {1}
|
||||
posResult.setBeginIndex(pos0.getBeginIndex() + index0);
|
||||
posResult.setEndIndex(pos0.getEndIndex() + index0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Format 2 Calendars to using fall-back interval pattern
|
||||
|
@ -766,17 +831,41 @@ public class DateIntervalFormat extends UFormat {
|
|||
*/
|
||||
private final StringBuffer fallbackFormat(Calendar fromCalendar,
|
||||
Calendar toCalendar,
|
||||
boolean fromToOnSameDay,
|
||||
StringBuffer appendTo,
|
||||
FieldPosition pos) {
|
||||
String fullPattern = null; // for saving the pattern in fDateFormat
|
||||
boolean formatDatePlusTimeRange = (fromToOnSameDay && fDatePattern != null && fTimePattern != null);
|
||||
// the fall back
|
||||
if (formatDatePlusTimeRange) {
|
||||
fullPattern = fDateFormat.toPattern(); // save current pattern, restore later
|
||||
fDateFormat.applyPattern(fTimePattern);
|
||||
}
|
||||
FieldPosition otherPos = new FieldPosition(pos.getField());
|
||||
StringBuffer earlierDate = new StringBuffer(64);
|
||||
earlierDate = fDateFormat.format(fromCalendar, earlierDate, pos);
|
||||
StringBuffer laterDate = new StringBuffer(64);
|
||||
laterDate = fDateFormat.format(toCalendar, laterDate, pos);
|
||||
laterDate = fDateFormat.format(toCalendar, laterDate, otherPos);
|
||||
String fallbackPattern = fInfo.getFallbackIntervalPattern();
|
||||
String fallback = MessageFormat.format(fallbackPattern, new Object[]
|
||||
adjustPosition(fallbackPattern, earlierDate.toString(), pos, laterDate.toString(), otherPos, pos);
|
||||
String fallbackRange = MessageFormat.format(fallbackPattern, new Object[]
|
||||
{earlierDate.toString(), laterDate.toString()});
|
||||
appendTo.append(fallback);
|
||||
if (formatDatePlusTimeRange) {
|
||||
// fallbackRange has just the time range, need to format the date part and combine that
|
||||
fDateFormat.applyPattern(fDatePattern);
|
||||
StringBuffer datePortion = new StringBuffer(64);
|
||||
otherPos.setBeginIndex(0);
|
||||
otherPos.setEndIndex(0);
|
||||
datePortion = fDateFormat.format(fromCalendar, datePortion, otherPos);
|
||||
adjustPosition(fDateTimeFormat, fallbackRange, pos, datePortion.toString(), otherPos, pos);
|
||||
fallbackRange = MessageFormat.format(fDateTimeFormat, new Object[]
|
||||
{fallbackRange, datePortion.toString()});
|
||||
}
|
||||
appendTo.append(fallbackRange);
|
||||
if (formatDatePlusTimeRange) {
|
||||
// restore full pattern
|
||||
fDateFormat.applyPattern(fullPattern);
|
||||
}
|
||||
return appendTo;
|
||||
}
|
||||
|
||||
|
@ -800,12 +889,13 @@ public class DateIntervalFormat extends UFormat {
|
|||
*/
|
||||
private final StringBuffer fallbackFormat(Calendar fromCalendar,
|
||||
Calendar toCalendar,
|
||||
boolean fromToOnSameDay,
|
||||
StringBuffer appendTo,
|
||||
FieldPosition pos,
|
||||
String fullPattern) {
|
||||
String originalPattern = fDateFormat.toPattern();
|
||||
fDateFormat.applyPattern(fullPattern);
|
||||
fallbackFormat(fromCalendar, toCalendar, appendTo, pos);
|
||||
fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos);
|
||||
fDateFormat.applyPattern(originalPattern);
|
||||
return appendTo;
|
||||
}
|
||||
|
@ -1030,10 +1120,22 @@ public class DateIntervalFormat extends UFormat {
|
|||
String normalizedDateSkeleton = normalizedDate.toString();
|
||||
String normalizedTimeSkeleton = normalizedTime.toString();
|
||||
|
||||
// move this up here since we need it for fallbacks
|
||||
if (time.length() != 0 && date.length() != 0) {
|
||||
// Need the Date/Time pattern for concatnation the date with
|
||||
// the time interval.
|
||||
// The date/time pattern ( such as {0} {1} ) is saved in
|
||||
// calendar, that is why need to get the CalendarData here.
|
||||
CalendarData calData = new CalendarData(locale, null);
|
||||
String[] patterns = calData.getDateTimePatterns();
|
||||
fDateTimeFormat = patterns[8];
|
||||
}
|
||||
|
||||
boolean found = genSeparateDateTimePtn(normalizedDateSkeleton,
|
||||
normalizedTimeSkeleton,
|
||||
intervalPatterns);
|
||||
intervalPatterns, dtpng);
|
||||
|
||||
// for skeletons with seconds, found is false and we enter this block
|
||||
if ( found == false ) {
|
||||
// use fallback
|
||||
// TODO: if user asks "m", but "d" differ
|
||||
|
@ -1137,16 +1239,13 @@ public class DateIntervalFormat extends UFormat {
|
|||
* 2) otherwise, present the date followed by the
|
||||
* range expression for the time.
|
||||
*/
|
||||
// Need the Date/Time pattern for concatnation the date with
|
||||
// the time interval.
|
||||
// The date/time pattern ( such as {0} {1} ) is saved in
|
||||
// calendar, that is why need to get the CalendarData here.
|
||||
CalendarData calData = new CalendarData(locale, null);
|
||||
String[] patterns = calData.getDateTimePatterns();
|
||||
if (fDateTimeFormat == null) {
|
||||
fDateTimeFormat = "{1} {0}";
|
||||
}
|
||||
String datePattern =dtpng.getBestPattern(dateSkeleton);
|
||||
concatSingleDate2TimeInterval(patterns[8], datePattern, Calendar.AM_PM, intervalPatterns);
|
||||
concatSingleDate2TimeInterval(patterns[8], datePattern, Calendar.HOUR, intervalPatterns);
|
||||
concatSingleDate2TimeInterval(patterns[8], datePattern, Calendar.MINUTE, intervalPatterns);
|
||||
concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.AM_PM, intervalPatterns);
|
||||
concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.HOUR, intervalPatterns);
|
||||
concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.MINUTE, intervalPatterns);
|
||||
}
|
||||
|
||||
return intervalPatterns;
|
||||
|
@ -1383,12 +1482,13 @@ public class DateIntervalFormat extends UFormat {
|
|||
*/
|
||||
private boolean genSeparateDateTimePtn(String dateSkeleton,
|
||||
String timeSkeleton,
|
||||
Map<String, PatternInfo> intervalPatterns)
|
||||
Map<String, PatternInfo> intervalPatterns,
|
||||
DateTimePatternGenerator dtpng)
|
||||
{
|
||||
String skeleton;
|
||||
// if both date and time skeleton present,
|
||||
// the final interval pattern might include time interval patterns
|
||||
// ( when, am_pm, hour, minute differ ),
|
||||
// ( when, am_pm, hour, minute, second differ ),
|
||||
// but not date interval patterns ( when year, month, day differ ).
|
||||
// For year/month/day differ, it falls back to fall-back pattern.
|
||||
if ( timeSkeleton.length() != 0 ) {
|
||||
|
@ -1410,11 +1510,22 @@ public class DateIntervalFormat extends UFormat {
|
|||
String bestSkeleton = retValue.bestMatchSkeleton;
|
||||
int differenceInfo = retValue.bestMatchDistanceInfo;
|
||||
|
||||
// Set patterns for fallback use, need to do this
|
||||
// before returning if differenceInfo == -1
|
||||
if (dateSkeleton.length() != 0 ) {
|
||||
fDatePattern = dtpng.getBestPattern(dateSkeleton);
|
||||
}
|
||||
if (timeSkeleton.length() != 0 ) {
|
||||
fTimePattern = dtpng.getBestPattern(timeSkeleton);
|
||||
}
|
||||
|
||||
// difference:
|
||||
// 0 means the best matched skeleton is the same as input skeleton
|
||||
// 1 means the fields are the same, but field width are different
|
||||
// 2 means the only difference between fields are v/z,
|
||||
// -1 means there are other fields difference
|
||||
// (this will happen, for instance, if the supplied skeleton has seconds,
|
||||
// but no skeletons in the intervalFormats data do)
|
||||
if ( differenceInfo == -1 ) {
|
||||
// skeleton has different fields, not only v/z difference
|
||||
return false;
|
||||
|
|
|
@ -71,9 +71,11 @@ import com.ibm.icu.util.UResourceBundle;
|
|||
*
|
||||
* <P>
|
||||
* The calendar fields we support for interval formatting are:
|
||||
* year, month, date, day-of-week, am-pm, hour, hour-of-day, and minute.
|
||||
* year, month, date, day-of-week, am-pm, hour, hour-of-day, minute, and
|
||||
* second (though we do not currently have specific intervalFormat data for
|
||||
* skeletons with seconds).
|
||||
* Those calendar fields can be defined in the following order:
|
||||
* year > month > date > am-pm > hour > minute
|
||||
* year > month > date > am-pm > hour > minute > second
|
||||
*
|
||||
* The largest different calendar fields between 2 calendars is the
|
||||
* first different calendar field in above order.
|
||||
|
@ -134,7 +136,7 @@ import com.ibm.icu.util.UResourceBundle;
|
|||
* the interval patterns using setIntervalPattern function as so desired.
|
||||
* Currently, users can only set interval patterns when the following
|
||||
* calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH,
|
||||
* DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE.
|
||||
* DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, MINUTE and SECOND.
|
||||
* Interval patterns when other calendar fields are different is not supported.
|
||||
* <P>
|
||||
* DateIntervalInfo objects are cloneable.
|
||||
|
@ -285,7 +287,7 @@ public class DateIntervalInfo implements Cloneable, Freezable<DateIntervalInfo>,
|
|||
|
||||
private static final long serialVersionUID = 1;
|
||||
private static final int MINIMUM_SUPPORTED_CALENDAR_FIELD =
|
||||
Calendar.MINUTE;
|
||||
Calendar.SECOND;
|
||||
//private static boolean DEBUG = true;
|
||||
|
||||
private static String FALLBACK_STRING = "fallback";
|
||||
|
@ -478,6 +480,8 @@ public class DateIntervalInfo implements Cloneable, Freezable<DateIntervalInfo>,
|
|||
key = CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.HOUR];
|
||||
} else if ( key.equals(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MINUTE]) ) {
|
||||
calendarField = Calendar.MINUTE;
|
||||
} else if ( key.equals(CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.SECOND]) ) {
|
||||
calendarField = Calendar.SECOND;
|
||||
}
|
||||
|
||||
if ( calendarField != -1 ) {
|
||||
|
@ -592,7 +596,7 @@ public class DateIntervalInfo implements Cloneable, Freezable<DateIntervalInfo>,
|
|||
* Restriction:
|
||||
* Currently, users can only set interval patterns when the following
|
||||
* calendar fields are different: ERA, YEAR, MONTH, DATE, DAY_OF_MONTH,
|
||||
* DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, and MINUTE.
|
||||
* DAY_OF_WEEK, AM_PM, HOUR, HOUR_OF_DAY, MINUTE, and SECOND.
|
||||
* Interval patterns when other calendar fields are different are
|
||||
* not supported.
|
||||
*
|
||||
|
@ -737,7 +741,7 @@ public class DateIntervalInfo implements Cloneable, Freezable<DateIntervalInfo>,
|
|||
public PatternInfo getIntervalPattern(String skeleton, int field)
|
||||
{
|
||||
if ( field > MINIMUM_SUPPORTED_CALENDAR_FIELD ) {
|
||||
throw new IllegalArgumentException("no support for field less than MINUTE");
|
||||
throw new IllegalArgumentException("no support for field less than SECOND");
|
||||
}
|
||||
Map<String, PatternInfo> patternsOfOneSkeleton = fIntervalPatterns.get(skeleton);
|
||||
if ( patternsOfOneSkeleton != null ) {
|
||||
|
|
|
@ -410,7 +410,7 @@ public class DateIntervalFormatTest extends com.ibm.icu.dev.test.TestFmwk {
|
|||
|
||||
"en", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hhmmzz", "10:10 AM PST",
|
||||
|
||||
"en", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hms", "10:10:10 AM",
|
||||
"en", "2007 01 10 10:10:10", "2007 01 10 10:10:20", "hms", "10:10:10 AM \u2013 10:10:20 AM",
|
||||
|
||||
"en", "2007 01 01 22:00:00", "2007 01 01 23:00:00", "yMMMMdHm", "January 1, 2007, 22:00 \u2013 23:00",
|
||||
|
||||
|
@ -1196,10 +1196,10 @@ public class DateIntervalFormatTest extends com.ibm.icu.dev.test.TestFmwk {
|
|||
*/
|
||||
public void TestGetIntervalPattern(){
|
||||
// Tests when "if ( field > MINIMUM_SUPPORTED_CALENDAR_FIELD )" is true
|
||||
// MINIMUM_SUPPORTED_CALENDAR_FIELD = Calendar.MINUTE;
|
||||
// MINIMUM_SUPPORTED_CALENDAR_FIELD = Calendar.SECOND;
|
||||
DateIntervalInfo dii = new DateIntervalInfo();
|
||||
try{
|
||||
dii.getIntervalPattern("", Calendar.MINUTE+1);
|
||||
dii.getIntervalPattern("", Calendar.SECOND+1);
|
||||
errln("DateIntervalInfo.getIntervalPattern(String,int) was suppose " +
|
||||
"to return an exception for the 'int field' parameter " +
|
||||
"when it exceeds MINIMUM_SUPPORTED_CALENDAR_FIELD.");
|
||||
|
@ -1221,10 +1221,10 @@ public class DateIntervalFormatTest extends com.ibm.icu.dev.test.TestFmwk {
|
|||
} catch(Exception e){}
|
||||
|
||||
// Tests when "if ( lrgDiffCalUnit > MINIMUM_SUPPORTED_CALENDAR_FIELD )" is true
|
||||
// MINIMUM_SUPPORTED_CALENDAR_FIELD = Calendar.MINUTE;
|
||||
// MINIMUM_SUPPORTED_CALENDAR_FIELD = Calendar.SECOND;
|
||||
try{
|
||||
dii = (DateIntervalInfo) dii.cloneAsThawed();
|
||||
dii.setIntervalPattern("", Calendar.MINUTE+1, "");
|
||||
dii.setIntervalPattern("", Calendar.SECOND+1, "");
|
||||
errln("DateIntervalInfo.setIntervalPattern(String,int,String) " +
|
||||
"was suppose to return an exception when the " +
|
||||
"variable 'lrgDiffCalUnit' is greater than " +
|
||||
|
@ -1528,4 +1528,189 @@ public class DateIntervalFormatTest extends com.ibm.icu.dev.test.TestFmwk {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void TestFPos_SkelWithSeconds () {
|
||||
|
||||
final long[] deltas = {
|
||||
0L, // none
|
||||
200L, // 200 millisec
|
||||
20000L, // 20 sec
|
||||
1200000L, // 20 min
|
||||
7200000L, // 2 hrs
|
||||
43200000L, // 12 hrs
|
||||
691200000L, // 8 days
|
||||
1382400000L, // 16 days,
|
||||
8640000000L, // 100 days
|
||||
};
|
||||
|
||||
class ExpectPosAndFormat {
|
||||
public int posBegin;
|
||||
public int posEnd;
|
||||
public String format;
|
||||
// Simple constructor
|
||||
public ExpectPosAndFormat(int pBegin, int pEnd, String fmt) {
|
||||
posBegin = pBegin;
|
||||
posEnd = pEnd;
|
||||
format = fmt;
|
||||
}
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_en_HHmm = {
|
||||
new ExpectPosAndFormat( 3, 5, "09:00" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00 \u2013 09:20" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00 \u2013 11:00" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00 \u2013 21:00" ),
|
||||
new ExpectPosAndFormat( 15, 17, "11/20/2014, 09:00 \u2013 11/28/2014, 09:00" ),
|
||||
new ExpectPosAndFormat( 15, 17, "11/20/2014, 09:00 \u2013 12/6/2014, 09:00" ),
|
||||
new ExpectPosAndFormat( 15, 17, "11/20/2014, 09:00 \u2013 2/28/2015, 09:00" )
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_en_HHmmss = {
|
||||
new ExpectPosAndFormat( 3, 5, "09:00:00" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00:00" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00:00 \u2013 09:00:20" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00:00 \u2013 09:20:00" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00:00 \u2013 11:00:00" ),
|
||||
new ExpectPosAndFormat( 3, 5, "09:00:00 \u2013 21:00:00" ),
|
||||
new ExpectPosAndFormat( 15, 17, "11/20/2014, 09:00:00 \u2013 11/28/2014, 09:00:00" ),
|
||||
new ExpectPosAndFormat( 15, 17, "11/20/2014, 09:00:00 \u2013 12/6/2014, 09:00:00" ),
|
||||
new ExpectPosAndFormat( 15, 17, "11/20/2014, 09:00:00 \u2013 2/28/2015, 09:00:00" )
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_en_yyMMdd = {
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14" ),
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14" ),
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14" ),
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14" ),
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14" ),
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14" ),
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14 \u2013 11/28/14" ),
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14 \u2013 12/6/14" ),
|
||||
new ExpectPosAndFormat( 0, 0, "11/20/14 \u2013 2/28/15" )
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_en_yyMMddHHmm = {
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00 \u2013 09:20" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00 \u2013 11:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00 \u2013 21:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00 \u2013 11/28/14, 09:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00 \u2013 12/06/14, 09:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00 \u2013 02/28/15, 09:00" )
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_en_yyMMddHHmmss = {
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00 \u2013 09:00:20" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00 \u2013 09:20:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00 \u2013 11:00:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00 \u2013 21:00:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00 \u2013 11/28/14, 09:00:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00 \u2013 12/06/14, 09:00:00" ),
|
||||
new ExpectPosAndFormat( 13, 15, "11/20/14, 09:00:00 \u2013 02/28/15, 09:00:00" )
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_en_yMMMdhmmssz = {
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT" ),
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT" ),
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT \u2013 9:00:20 AM GMT" ),
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT \u2013 9:20:00 AM GMT" ),
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT \u2013 11:00:00 AM GMT" ),
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT \u2013 9:00:00 PM GMT" ),
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT \u2013 Nov 28, 2014, 9:00:00 AM GMT" ),
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT \u2013 Dec 6, 2014, 9:00:00 AM GMT" ),
|
||||
new ExpectPosAndFormat( 16, 18, "Nov 20, 2014, 9:00:00 AM GMT \u2013 Feb 28, 2015, 9:00:00 AM GMT" )
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_ja_yyMMddHHmm = {
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9\u664200\u5206\uFF5E9\u664220\u5206" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9\u664200\u5206\uFF5E11\u664200\u5206" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9\u664200\u5206\uFF5E21\u664200\u5206" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00\uFF5E14/11/28 9:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00\uFF5E14/12/06 9:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00\uFF5E15/02/28 9:00" )
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_ja_yyMMddHHmmss = {
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00\uFF5E9:00:20" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00\uFF5E9:20:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00\uFF5E11:00:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00\uFF5E21:00:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00\uFF5E14/11/28 9:00:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00\uFF5E14/12/06 9:00:00" ),
|
||||
new ExpectPosAndFormat( 11, 13, "14/11/20 9:00:00\uFF5E15/02/28 9:00:00" )
|
||||
};
|
||||
|
||||
final ExpectPosAndFormat[] exp_ja_yMMMdHHmmss = {
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00" ),
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00" ),
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00\uFF5E9:00:20" ),
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00\uFF5E9:20:00" ),
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00\uFF5E11:00:00" ),
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00\uFF5E21:00:00" ),
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00\uFF5E2014\u5E7411\u670828\u65E5 9:00:00" ),
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00\uFF5E2014\u5E7412\u67086\u65E5 9:00:00" ),
|
||||
new ExpectPosAndFormat( 14, 16, "2014\u5E7411\u670820\u65E5 9:00:00\uFF5E2015\u5E742\u670828\u65E5 9:00:00" )
|
||||
};
|
||||
|
||||
class LocaleAndSkeletonItem {
|
||||
public String locale;
|
||||
public String skeleton;
|
||||
public int fieldToCheck;
|
||||
public ExpectPosAndFormat[] expected;
|
||||
// Simple constructor
|
||||
public LocaleAndSkeletonItem(String loc, String skel, int field, ExpectPosAndFormat[] exp) {
|
||||
locale = loc;
|
||||
skeleton = skel;
|
||||
fieldToCheck = field;
|
||||
expected = exp;
|
||||
}
|
||||
};
|
||||
|
||||
final LocaleAndSkeletonItem[] locSkelItems = {
|
||||
new LocaleAndSkeletonItem( "en", "HHmm", DateFormat.MINUTE_FIELD, exp_en_HHmm ),
|
||||
new LocaleAndSkeletonItem( "en", "HHmmss", DateFormat.MINUTE_FIELD, exp_en_HHmmss ),
|
||||
new LocaleAndSkeletonItem( "en", "yyMMdd", DateFormat.MINUTE_FIELD, exp_en_yyMMdd ),
|
||||
new LocaleAndSkeletonItem( "en", "yyMMddHHmm", DateFormat.MINUTE_FIELD, exp_en_yyMMddHHmm ),
|
||||
new LocaleAndSkeletonItem( "en", "yyMMddHHmmss", DateFormat.MINUTE_FIELD, exp_en_yyMMddHHmmss ),
|
||||
// skip the following until ICU4J DateIntervalFormat has support for setting time zone
|
||||
// new LocaleAndSkeletonItem( "en", "yMMMdhmmssz", DateFormat.MINUTE_FIELD, exp_en_yMMMdhmmssz ),
|
||||
new LocaleAndSkeletonItem( "ja", "yyMMddHHmm", DateFormat.MINUTE_FIELD, exp_ja_yyMMddHHmm ),
|
||||
new LocaleAndSkeletonItem( "ja", "yyMMddHHmmss", DateFormat.MINUTE_FIELD, exp_ja_yyMMddHHmmss ),
|
||||
new LocaleAndSkeletonItem( "ja", "yMMMdHHmmss", DateFormat.MINUTE_FIELD, exp_ja_yMMMdHHmmss )
|
||||
};
|
||||
|
||||
//final String zoneGMT = "GMT";
|
||||
final long startTimeGMT = 1416474000000L; // 2014 Nov 20 09:00 GMT
|
||||
|
||||
TimeZone localZone = TimeZone.getDefault();
|
||||
long startTime = startTimeGMT - localZone.getOffset(startTimeGMT);
|
||||
for (LocaleAndSkeletonItem item: locSkelItems) {
|
||||
DateIntervalFormat difmt = DateIntervalFormat.getInstance(item.skeleton, new ULocale(item.locale));
|
||||
int dIdx, dCount = deltas.length;
|
||||
for (dIdx = 0; dIdx < dCount; dIdx++) {
|
||||
DateInterval di = new DateInterval(startTime, startTime + deltas[dIdx]);
|
||||
StringBuffer actual = new StringBuffer(64);
|
||||
FieldPosition pos = new FieldPosition(item.fieldToCheck);
|
||||
String actualString = difmt.format(di, actual, pos).toString();
|
||||
ExpectPosAndFormat expectPosFmt = item.expected[dIdx];
|
||||
if (!actualString.equals(expectPosFmt.format) ||
|
||||
pos.getBeginIndex() != expectPosFmt.posBegin || pos.getEndIndex() != expectPosFmt.posEnd) {
|
||||
errln("For locale " + item.locale + ", skeleton " + item.skeleton + ", delta " + deltas[dIdx] +
|
||||
": expect " + expectPosFmt.posBegin + "-" + expectPosFmt.posEnd + " \"" + expectPosFmt.format +
|
||||
"\"; get " + pos.getBeginIndex() + "-" + pos.getEndIndex() + " \"" + actualString + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue