use of android.icu.text.DateIntervalInfo.PatternInfo in project j2objc by google.
the class DateIntervalFormat method initializeIntervalPattern.
/*
* Initialize interval patterns locale to this formatter
*
* This code is a bit complicated since
* 1. the interval patterns saved in resource bundle files are interval
* patterns based on date or time only.
* It does not have interval patterns based on both date and time.
* Interval patterns on both date and time are algorithm generated.
*
* For example, it has interval patterns on skeleton "dMy" and "hm",
* but it does not have interval patterns on skeleton "dMyhm".
*
* The rule to generate interval patterns for both date and time skeleton are
* 1) when the year, month, or day differs, concatenate the two original
* expressions with a separator between,
* For example, interval pattern from "Jan 10, 2007 10:10 am"
* to "Jan 11, 2007 10:10am" is
* "Jan 10, 2007 10:10 am - Jan 11, 2007 10:10am"
*
* 2) otherwise, present the date followed by the range expression
* for the time.
* For example, interval pattern from "Jan 10, 2007 10:10 am"
* to "Jan 10, 2007 11:10am" is
* "Jan 10, 2007 10:10 am - 11:10am"
*
* 2. even a pattern does not request a certain calendar field,
* the interval pattern needs to include such field if such fields are
* different between 2 dates.
* For example, a pattern/skeleton is "hm", but the interval pattern
* includes year, month, and date when year, month, and date differs.
*
*
* @param fullPattern formatter's full pattern
* @param locale the given locale.
* @return interval patterns' hash map
*/
private Map<String, PatternInfo> initializeIntervalPattern(String fullPattern, ULocale locale) {
DateTimePatternGenerator dtpng = DateTimePatternGenerator.getInstance(locale);
if (fSkeleton == null) {
// fSkeleton is already set by getDateIntervalInstance()
// or by getInstance(String skeleton, .... )
fSkeleton = dtpng.getSkeleton(fullPattern);
}
String skeleton = fSkeleton;
HashMap<String, PatternInfo> intervalPatterns = new HashMap<String, PatternInfo>();
/* Check whether the skeleton is a combination of date and time.
* For the complication reason 1 explained above.
*/
StringBuilder date = new StringBuilder(skeleton.length());
StringBuilder normalizedDate = new StringBuilder(skeleton.length());
StringBuilder time = new StringBuilder(skeleton.length());
StringBuilder normalizedTime = new StringBuilder(skeleton.length());
/* the difference between time skeleton and normalizedTimeSkeleton are:
* 1. (Formerly, normalized time skeleton folded 'H' to 'h'; no longer true)
* 2. 'a' is omitted in normalized time skeleton.
* 3. there is only one appearance for 'h', 'm','v', 'z' in normalized
* time skeleton
*
* The difference between date skeleton and normalizedDateSkeleton are:
* 1. both 'y' and 'd' appear only once in normalizeDateSkeleton
* 2. 'E' and 'EE' are normalized into 'EEE'
* 3. 'MM' is normalized into 'M'
*/
getDateTimeSkeleton(skeleton, date, normalizedDate, time, normalizedTime);
String dateSkeleton = date.toString();
String timeSkeleton = time.toString();
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 concatenating 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.
fDateTimeFormat = getConcatenationPattern(locale);
}
boolean found = genSeparateDateTimePtn(normalizedDateSkeleton, normalizedTimeSkeleton, intervalPatterns, dtpng);
// for skeletons with seconds, found is false and we enter this block
if (found == false) {
// StringBuffer skeleton = new StringBuffer(skeleton);
if (time.length() != 0) {
// genFallbackForNotFound(Calendar.AM_PM, skeleton);
if (date.length() == 0) {
// prefix with yMd
timeSkeleton = DateFormat.YEAR_NUM_MONTH_DAY + timeSkeleton;
String pattern = dtpng.getBestPattern(timeSkeleton);
// for fall back interval patterns,
// the first part of the pattern is empty,
// the second part of the pattern is the full-pattern
// should be used in fall-back.
PatternInfo ptn = new PatternInfo(null, pattern, fInfo.getDefaultOrder());
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE], ptn);
// share interval pattern
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MONTH], ptn);
// share interval pattern
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.YEAR], ptn);
} else {
// genFallbackForNotFound(Calendar.DATE, skeleton);
// genFallbackForNotFound(Calendar.MONTH, skeleton);
// genFallbackForNotFound(Calendar.YEAR, skeleton);
}
} else {
// genFallbackForNotFound(Calendar.DATE, skeleton);
// genFallbackForNotFound(Calendar.MONTH, skeleton);
// genFallbackForNotFound(Calendar.YEAR, skeleton);
}
return intervalPatterns;
}
// interval patterns for skeleton are found in resource
if (time.length() == 0) {
// done
} else if (date.length() == 0) {
// need to set up patterns for y/M/d differ
/* result from following looks confusing.
* for example: 10 10:10 - 11 10:10, it is not
* clear that the first 10 is the 10th day
time.insert(0, 'd');
genFallbackPattern(Calendar.DATE, time);
time.insert(0, 'M');
genFallbackPattern(Calendar.MONTH, time);
time.insert(0, 'y');
genFallbackPattern(Calendar.YEAR, time);
*/
// prefix with yMd
timeSkeleton = DateFormat.YEAR_NUM_MONTH_DAY + timeSkeleton;
String pattern = dtpng.getBestPattern(timeSkeleton);
// for fall back interval patterns,
// the first part of the pattern is empty,
// the second part of the pattern is the full-pattern
// should be used in fall-back.
PatternInfo ptn = new PatternInfo(null, pattern, fInfo.getDefaultOrder());
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE], ptn);
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MONTH], ptn);
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.YEAR], ptn);
} else {
// if field exists, use fall back
if (!fieldExistsInSkeleton(Calendar.DATE, dateSkeleton)) {
// prefix skeleton with 'd'
skeleton = DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.DATE] + skeleton;
genFallbackPattern(Calendar.DATE, skeleton, intervalPatterns, dtpng);
}
if (!fieldExistsInSkeleton(Calendar.MONTH, dateSkeleton)) {
// then prefix skeleton with 'M'
skeleton = DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.MONTH] + skeleton;
genFallbackPattern(Calendar.MONTH, skeleton, intervalPatterns, dtpng);
}
if (!fieldExistsInSkeleton(Calendar.YEAR, dateSkeleton)) {
// then prefix skeleton with 'y'
skeleton = DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[Calendar.YEAR] + skeleton;
genFallbackPattern(Calendar.YEAR, skeleton, intervalPatterns, dtpng);
}
/*
* 2) otherwise, present the date followed by the
* range expression for the time.
*/
if (fDateTimeFormat == null) {
fDateTimeFormat = "{1} {0}";
}
String datePattern = dtpng.getBestPattern(dateSkeleton);
concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.AM_PM, intervalPatterns);
concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.HOUR, intervalPatterns);
concatSingleDate2TimeInterval(fDateTimeFormat, datePattern, Calendar.MINUTE, intervalPatterns);
}
return intervalPatterns;
}
use of android.icu.text.DateIntervalInfo.PatternInfo in project j2objc by google.
the class DateIntervalFormat method format.
/**
* Format 2 Calendars to produce a string.
*
* @param fromCalendar calendar set to the from date in date interval
* to be formatted into date interval string
* @param toCalendar calendar set to the to date in date interval
* to be formatted into date interval string
* @param appendTo Output parameter to receive result.
* 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.
*/
public final synchronized StringBuffer format(Calendar fromCalendar, Calendar toCalendar, StringBuffer appendTo, FieldPosition pos) {
// not support different calendar types and time zones
if (!fromCalendar.isEquivalentTo(toCalendar)) {
throw new IllegalArgumentException("can not format on two different calendars");
}
// First, find the largest different calendar field.
// init with an invalid value.
int field = -1;
if (fromCalendar.get(Calendar.ERA) != toCalendar.get(Calendar.ERA)) {
field = Calendar.ERA;
} else if (fromCalendar.get(Calendar.YEAR) != toCalendar.get(Calendar.YEAR)) {
field = Calendar.YEAR;
} else if (fromCalendar.get(Calendar.MONTH) != toCalendar.get(Calendar.MONTH)) {
field = Calendar.MONTH;
} else if (fromCalendar.get(Calendar.DATE) != toCalendar.get(Calendar.DATE)) {
field = Calendar.DATE;
} else if (fromCalendar.get(Calendar.AM_PM) != toCalendar.get(Calendar.AM_PM)) {
field = Calendar.AM_PM;
} else if (fromCalendar.get(Calendar.HOUR) != toCalendar.get(Calendar.HOUR)) {
field = Calendar.HOUR;
} 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 {
/* 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(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field]);
if (intervalPattern == null) {
if (fDateFormat.isFieldUnitIgnored(field)) {
/* the largest different calendar field is small than
* the smallest calendar field in pattern,
* return single date format.
*/
return fDateFormat.format(fromCalendar, appendTo, pos);
}
return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos);
}
// For a 'real' interval pattern, the first part will never be empty.
if (intervalPattern.getFirstPart() == null) {
// fall back
return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos, intervalPattern.getSecondPart());
}
Calendar firstCal;
Calendar secondCal;
if (intervalPattern.firstDateInPtnIsLaterDate()) {
firstCal = toCalendar;
secondCal = fromCalendar;
} else {
firstCal = fromCalendar;
secondCal = toCalendar;
}
// break the interval pattern into 2 parts
// first part should not be empty,
String originalPattern = fDateFormat.toPattern();
fDateFormat.applyPattern(intervalPattern.getFirstPart());
fDateFormat.format(firstCal, appendTo, pos);
if (intervalPattern.getSecondPart() != null) {
fDateFormat.applyPattern(intervalPattern.getSecondPart());
FieldPosition otherPos = new FieldPosition(pos.getField());
fDateFormat.format(secondCal, appendTo, otherPos);
if (pos.getEndIndex() == 0 && otherPos.getEndIndex() > 0) {
pos.setBeginIndex(otherPos.getBeginIndex());
pos.setEndIndex(otherPos.getEndIndex());
}
}
fDateFormat.applyPattern(originalPattern);
return appendTo;
}
use of android.icu.text.DateIntervalInfo.PatternInfo in project j2objc by google.
the class DateIntervalFormat method concatSingleDate2TimeInterval.
/*
* Concat a single date pattern with a time interval pattern,
* set it into the intervalPatterns, while field is time field.
* This is used to handle time interval patterns on skeleton with
* both time and date. Present the date followed by
* the range expression for the time.
* @param dtfmt date and time format
* @param datePattern date pattern
* @param field time calendar field: AM_PM, HOUR, MINUTE
* @param intervalPatterns interval patterns
*/
private void concatSingleDate2TimeInterval(String dtfmt, String datePattern, int field, Map<String, PatternInfo> intervalPatterns) {
PatternInfo timeItvPtnInfo = intervalPatterns.get(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field]);
if (timeItvPtnInfo != null) {
String timeIntervalPattern = timeItvPtnInfo.getFirstPart() + timeItvPtnInfo.getSecondPart();
String pattern = SimpleFormatterImpl.formatRawPattern(dtfmt, 2, 2, timeIntervalPattern, datePattern);
timeItvPtnInfo = DateIntervalInfo.genPatternInfo(pattern, timeItvPtnInfo.firstDateInPtnIsLaterDate());
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field], timeItvPtnInfo);
}
// else: fall back
// it should not happen if the interval format defined is valid
}
use of android.icu.text.DateIntervalInfo.PatternInfo in project j2objc by google.
the class DateIntervalFormat method genIntervalPattern.
/*
* Generate interval pattern from existing resource
*
* It not only save the interval patterns,
* but also return the skeleton and its best match skeleton.
*
* @param field largest different calendar field
* @param skeleton skeleton
* @param bestSkeleton the best match skeleton which has interval pattern
* defined in resource
* @param differenceInfo the difference between skeleton and best skeleton
* 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
*
* @param intervalPatterns interval patterns
*
* @return an extended skeleton or extended best skeleton if applicable.
* null otherwise.
*/
private SkeletonAndItsBestMatch genIntervalPattern(int field, String skeleton, String bestSkeleton, int differenceInfo, Map<String, PatternInfo> intervalPatterns) {
SkeletonAndItsBestMatch retValue = null;
PatternInfo pattern = fInfo.getIntervalPattern(bestSkeleton, field);
if (pattern == null) {
// single date
if (SimpleDateFormat.isFieldUnitIgnored(bestSkeleton, field)) {
PatternInfo ptnInfo = new PatternInfo(fDateFormat.toPattern(), null, fInfo.getDefaultOrder());
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field], ptnInfo);
return null;
}
// add it here for simplicity
if (field == Calendar.AM_PM) {
pattern = fInfo.getIntervalPattern(bestSkeleton, Calendar.HOUR);
if (pattern != null) {
// share
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field], pattern);
}
return null;
}
// else, looking for pattern when 'y' differ for 'dMMMM' skeleton,
// first, get best match pattern "MMMd",
// since there is no pattern for 'y' differs for skeleton 'MMMd',
// need to look for it from skeleton 'yMMMd',
// if found, adjust field width in interval pattern from
// "MMM" to "MMMM".
String fieldLetter = DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field];
bestSkeleton = fieldLetter + bestSkeleton;
skeleton = fieldLetter + skeleton;
// for example, looking for patterns when 'y' differ for
// skeleton "MMMM".
pattern = fInfo.getIntervalPattern(bestSkeleton, field);
if (pattern == null && differenceInfo == 0) {
// if there is no skeleton "yMMMM" defined,
// look for the best match skeleton, for example: "yMMM"
BestMatchInfo tmpRetValue = fInfo.getBestSkeleton(skeleton);
String tmpBestSkeleton = tmpRetValue.bestMatchSkeleton;
differenceInfo = tmpRetValue.bestMatchDistanceInfo;
if (tmpBestSkeleton.length() != 0 && differenceInfo != -1) {
pattern = fInfo.getIntervalPattern(tmpBestSkeleton, field);
bestSkeleton = tmpBestSkeleton;
}
}
if (pattern != null) {
retValue = new SkeletonAndItsBestMatch(skeleton, bestSkeleton);
}
}
if (pattern != null) {
if (differenceInfo != 0) {
String part1 = adjustFieldWidth(skeleton, bestSkeleton, pattern.getFirstPart(), differenceInfo);
String part2 = adjustFieldWidth(skeleton, bestSkeleton, pattern.getSecondPart(), differenceInfo);
pattern = new PatternInfo(part1, part2, pattern.firstDateInPtnIsLaterDate());
} else {
// pattern is immutable, no need to clone;
// pattern = (PatternInfo)pattern.clone();
}
intervalPatterns.put(DateIntervalInfo.CALENDAR_FIELD_TO_PATTERN_LETTER[field], pattern);
}
return retValue;
}
use of android.icu.text.DateIntervalInfo.PatternInfo in project j2objc by google.
the class DateIntervalFormatTest method TestTicket11583.
@Test
public void TestTicket11583() {
ULocale[] locales = { ULocale.ENGLISH, SPANISH, LA_SPANISH };
String[] skeletons = { "yMMMMd", "yMMMM", "MMMM", "yMMMd", "yMMM", "MMM", "yMMd", "yMMdd", "yMM", "MM", "yMdd", "yMd", "yM", "M" };
final long startDate = 1232364615000L;
final long endDate = 1240399815000L;
// "yMMM";
String filterPattern = null;
for (ULocale locale : locales) {
for (String skeleton : skeletons) {
if (filterPattern != null && !skeleton.equals(filterPattern)) {
continue;
}
DateFormat dateFormat = DateFormat.getPatternInstance(skeleton, locale);
String dateFormatPattern = ((SimpleDateFormat) dateFormat).toPattern();
DateIntervalFormat intervalFormat = DateIntervalFormat.getInstance(skeleton, locale);
DateIntervalInfo intervalInfo = intervalFormat.getDateIntervalInfo();
if (skeleton.equals(filterPattern)) {
logln(filterPattern + " => " + intervalInfo.getRawPatterns().get(filterPattern));
}
DateInterval date_interval = new DateInterval(startDate, endDate);
String interval = intervalFormat.format(date_interval);
String formattedStart = dateFormat.format(startDate);
String formattedEnd = dateFormat.format(endDate);
PatternInfo patternInfo = intervalFormat.getRawPatterns().get("M");
String firstPart = patternInfo.getFirstPart();
String secondPart = patternInfo.getSecondPart();
if (!matches(dateFormatPattern, firstPart, secondPart)) {
if (logKnownIssue("11585", "incompatible pattern between date format and date interval format")) {
logln("For skeleton " + skeleton + "/locale " + locale + ": mismatch between date format «" + dateFormatPattern + "» and date interval format «" + firstPart + secondPart + "».");
} else {
errln("For skeleton " + skeleton + "/locale " + locale + ": mismatch between date format «" + dateFormatPattern + "» and date interval format «" + firstPart + secondPart + "».");
}
}
logln(locale + "\tskeleton: «" + skeleton + "»\tpattern: «" + dateFormatPattern + "»\tintervalPattern1: «" + firstPart + "»\tintervalPattern2: «" + secondPart + "»\tstartDate: «" + formattedStart + "»\tendDate: «" + formattedEnd + "»\tinterval: «" + interval + "»");
}
}
}
Aggregations