Search in sources :

Example 1 with PatternInfo

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;
}
Also used : HashMap(java.util.HashMap) PatternInfo(android.icu.text.DateIntervalInfo.PatternInfo)

Example 2 with PatternInfo

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;
}
Also used : Calendar(android.icu.util.Calendar) PatternInfo(android.icu.text.DateIntervalInfo.PatternInfo) FieldPosition(java.text.FieldPosition)

Example 3 with PatternInfo

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
}
Also used : PatternInfo(android.icu.text.DateIntervalInfo.PatternInfo)

Example 4 with PatternInfo

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;
}
Also used : PatternInfo(android.icu.text.DateIntervalInfo.PatternInfo)

Example 5 with PatternInfo

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 + "»");
        }
    }
}
Also used : ULocale(android.icu.util.ULocale) DateIntervalInfo(android.icu.text.DateIntervalInfo) DateFormat(android.icu.text.DateFormat) SimpleDateFormat(android.icu.text.SimpleDateFormat) DateIntervalFormat(android.icu.text.DateIntervalFormat) DateInterval(android.icu.util.DateInterval) PatternInfo(android.icu.text.DateIntervalInfo.PatternInfo) SimpleDateFormat(android.icu.text.SimpleDateFormat) Test(org.junit.Test)

Aggregations

PatternInfo (android.icu.text.DateIntervalInfo.PatternInfo)9 DateIntervalInfo (android.icu.text.DateIntervalInfo)2 ULocale (android.icu.util.ULocale)2 Test (org.junit.Test)2 DateFormat (android.icu.text.DateFormat)1 DateIntervalFormat (android.icu.text.DateIntervalFormat)1 SimpleDateFormat (android.icu.text.SimpleDateFormat)1 Calendar (android.icu.util.Calendar)1 DateInterval (android.icu.util.DateInterval)1 FieldPosition (java.text.FieldPosition)1 HashMap (java.util.HashMap)1