ICU-8464 Add Relative Date Formatting for JAVA.
X-SVN-Rev: 34663
This commit is contained in:
parent
e1a7ad244f
commit
b90cbad09c
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -260,6 +260,8 @@ icu4j/main/classes/core/.settings/edu.umd.cs.findbugs.core.prefs -text
|
||||
icu4j/main/classes/core/.settings/org.eclipse.core.resources.prefs -text
|
||||
icu4j/main/classes/core/.settings/org.eclipse.jdt.core.prefs -text
|
||||
icu4j/main/classes/core/manifest.stub -text
|
||||
icu4j/main/classes/core/src/com/ibm/icu/text/QuantityFormatter.java -text
|
||||
icu4j/main/classes/core/src/com/ibm/icu/text/RelativeDateTimeFormatter.java -text
|
||||
icu4j/main/classes/currdata/.externalToolBuilders/copy-data-currdata.launch -text
|
||||
icu4j/main/classes/currdata/.settings/org.eclipse.core.resources.prefs -text
|
||||
icu4j/main/classes/currdata/.settings/org.eclipse.jdt.core.prefs -text
|
||||
@ -320,6 +322,7 @@ icu4j/main/tests/core/manifest.stub -text
|
||||
icu4j/main/tests/core/src/com/ibm/icu/dev/data/rbbi/english.dict -text
|
||||
icu4j/main/tests/core/src/com/ibm/icu/dev/data/resources/testmessages.properties -text
|
||||
icu4j/main/tests/core/src/com/ibm/icu/dev/data/thai6.ucs -text
|
||||
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/RelativeDateTimeFormatterTest.java -text
|
||||
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.OlsonTimeZone.dat -text
|
||||
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.impl.TimeZoneAdapter.dat -text
|
||||
icu4j/main/tests/core/src/com/ibm/icu/dev/test/serializable/data/ICU_3.6/com.ibm.icu.math.BigDecimal.dat -text
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2004-2012, International Business Machines Corporation and *
|
||||
* Copyright (C) 2004-2013, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
@ -9,6 +9,7 @@ package com.ibm.icu.impl;
|
||||
import java.util.ArrayList;
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
import com.ibm.icu.text.DateFormat;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.UResourceBundle;
|
||||
import com.ibm.icu.util.UResourceBundleIterator;
|
||||
@ -159,7 +160,50 @@ public class CalendarData {
|
||||
|
||||
return list.toArray(new String[list.size()]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default date-time pattern such as <code>{1}, {0}</code>.
|
||||
* {1} is always the date and {0} is always the time.
|
||||
*/
|
||||
public String getDateTimePattern() {
|
||||
// this is a hack to get offset 8 from the dateTimePatterns array.
|
||||
return _getDateTimePattern(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date-time pattern by style where style is one of the style fields defined
|
||||
* in DateFormat. If date-time patterns by style are not available, it returns what
|
||||
* {@link #getDateTimePattern()} would return.
|
||||
* @param style the style e.g DateFormat.LONG.
|
||||
* @return the pattern, e.g {1}, {0}.
|
||||
*/
|
||||
public String getDateTimePattern(int style) {
|
||||
// mask away high order bits such as the DateFormat.RELATIVE bit.
|
||||
// We do it this way to avoid making this class depend on DateFormat. It makes this
|
||||
// code more brittle, but it is no more brittle than how we access patterns by style.
|
||||
return _getDateTimePattern(style & 7);
|
||||
}
|
||||
|
||||
private String _getDateTimePattern(int offset) {
|
||||
String[] patterns = null;
|
||||
try {
|
||||
patterns = getDateTimePatterns();
|
||||
} catch (MissingResourceException ignored) {
|
||||
// ignore. patterns remains null.
|
||||
}
|
||||
if (patterns == null || patterns.length < 9) {
|
||||
// Return hard-coded default. patterns array not available or it has too few
|
||||
// elements.
|
||||
return "{1} {0}";
|
||||
}
|
||||
if (patterns.length < 13) {
|
||||
// Offset 8 contains default pattern if we don't have per style patterns.
|
||||
return patterns[8];
|
||||
}
|
||||
// DateTimePatterns start at index 9 in the array.
|
||||
return patterns[9 + offset];
|
||||
}
|
||||
|
||||
public String[] getOverrides(){
|
||||
ICUResourceBundle bundle = get("DateTimePatterns");
|
||||
ArrayList<String> list = new ArrayList<String>();
|
||||
|
@ -0,0 +1,115 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.text;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* QuantityFormatter represents an unknown quantity of something and formats a known quantity
|
||||
* in terms of that something. For example, a QuantityFormatter that represents X apples may
|
||||
* format 1 as "1 apple" and 3 as "3 apples"
|
||||
* <p>
|
||||
* QuanitityFormatter appears here instead of in com.ibm.icu.impl because it depends on
|
||||
* PluralRules and DecimalFormat. It is package-protected as it is not meant for public use.
|
||||
* @author rocketman
|
||||
*/
|
||||
class QuantityFormatter {
|
||||
|
||||
private static final Map<String, Integer> INDEX_MAP = new HashMap<String, Integer>();
|
||||
private static final int MAX_INDEX;
|
||||
|
||||
static {
|
||||
int idx = 0;
|
||||
INDEX_MAP.put("other", idx++);
|
||||
INDEX_MAP.put("zero", idx++);
|
||||
INDEX_MAP.put("one", idx++);
|
||||
INDEX_MAP.put("two", idx++);
|
||||
INDEX_MAP.put("few", idx++);
|
||||
INDEX_MAP.put("many", idx++);
|
||||
|
||||
MAX_INDEX = idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder builds a QuantityFormatter.
|
||||
*
|
||||
* @author rocketman
|
||||
*/
|
||||
static class Builder {
|
||||
|
||||
private String[] templates;
|
||||
|
||||
/**
|
||||
* Adds a template.
|
||||
* @param variant the plural variant, e.g "zero", "one", "two", "few", "many", "other"
|
||||
* @param template the text for that plural variant with "{0}" as the quantity. For
|
||||
* example, in English, the template for the "one" variant may be "{0} apple" while the
|
||||
* template for the "other" variant may be "{0} apples"
|
||||
* @return a reference to this Builder for chaining.
|
||||
*/
|
||||
public Builder add(String variant, String template) {
|
||||
ensureCapacity();
|
||||
templates[INDEX_MAP.get(variant)] = template;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void ensureCapacity() {
|
||||
if (templates == null) {
|
||||
templates = new String[MAX_INDEX];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the new QuantityFormatter and resets this Builder to its initial state.
|
||||
* @return the new QuantityFormatter object.
|
||||
* @throws IllegalStateException if no template is specified for the "other" variant.
|
||||
* When throwing this exception, build() still resets this Builder to its initial
|
||||
* state.
|
||||
*/
|
||||
public QuantityFormatter build() {
|
||||
if (templates == null || templates[0] == null) {
|
||||
templates = null;
|
||||
throw new IllegalStateException("At least other variant must be set.");
|
||||
}
|
||||
QuantityFormatter result = new QuantityFormatter(templates);
|
||||
templates = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final String[] templates;
|
||||
|
||||
private QuantityFormatter(String[] templates) {
|
||||
this.templates = templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format formats a quantity with this object.
|
||||
* @param quantity the quantity to be formatted
|
||||
* @param numberFormat used to actually format the quantity.
|
||||
* @param pluralRules uses the quantity and the numberFormat to determine what plural
|
||||
* variant to use for fetching the formatting template.
|
||||
* @return the formatted string e.g '3 apples'
|
||||
*/
|
||||
public String format(double quantity, NumberFormat numberFormat, PluralRules pluralRules) {
|
||||
String formatStr = numberFormat.format(quantity);
|
||||
String variant;
|
||||
if (numberFormat instanceof DecimalFormat) {
|
||||
variant = pluralRules.select(((DecimalFormat) numberFormat).getFixedDecimal(quantity));
|
||||
} else {
|
||||
variant = pluralRules.select(quantity);
|
||||
}
|
||||
return getByVariant(variant).replace("{0}", formatStr);
|
||||
}
|
||||
|
||||
private String getByVariant(String variant) {
|
||||
String template = templates[INDEX_MAP.get(variant)];
|
||||
return template == null ? templates[0] : template;
|
||||
}
|
||||
}
|
@ -0,0 +1,634 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.text;
|
||||
|
||||
import java.util.EnumMap;
|
||||
|
||||
import com.ibm.icu.impl.CalendarData;
|
||||
import com.ibm.icu.impl.ICUCache;
|
||||
import com.ibm.icu.impl.ICUResourceBundle;
|
||||
import com.ibm.icu.impl.SimpleCache;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.UResourceBundle;
|
||||
|
||||
|
||||
/**
|
||||
* Formats simple relative dates. There are two types of relative dates that
|
||||
* it handles:
|
||||
* <ul>
|
||||
* <li>relative dates with a quantity e.g "in 5 days"</li>
|
||||
* <li>relative dates without a quantity e.g "next Tuesday"</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* This API is very basic and is intended to be a building block for more
|
||||
* fancy APIs. The caller tells it exactly what to display in a locale
|
||||
* independent way. While this class automatically provides the correct plural
|
||||
* forms, the grammatical form is otherwise as neutral as possible. It is the
|
||||
* caller's responsibility to handle cut-off logic such as deciding between
|
||||
* displaying "in 7 days" or "in 1 week." This API supports relative dates
|
||||
* involving one single unit. This API does not support relative dates
|
||||
* involving compound units.
|
||||
* e.g "in 5 days and 4 hours" nor does it support parsing.
|
||||
* This class is NOT thread-safe.
|
||||
* <p>
|
||||
* Here are some examples of use:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance();
|
||||
* fmt.format(1, Direction.NEXT, RelativeUnit.DAYS); // "in 1 day"
|
||||
* fmt.format(3, Direction.NEXT, RelativeUnit.DAYS); // "in 3 days"
|
||||
* fmt.format(3.2, Direction.LAST, RelativeUnit.YEARS); // "3.2 years ago"
|
||||
*
|
||||
* fmt.format(Direction.LAST, AbsoluteUnit.SUNDAY); // "last Sunday"
|
||||
* fmt.format(Direction.THIS, AbsoluteUnit.SUNDAY); // "this Sunday"
|
||||
* fmt.format(Direction.NEXT, AbsoluteUnit.SUNDAY); // "next Sunday"
|
||||
* fmt.format(Direction.PLAIN, AbsoluteUnit.SUNDAY); // "Sunday"
|
||||
*
|
||||
* fmt.format(Direction.LAST, AbsoluteUnit.DAY); // "yesterday"
|
||||
* fmt.format(Direction.THIS, AbsoluteUnit.DAY); // "today"
|
||||
* fmt.format(Direction.NEXT, AbsoluteUnit.DAY); // "tomorrow"
|
||||
*
|
||||
* fmt.format(Direction.PLAIN, AbsoluteUnit.NOW); // "now"
|
||||
* </pre>
|
||||
* </blockquote>
|
||||
* <p>
|
||||
* In the future, we may add more forms, such as abbreviated/short forms
|
||||
* (3 secs ago), and relative day periods ("yesterday afternoon"), etc.
|
||||
*
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public final class RelativeDateTimeFormatter {
|
||||
|
||||
/**
|
||||
* Represents the unit for formatting a relative date. e.g "in 5 days"
|
||||
* or "in 3 months"
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public static enum RelativeUnit {
|
||||
|
||||
/**
|
||||
* Seconds
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
SECONDS,
|
||||
|
||||
/**
|
||||
* Minutes
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
MINUTES,
|
||||
|
||||
/**
|
||||
* Hours
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
HOURS,
|
||||
|
||||
/**
|
||||
* Days
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
DAYS,
|
||||
|
||||
/**
|
||||
* Weeks
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
WEEKS,
|
||||
|
||||
/**
|
||||
* Months
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
MONTHS,
|
||||
|
||||
/**
|
||||
* Years
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
YEARS,
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an absolute unit.
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public static enum AbsoluteUnit {
|
||||
|
||||
/**
|
||||
* Sunday
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
SUNDAY,
|
||||
|
||||
/**
|
||||
* Monday
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
MONDAY,
|
||||
|
||||
/**
|
||||
* Tuesday
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
TUESDAY,
|
||||
|
||||
/**
|
||||
* Wednesday
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
WEDNESDAY,
|
||||
|
||||
/**
|
||||
* Thursday
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
THURSDAY,
|
||||
|
||||
/**
|
||||
* Friday
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
FRIDAY,
|
||||
|
||||
/**
|
||||
* Saturday
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
SATURDAY,
|
||||
|
||||
/**
|
||||
* Day
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
DAY,
|
||||
|
||||
/**
|
||||
* Week
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
WEEK,
|
||||
|
||||
/**
|
||||
* Month
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
MONTH,
|
||||
|
||||
/**
|
||||
* Year
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
YEAR,
|
||||
|
||||
/**
|
||||
* Now
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
NOW,
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a direction for an absolute unit e.g "Next Tuesday"
|
||||
* or "Last Tuesday"
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public static enum Direction {
|
||||
|
||||
/**
|
||||
* Two before. Not fully supported in every locale
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
LAST_2,
|
||||
|
||||
|
||||
/**
|
||||
* Last
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
LAST,
|
||||
|
||||
/**
|
||||
* This
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
THIS,
|
||||
|
||||
/**
|
||||
* Next
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
NEXT,
|
||||
|
||||
/**
|
||||
* Two after. Not fully supported in every locale
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
NEXT_2,
|
||||
|
||||
/**
|
||||
* Plain, which means the absence of a qualifier
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
PLAIN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a RelativeDateTimeFormatter for the default locale.
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public static RelativeDateTimeFormatter getInstance() {
|
||||
return getInstance(ULocale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a RelativeDateTimeFormatter for a particular locale.
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public static RelativeDateTimeFormatter getInstance(ULocale locale) {
|
||||
CalendarData calData = new CalendarData(locale, null);
|
||||
RelativeDateTimeFormatterData data = cache.get(locale);
|
||||
return new RelativeDateTimeFormatter(
|
||||
data.qualitativeUnitMap,
|
||||
data.quantitativeUnitMap,
|
||||
new MessageFormat(calData.getDateTimePattern()),
|
||||
PluralRules.forLocale(locale),
|
||||
NumberFormat.getInstance(locale));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats a relative date with a quantity such as "in 5 days" or
|
||||
* "3 months ago"
|
||||
* @param quantity The numerical amount e.g 5. This value is formatted
|
||||
* according to this object's {@link NumberFormat} object.
|
||||
* @param direction NEXT means a future relative date; LAST means a past
|
||||
* relative date.
|
||||
* @param unit the unit e.g day? month? year?
|
||||
* @return the formatted string
|
||||
* @throws IllegalArgumentException if direction is something other than
|
||||
* NEXT or LAST.
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public String format(double quantity, Direction direction, RelativeUnit unit) {
|
||||
if (direction != Direction.LAST && direction != Direction.NEXT) {
|
||||
throw new IllegalArgumentException("direction must be NEXT or LAST");
|
||||
}
|
||||
return getQuantity(unit, direction == Direction.NEXT).format(quantity, numberFormat, pluralRules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a relative date without a quantity.
|
||||
* @param direction NEXT, LAST, THIS, etc.
|
||||
* @param unit e.g SATURDAY, DAY, MONTH
|
||||
* @return the formatted string. If direction has a value that is documented as not being
|
||||
* fully supported in every locale (for example NEXT_2 or LAST_2) then this function may
|
||||
* return null to signal that no formatted string is available.
|
||||
* @throws IllegalArgumentException if the direction is incompatible with
|
||||
* unit this can occur with NOW which can only take PLAIN.
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public String format(Direction direction, AbsoluteUnit unit) {
|
||||
if (unit == AbsoluteUnit.NOW && direction != Direction.PLAIN) {
|
||||
throw new IllegalArgumentException("NOW can only accept direction PLAIN.");
|
||||
}
|
||||
return this.qualitativeUnitMap.get(unit).get(direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify which NumberFormat object this object should use for
|
||||
* formatting numbers. By default this object uses the default
|
||||
* NumberFormat object for this object's locale.
|
||||
* @param nf the NumberFormat object to use. This method makes
|
||||
* its own defensive copy of nf so that subsequent
|
||||
* changes to nf will not affect the operation of this object.
|
||||
* @see #format(double, Direction, RelativeUnit)
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public void setNumberFormat(NumberFormat nf) {
|
||||
this.numberFormat = (NumberFormat) nf.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines a relative date string and a time string in this object's
|
||||
* locale. This is done with the same date-time separator used for the
|
||||
* default calendar in this locale.
|
||||
* @param relativeDateString the relative date e.g 'yesterday'
|
||||
* @param timeString the time e.g '3:45'
|
||||
* @return the date and time concatenated according to the default
|
||||
* calendar in this locale e.g 'yesterday, 3:45'
|
||||
* @draft ICU 53
|
||||
* @provisional
|
||||
*/
|
||||
public String combineDateAndTime(String relativeDateString, String timeString) {
|
||||
return this.combinedDateAndTime.format(
|
||||
new Object[]{timeString, relativeDateString}, new StringBuffer(), null).toString();
|
||||
}
|
||||
|
||||
private static void addQualitativeUnit(
|
||||
EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnits,
|
||||
AbsoluteUnit unit,
|
||||
String current) {
|
||||
EnumMap<Direction, String> unitStrings =
|
||||
new EnumMap<Direction, String>(Direction.class);
|
||||
unitStrings.put(Direction.LAST, current);
|
||||
unitStrings.put(Direction.THIS, current);
|
||||
unitStrings.put(Direction.NEXT, current);
|
||||
unitStrings.put(Direction.PLAIN, current);
|
||||
qualitativeUnits.put(unit, unitStrings);
|
||||
}
|
||||
|
||||
private static void addQualitativeUnit(
|
||||
EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnits,
|
||||
AbsoluteUnit unit, ICUResourceBundle bundle, String plain) {
|
||||
EnumMap<Direction, String> unitStrings =
|
||||
new EnumMap<Direction, String>(Direction.class);
|
||||
unitStrings.put(Direction.LAST, bundle.getStringWithFallback("-1"));
|
||||
unitStrings.put(Direction.THIS, bundle.getStringWithFallback("0"));
|
||||
unitStrings.put(Direction.NEXT, bundle.getStringWithFallback("1"));
|
||||
addOptionalDirection(unitStrings, Direction.LAST_2, bundle, "-2");
|
||||
addOptionalDirection(unitStrings, Direction.NEXT_2, bundle, "2");
|
||||
unitStrings.put(Direction.PLAIN, plain);
|
||||
qualitativeUnits.put(unit, unitStrings);
|
||||
}
|
||||
|
||||
private static void addOptionalDirection(
|
||||
EnumMap<Direction, String> unitStrings,
|
||||
Direction direction,
|
||||
ICUResourceBundle bundle,
|
||||
String key) {
|
||||
bundle = bundle.findWithFallback(key);
|
||||
if (bundle != null) {
|
||||
unitStrings.put(direction, bundle.getString());
|
||||
}
|
||||
}
|
||||
|
||||
private RelativeDateTimeFormatter(
|
||||
EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnitMap,
|
||||
EnumMap<RelativeUnit, QuantityFormatter[]> quantitativeUnitMap,
|
||||
MessageFormat combinedDateAndTime,
|
||||
PluralRules pluralRules,
|
||||
NumberFormat numberFormat) {
|
||||
this.qualitativeUnitMap = qualitativeUnitMap;
|
||||
this.quantitativeUnitMap = quantitativeUnitMap;
|
||||
this.combinedDateAndTime = combinedDateAndTime;
|
||||
this.pluralRules = pluralRules;
|
||||
this.numberFormat = numberFormat;
|
||||
}
|
||||
|
||||
private QuantityFormatter getQuantity(RelativeUnit unit, boolean isFuture) {
|
||||
QuantityFormatter[] quantities = quantitativeUnitMap.get(unit);
|
||||
return isFuture ? quantities[1] : quantities[0];
|
||||
}
|
||||
|
||||
private final EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnitMap;
|
||||
private final EnumMap<RelativeUnit, QuantityFormatter[]> quantitativeUnitMap;
|
||||
private final MessageFormat combinedDateAndTime;
|
||||
private final PluralRules pluralRules;
|
||||
private NumberFormat numberFormat;
|
||||
|
||||
private static class RelativeDateTimeFormatterData {
|
||||
public RelativeDateTimeFormatterData(
|
||||
EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnitMap,
|
||||
EnumMap<RelativeUnit, QuantityFormatter[]> quantitativeUnitMap) {
|
||||
this.qualitativeUnitMap = qualitativeUnitMap;
|
||||
this.quantitativeUnitMap = quantitativeUnitMap;
|
||||
}
|
||||
|
||||
public final EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnitMap;
|
||||
public final EnumMap<RelativeUnit, QuantityFormatter[]> quantitativeUnitMap;
|
||||
}
|
||||
|
||||
private static class Cache {
|
||||
private final ICUCache<String, RelativeDateTimeFormatterData> cache =
|
||||
new SimpleCache<String, RelativeDateTimeFormatterData>();
|
||||
|
||||
public RelativeDateTimeFormatterData get(ULocale locale) {
|
||||
String key = locale.toString();
|
||||
RelativeDateTimeFormatterData result = cache.get(key);
|
||||
if (result == null) {
|
||||
result = new Loader(locale).load();
|
||||
cache.put(key, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Loader {
|
||||
private final ULocale ulocale;
|
||||
|
||||
public Loader(ULocale ulocale) {
|
||||
this.ulocale = ulocale;
|
||||
}
|
||||
|
||||
public RelativeDateTimeFormatterData load() {
|
||||
EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnitMap =
|
||||
new EnumMap<AbsoluteUnit, EnumMap<Direction, String>>(AbsoluteUnit.class);
|
||||
|
||||
EnumMap<RelativeUnit, QuantityFormatter[]> quantitativeUnitMap =
|
||||
new EnumMap<RelativeUnit, QuantityFormatter[]>(RelativeUnit.class);
|
||||
|
||||
ICUResourceBundle r = (ICUResourceBundle)UResourceBundle.
|
||||
getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, ulocale);
|
||||
addTimeUnit(
|
||||
r.getWithFallback("fields/day"),
|
||||
RelativeUnit.DAYS,
|
||||
AbsoluteUnit.DAY,
|
||||
quantitativeUnitMap,
|
||||
qualitativeUnitMap);
|
||||
addTimeUnit(
|
||||
r.getWithFallback("fields/week"),
|
||||
RelativeUnit.WEEKS,
|
||||
AbsoluteUnit.WEEK,
|
||||
quantitativeUnitMap,
|
||||
qualitativeUnitMap);
|
||||
addTimeUnit(
|
||||
r.getWithFallback("fields/month"),
|
||||
RelativeUnit.MONTHS,
|
||||
AbsoluteUnit.MONTH,
|
||||
quantitativeUnitMap,
|
||||
qualitativeUnitMap);
|
||||
addTimeUnit(
|
||||
r.getWithFallback("fields/year"),
|
||||
RelativeUnit.YEARS,
|
||||
AbsoluteUnit.YEAR,
|
||||
quantitativeUnitMap,
|
||||
qualitativeUnitMap);
|
||||
addTimeUnit(
|
||||
r.getWithFallback("fields/second"),
|
||||
RelativeUnit.SECONDS,
|
||||
quantitativeUnitMap);
|
||||
addTimeUnit(
|
||||
r.getWithFallback("fields/minute"),
|
||||
RelativeUnit.MINUTES,
|
||||
quantitativeUnitMap);
|
||||
addTimeUnit(
|
||||
r.getWithFallback("fields/hour"),
|
||||
RelativeUnit.HOURS,
|
||||
quantitativeUnitMap);
|
||||
addQualitativeUnit(
|
||||
qualitativeUnitMap,
|
||||
AbsoluteUnit.NOW,
|
||||
r.getStringWithFallback("fields/second/relative/0"));
|
||||
|
||||
EnumMap<AbsoluteUnit, String> dayOfWeekMap = readDaysOfWeek(
|
||||
r.getWithFallback("calendar/gregorian/dayNames/stand-alone/wide")
|
||||
);
|
||||
|
||||
addWeekDay(
|
||||
r.getWithFallback("fields/mon"),
|
||||
dayOfWeekMap,
|
||||
AbsoluteUnit.MONDAY,
|
||||
qualitativeUnitMap);
|
||||
addWeekDay(
|
||||
r.getWithFallback("fields/tue"),
|
||||
dayOfWeekMap,
|
||||
AbsoluteUnit.TUESDAY,
|
||||
qualitativeUnitMap);
|
||||
addWeekDay(
|
||||
r.getWithFallback("fields/wed"),
|
||||
dayOfWeekMap,
|
||||
AbsoluteUnit.WEDNESDAY,
|
||||
qualitativeUnitMap);
|
||||
addWeekDay(
|
||||
r.getWithFallback("fields/thu"),
|
||||
dayOfWeekMap,
|
||||
AbsoluteUnit.THURSDAY,
|
||||
qualitativeUnitMap);
|
||||
addWeekDay(
|
||||
r.getWithFallback("fields/fri"),
|
||||
dayOfWeekMap,
|
||||
AbsoluteUnit.FRIDAY,
|
||||
qualitativeUnitMap);
|
||||
addWeekDay(
|
||||
r.getWithFallback("fields/sat"),
|
||||
dayOfWeekMap,
|
||||
AbsoluteUnit.SATURDAY,
|
||||
qualitativeUnitMap);
|
||||
addWeekDay(
|
||||
r.getWithFallback("fields/sun"),
|
||||
dayOfWeekMap,
|
||||
AbsoluteUnit.SUNDAY,
|
||||
qualitativeUnitMap);
|
||||
return new RelativeDateTimeFormatterData(qualitativeUnitMap, quantitativeUnitMap);
|
||||
}
|
||||
|
||||
private void addTimeUnit(
|
||||
ICUResourceBundle timeUnitBundle,
|
||||
RelativeUnit relativeUnit,
|
||||
AbsoluteUnit absoluteUnit,
|
||||
EnumMap<RelativeUnit, QuantityFormatter[]> quantitativeUnitMap,
|
||||
EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnitMap) {
|
||||
addTimeUnit(timeUnitBundle, relativeUnit, quantitativeUnitMap);
|
||||
String unitName = timeUnitBundle.getStringWithFallback("dn");
|
||||
// TODO(Travis Keep): This is a hack to get around CLDR bug 6818.
|
||||
if (ulocale.getLanguage().equals("en")) {
|
||||
unitName = unitName.toLowerCase();
|
||||
}
|
||||
timeUnitBundle = timeUnitBundle.getWithFallback("relative");
|
||||
addQualitativeUnit(
|
||||
qualitativeUnitMap,
|
||||
absoluteUnit,
|
||||
timeUnitBundle,
|
||||
unitName);
|
||||
}
|
||||
|
||||
private static void addTimeUnit(
|
||||
ICUResourceBundle timeUnitBundle,
|
||||
RelativeUnit relativeUnit,
|
||||
EnumMap<RelativeUnit, QuantityFormatter[]> quantitativeUnitMap) {
|
||||
QuantityFormatter.Builder future = new QuantityFormatter.Builder();
|
||||
QuantityFormatter.Builder past = new QuantityFormatter.Builder();
|
||||
timeUnitBundle = timeUnitBundle.getWithFallback("relativeTime");
|
||||
addTimeUnit(
|
||||
timeUnitBundle.getWithFallback("future"),
|
||||
future);
|
||||
addTimeUnit(
|
||||
timeUnitBundle.getWithFallback("past"),
|
||||
past);
|
||||
quantitativeUnitMap.put(
|
||||
relativeUnit, new QuantityFormatter[] { past.build(), future.build() });
|
||||
}
|
||||
|
||||
private static void addTimeUnit(
|
||||
ICUResourceBundle pastOrFuture, QuantityFormatter.Builder builder) {
|
||||
int size = pastOrFuture.getSize();
|
||||
for (int i = 0; i < size; i++) {
|
||||
UResourceBundle r = pastOrFuture.get(i);
|
||||
builder.add(r.getKey(), r.getString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void addWeekDay(
|
||||
ICUResourceBundle weekdayBundle,
|
||||
EnumMap<AbsoluteUnit, String> dayOfWeekMap,
|
||||
AbsoluteUnit weekDay,
|
||||
EnumMap<AbsoluteUnit, EnumMap<Direction, String>> qualitativeUnitMap) {
|
||||
weekdayBundle = weekdayBundle.findWithFallback("relative");
|
||||
addQualitativeUnit(
|
||||
qualitativeUnitMap,
|
||||
weekDay,
|
||||
weekdayBundle,
|
||||
dayOfWeekMap.get(weekDay));
|
||||
}
|
||||
|
||||
private static EnumMap<AbsoluteUnit, String> readDaysOfWeek(ICUResourceBundle daysOfWeekBundle) {
|
||||
EnumMap<AbsoluteUnit, String> dayOfWeekMap = new EnumMap<AbsoluteUnit, String>(AbsoluteUnit.class);
|
||||
if (daysOfWeekBundle.getSize() != 7) {
|
||||
throw new IllegalStateException(String.format("Expect 7 days in a week, got %d", daysOfWeekBundle.getSize()));
|
||||
}
|
||||
// Assuming that days of week are always listed from Sunday.
|
||||
// TODO(tkeep): Is this always true?
|
||||
int idx = 0;
|
||||
dayOfWeekMap.put(AbsoluteUnit.SUNDAY, daysOfWeekBundle.getString(idx++));
|
||||
dayOfWeekMap.put(AbsoluteUnit.MONDAY, daysOfWeekBundle.getString(idx++));
|
||||
dayOfWeekMap.put(AbsoluteUnit.TUESDAY, daysOfWeekBundle.getString(idx++));
|
||||
dayOfWeekMap.put(AbsoluteUnit.WEDNESDAY, daysOfWeekBundle.getString(idx++));
|
||||
dayOfWeekMap.put(AbsoluteUnit.THURSDAY, daysOfWeekBundle.getString(idx++));
|
||||
dayOfWeekMap.put(AbsoluteUnit.FRIDAY, daysOfWeekBundle.getString(idx++));
|
||||
dayOfWeekMap.put(AbsoluteUnit.SATURDAY, daysOfWeekBundle.getString(idx++));
|
||||
return dayOfWeekMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final Cache cache = new Cache();
|
||||
}
|
@ -0,0 +1,254 @@
|
||||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2013, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.dev.test.format;
|
||||
|
||||
|
||||
|
||||
import com.ibm.icu.dev.test.TestFmwk;
|
||||
import com.ibm.icu.text.NumberFormat;
|
||||
import com.ibm.icu.text.RelativeDateTimeFormatter;
|
||||
import com.ibm.icu.text.RelativeDateTimeFormatter.AbsoluteUnit;
|
||||
import com.ibm.icu.text.RelativeDateTimeFormatter.Direction;
|
||||
import com.ibm.icu.text.RelativeDateTimeFormatter.RelativeUnit;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
/**
|
||||
* @author rocketman
|
||||
*
|
||||
*/
|
||||
public class RelativeDateTimeFormatterTest extends TestFmwk {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
new RelativeDateTimeFormatterTest().run(args);
|
||||
}
|
||||
|
||||
public void TestRelativeDateWithQuantity() {
|
||||
Object[][] data = {
|
||||
{0.0, Direction.NEXT, RelativeUnit.SECONDS, "in 0 seconds"},
|
||||
{0.5, Direction.NEXT, RelativeUnit.SECONDS, "in 0.5 seconds"},
|
||||
{1.0, Direction.NEXT, RelativeUnit.SECONDS, "in 1 second"},
|
||||
{2.0, Direction.NEXT, RelativeUnit.SECONDS, "in 2 seconds"},
|
||||
{0.0, Direction.NEXT, RelativeUnit.MINUTES, "in 0 minutes"},
|
||||
{0.5, Direction.NEXT, RelativeUnit.MINUTES, "in 0.5 minutes"},
|
||||
{1.0, Direction.NEXT, RelativeUnit.MINUTES, "in 1 minute"},
|
||||
{2.0, Direction.NEXT, RelativeUnit.MINUTES, "in 2 minutes"},
|
||||
{0.0, Direction.NEXT, RelativeUnit.HOURS, "in 0 hours"},
|
||||
{0.5, Direction.NEXT, RelativeUnit.HOURS, "in 0.5 hours"},
|
||||
{1.0, Direction.NEXT, RelativeUnit.HOURS, "in 1 hour"},
|
||||
{2.0, Direction.NEXT, RelativeUnit.HOURS, "in 2 hours"},
|
||||
{0.0, Direction.NEXT, RelativeUnit.DAYS, "in 0 days"},
|
||||
{0.5, Direction.NEXT, RelativeUnit.DAYS, "in 0.5 days"},
|
||||
{1.0, Direction.NEXT, RelativeUnit.DAYS, "in 1 day"},
|
||||
{2.0, Direction.NEXT, RelativeUnit.DAYS, "in 2 days"},
|
||||
{0.0, Direction.NEXT, RelativeUnit.WEEKS, "in 0 weeks"},
|
||||
{0.5, Direction.NEXT, RelativeUnit.WEEKS, "in 0.5 weeks"},
|
||||
{1.0, Direction.NEXT, RelativeUnit.WEEKS, "in 1 week"},
|
||||
{2.0, Direction.NEXT, RelativeUnit.WEEKS, "in 2 weeks"},
|
||||
{0.0, Direction.NEXT, RelativeUnit.MONTHS, "in 0 months"},
|
||||
{0.5, Direction.NEXT, RelativeUnit.MONTHS, "in 0.5 months"},
|
||||
{1.0, Direction.NEXT, RelativeUnit.MONTHS, "in 1 month"},
|
||||
{2.0, Direction.NEXT, RelativeUnit.MONTHS, "in 2 months"},
|
||||
{0.0, Direction.NEXT, RelativeUnit.YEARS, "in 0 years"},
|
||||
{0.5, Direction.NEXT, RelativeUnit.YEARS, "in 0.5 years"},
|
||||
{1.0, Direction.NEXT, RelativeUnit.YEARS, "in 1 year"},
|
||||
{2.0, Direction.NEXT, RelativeUnit.YEARS, "in 2 years"},
|
||||
|
||||
{0.0, Direction.LAST, RelativeUnit.SECONDS, "0 seconds ago"},
|
||||
{0.5, Direction.LAST, RelativeUnit.SECONDS, "0.5 seconds ago"},
|
||||
{1.0, Direction.LAST, RelativeUnit.SECONDS, "1 second ago"},
|
||||
{2.0, Direction.LAST, RelativeUnit.SECONDS, "2 seconds ago"},
|
||||
{0.0, Direction.LAST, RelativeUnit.MINUTES, "0 minutes ago"},
|
||||
{0.5, Direction.LAST, RelativeUnit.MINUTES, "0.5 minutes ago"},
|
||||
{1.0, Direction.LAST, RelativeUnit.MINUTES, "1 minute ago"},
|
||||
{2.0, Direction.LAST, RelativeUnit.MINUTES, "2 minutes ago"},
|
||||
{0.0, Direction.LAST, RelativeUnit.HOURS, "0 hours ago"},
|
||||
{0.5, Direction.LAST, RelativeUnit.HOURS, "0.5 hours ago"},
|
||||
{1.0, Direction.LAST, RelativeUnit.HOURS, "1 hour ago"},
|
||||
{2.0, Direction.LAST, RelativeUnit.HOURS, "2 hours ago"},
|
||||
{0.0, Direction.LAST, RelativeUnit.DAYS, "0 days ago"},
|
||||
{0.5, Direction.LAST, RelativeUnit.DAYS, "0.5 days ago"},
|
||||
{1.0, Direction.LAST, RelativeUnit.DAYS, "1 day ago"},
|
||||
{2.0, Direction.LAST, RelativeUnit.DAYS, "2 days ago"},
|
||||
{0.0, Direction.LAST, RelativeUnit.WEEKS, "0 weeks ago"},
|
||||
{0.5, Direction.LAST, RelativeUnit.WEEKS, "0.5 weeks ago"},
|
||||
{1.0, Direction.LAST, RelativeUnit.WEEKS, "1 week ago"},
|
||||
{2.0, Direction.LAST, RelativeUnit.WEEKS, "2 weeks ago"},
|
||||
{0.0, Direction.LAST, RelativeUnit.MONTHS, "0 months ago"},
|
||||
{0.5, Direction.LAST, RelativeUnit.MONTHS, "0.5 months ago"},
|
||||
{1.0, Direction.LAST, RelativeUnit.MONTHS, "1 month ago"},
|
||||
{2.0, Direction.LAST, RelativeUnit.MONTHS, "2 months ago"},
|
||||
{0.0, Direction.LAST, RelativeUnit.YEARS, "0 years ago"},
|
||||
{0.5, Direction.LAST, RelativeUnit.YEARS, "0.5 years ago"},
|
||||
{1.0, Direction.LAST, RelativeUnit.YEARS, "1 year ago"},
|
||||
{2.0, Direction.LAST, RelativeUnit.YEARS, "2 years ago"},
|
||||
};
|
||||
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(new ULocale("en_US"));
|
||||
for (Object[] row : data) {
|
||||
String actual = fmt.format(
|
||||
((Double) row[0]).doubleValue(), (Direction) row[1], (RelativeUnit) row[2]);
|
||||
assertEquals("Relative date with quantity", row[3], actual);
|
||||
}
|
||||
}
|
||||
|
||||
public void TestRelativeDateWithQuantitySr() {
|
||||
Object[][] data = {
|
||||
{0.0, Direction.NEXT, RelativeUnit.MONTHS, "за 0 месеци"},
|
||||
{1.2, Direction.NEXT, RelativeUnit.MONTHS, "за 1,2 месеца"},
|
||||
{21.0, Direction.NEXT, RelativeUnit.MONTHS, "за 21 месец"},
|
||||
};
|
||||
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(new ULocale("sr"));
|
||||
for (Object[] row : data) {
|
||||
String actual = fmt.format(
|
||||
((Double) row[0]).doubleValue(), (Direction) row[1], (RelativeUnit) row[2]);
|
||||
assertEquals("Relative date with quantity", row[3], actual);
|
||||
}
|
||||
}
|
||||
|
||||
public void TestRelativeDateWithoutQuantity() {
|
||||
Object[][] data = {
|
||||
{Direction.NEXT_2, AbsoluteUnit.DAY, null},
|
||||
|
||||
{Direction.NEXT, AbsoluteUnit.DAY, "tomorrow"},
|
||||
{Direction.NEXT, AbsoluteUnit.WEEK, "next week"},
|
||||
{Direction.NEXT, AbsoluteUnit.MONTH, "next month"},
|
||||
{Direction.NEXT, AbsoluteUnit.YEAR, "next year"},
|
||||
{Direction.NEXT, AbsoluteUnit.MONDAY, "next Monday"},
|
||||
{Direction.NEXT, AbsoluteUnit.TUESDAY, "next Tuesday"},
|
||||
{Direction.NEXT, AbsoluteUnit.WEDNESDAY, "next Wednesday"},
|
||||
{Direction.NEXT, AbsoluteUnit.THURSDAY, "next Thursday"},
|
||||
{Direction.NEXT, AbsoluteUnit.FRIDAY, "next Friday"},
|
||||
{Direction.NEXT, AbsoluteUnit.SATURDAY, "next Saturday"},
|
||||
{Direction.NEXT, AbsoluteUnit.SUNDAY, "next Sunday"},
|
||||
|
||||
{Direction.LAST_2, AbsoluteUnit.DAY, null},
|
||||
|
||||
{Direction.LAST, AbsoluteUnit.DAY, "yesterday"},
|
||||
{Direction.LAST, AbsoluteUnit.WEEK, "last week"},
|
||||
{Direction.LAST, AbsoluteUnit.MONTH, "last month"},
|
||||
{Direction.LAST, AbsoluteUnit.YEAR, "last year"},
|
||||
{Direction.LAST, AbsoluteUnit.MONDAY, "last Monday"},
|
||||
{Direction.LAST, AbsoluteUnit.TUESDAY, "last Tuesday"},
|
||||
{Direction.LAST, AbsoluteUnit.WEDNESDAY, "last Wednesday"},
|
||||
{Direction.LAST, AbsoluteUnit.THURSDAY, "last Thursday"},
|
||||
{Direction.LAST, AbsoluteUnit.FRIDAY, "last Friday"},
|
||||
{Direction.LAST, AbsoluteUnit.SATURDAY, "last Saturday"},
|
||||
{Direction.LAST, AbsoluteUnit.SUNDAY, "last Sunday"},
|
||||
|
||||
{Direction.THIS, AbsoluteUnit.DAY, "today"},
|
||||
{Direction.THIS, AbsoluteUnit.WEEK, "this week"},
|
||||
{Direction.THIS, AbsoluteUnit.MONTH, "this month"},
|
||||
{Direction.THIS, AbsoluteUnit.YEAR, "this year"},
|
||||
{Direction.THIS, AbsoluteUnit.MONDAY, "this Monday"},
|
||||
{Direction.THIS, AbsoluteUnit.TUESDAY, "this Tuesday"},
|
||||
{Direction.THIS, AbsoluteUnit.WEDNESDAY, "this Wednesday"},
|
||||
{Direction.THIS, AbsoluteUnit.THURSDAY, "this Thursday"},
|
||||
{Direction.THIS, AbsoluteUnit.FRIDAY, "this Friday"},
|
||||
{Direction.THIS, AbsoluteUnit.SATURDAY, "this Saturday"},
|
||||
{Direction.THIS, AbsoluteUnit.SUNDAY, "this Sunday"},
|
||||
|
||||
{Direction.PLAIN, AbsoluteUnit.DAY, "day"},
|
||||
{Direction.PLAIN, AbsoluteUnit.WEEK, "week"},
|
||||
{Direction.PLAIN, AbsoluteUnit.MONTH, "month"},
|
||||
{Direction.PLAIN, AbsoluteUnit.YEAR, "year"},
|
||||
{Direction.PLAIN, AbsoluteUnit.MONDAY, "Monday"},
|
||||
{Direction.PLAIN, AbsoluteUnit.TUESDAY, "Tuesday"},
|
||||
{Direction.PLAIN, AbsoluteUnit.WEDNESDAY, "Wednesday"},
|
||||
{Direction.PLAIN, AbsoluteUnit.THURSDAY, "Thursday"},
|
||||
{Direction.PLAIN, AbsoluteUnit.FRIDAY, "Friday"},
|
||||
{Direction.PLAIN, AbsoluteUnit.SATURDAY, "Saturday"},
|
||||
{Direction.PLAIN, AbsoluteUnit.SUNDAY, "Sunday"},
|
||||
|
||||
{Direction.PLAIN, AbsoluteUnit.NOW, "now"},
|
||||
};
|
||||
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(new ULocale("en_US"));
|
||||
for (Object[] row : data) {
|
||||
String actual = fmt.format((Direction) row[0], (AbsoluteUnit) row[1]);
|
||||
assertEquals("Relative date without quantity", row[2], actual);
|
||||
}
|
||||
}
|
||||
|
||||
public void TestTwoBeforeTwoAfter() {
|
||||
Object[][] data = {
|
||||
{Direction.NEXT_2, AbsoluteUnit.DAY, "pasado ma\u00F1ana"},
|
||||
{Direction.LAST_2, AbsoluteUnit.DAY, "antes de ayer"},
|
||||
};
|
||||
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(new ULocale("es"));
|
||||
for (Object[] row : data) {
|
||||
String actual = fmt.format((Direction) row[0], (AbsoluteUnit) row[1]);
|
||||
assertEquals("Two before two after", row[2], actual);
|
||||
}
|
||||
}
|
||||
|
||||
public void TestFormatWithQuantityIllegalArgument() {
|
||||
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(new ULocale("en_US"));
|
||||
try {
|
||||
fmt.format(1.0, Direction.PLAIN, RelativeUnit.DAYS);
|
||||
fail("Expected IllegalArgumentException.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
fmt.format(1.0, Direction.THIS, RelativeUnit.DAYS);
|
||||
fail("Expected IllegalArgumentException.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
public void TestFormatWithoutQuantityIllegalArgument() {
|
||||
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(new ULocale("en_US"));
|
||||
try {
|
||||
fmt.format(Direction.LAST, AbsoluteUnit.NOW);
|
||||
fail("Expected IllegalArgumentException.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
fmt.format(Direction.NEXT, AbsoluteUnit.NOW);
|
||||
fail("Expected IllegalArgumentException.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected
|
||||
}
|
||||
try {
|
||||
fmt.format(Direction.THIS, AbsoluteUnit.NOW);
|
||||
fail("Expected IllegalArgumentException.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected
|
||||
}
|
||||
}
|
||||
|
||||
public void TestSetNumberFormat() {
|
||||
ULocale loc = new ULocale("en_US");
|
||||
NumberFormat nf = NumberFormat.getInstance(loc);
|
||||
nf.setMinimumFractionDigits(1);
|
||||
nf.setMaximumFractionDigits(1);
|
||||
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(loc);
|
||||
fmt.setNumberFormat(nf);
|
||||
|
||||
// Change nf after the fact to prove that we made a defensive copy
|
||||
nf.setMinimumFractionDigits(3);
|
||||
nf.setMaximumFractionDigits(3);
|
||||
|
||||
Object[][] data = {
|
||||
{0.0, Direction.NEXT, RelativeUnit.SECONDS, "in 0.0 seconds"},
|
||||
{0.5, Direction.NEXT, RelativeUnit.SECONDS, "in 0.5 seconds"},
|
||||
{1.0, Direction.NEXT, RelativeUnit.SECONDS, "in 1.0 seconds"},
|
||||
{2.0, Direction.NEXT, RelativeUnit.SECONDS, "in 2.0 seconds"},
|
||||
};
|
||||
for (Object[] row : data) {
|
||||
String actual = fmt.format(
|
||||
((Double) row[0]).doubleValue(), (Direction) row[1], (RelativeUnit) row[2]);
|
||||
assertEquals("Relative date with quantity special NumberFormat", row[3], actual);
|
||||
}
|
||||
}
|
||||
|
||||
public void TestCombineDateAndTime() {
|
||||
RelativeDateTimeFormatter fmt = RelativeDateTimeFormatter.getInstance(new ULocale("en_US"));
|
||||
assertEquals("TestcombineDateAndTime", "yesterday, 3:50", fmt.combineDateAndTime("yesterday", "3:50"));
|
||||
}
|
||||
|
||||
}
|
@ -80,7 +80,8 @@ public class TestAll extends TestGroup {
|
||||
"DateTimeGeneratorTest",
|
||||
"IntlTestSimpleDateFormatAPI",
|
||||
"DateFormatRegressionTestJ",
|
||||
"TimeZoneFormatTest"
|
||||
"TimeZoneFormatTest",
|
||||
"RelativeDateTimeFormatterTest"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user