ICU-10274 Add compound duration formatting for JAVA.

X-SVN-Rev: 33980
This commit is contained in:
Travis Keep 2013-07-24 23:07:31 +00:00
parent a26088f951
commit 4b1b47ddb0
4 changed files with 246 additions and 136 deletions

View file

@ -13,6 +13,9 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import javax.management.StandardEmitterMBean;
import com.ibm.icu.impl.ICUCache;
import com.ibm.icu.impl.ICUResourceBundle;
@ -34,6 +37,43 @@ final public class ListFormatter {
private final String middle;
private final String end;
private final ULocale locale;
/**
* Indicates the style of Listformatter
* @deprecated internal use only.
* @internal
*/
public enum Style {
/**
* Standard style.
* @deprecated
* @internal
*/
STANDARD("standard"),
/**
* Style for full durations
* @deprecated
* @internal
*/
DURATION("duration"),
/**
* Style for durations in abbrevated form
* @deprecated
* @internal
*/
DURATION_SHORT("duration-short");
private final String name;
Style(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
/**
* <b>Internal:</b> Create a ListFormatter from component strings,
@ -75,7 +115,7 @@ final public class ListFormatter {
* @provisional This API might change or be removed in a future release.
*/
public static ListFormatter getInstance(ULocale locale) {
return cache.get(locale);
return getInstance(locale, Style.STANDARD);
}
/**
@ -88,7 +128,20 @@ final public class ListFormatter {
* @provisional This API might change or be removed in a future release.
*/
public static ListFormatter getInstance(Locale locale) {
return getInstance(ULocale.forLocale(locale));
return getInstance(ULocale.forLocale(locale), Style.STANDARD);
}
/**
* Create a list formatter that is appropriate for a locale and style.
*
* @param locale the locale in question.
* @param style the style
* @return ListFormatter
* @deprecated Internal use only.
* @internal
*/
public static ListFormatter getInstance(ULocale locale, Style style) {
return cache.get(locale, style.getName());
}
/**
@ -199,28 +252,39 @@ final public class ListFormatter {
}
private static class Cache {
private final ICUCache<ULocale, ListFormatter> cache =
new SimpleCache<ULocale, ListFormatter>();
private final ICUCache<String, ListFormatter> cache =
new SimpleCache<String, ListFormatter>();
public ListFormatter get(ULocale locale) {
ListFormatter result = cache.get(locale);
public ListFormatter get(ULocale locale, String style) {
String key = String.format("%s:%s", locale.toString(), style);
ListFormatter result = cache.get(key);
if (result == null) {
result = load(locale);
cache.put(locale, result);
result = load(locale, style);
cache.put(key, result);
}
return result;
}
private static ListFormatter load(ULocale ulocale) {
private static ListFormatter load(ULocale ulocale, String style) {
ICUResourceBundle r = (ICUResourceBundle)UResourceBundle.
getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, ulocale);
r = r.getWithFallback("listPattern/standard");
return new ListFormatter(
r.getWithFallback("2").getString(),
r.getWithFallback("start").getString(),
r.getWithFallback("middle").getString(),
r.getWithFallback("end").getString(),
ulocale);
// TODO(Travis Keep): This try-catch is a hack to cover missing aliases
// for listPattern/duration and listPattern/duration-narrow in root.txt.
try {
return new ListFormatter(
r.getWithFallback("listPattern/" + style + "/2").getString(),
r.getWithFallback("listPattern/" + style + "/start").getString(),
r.getWithFallback("listPattern/" + style + "/middle").getString(),
r.getWithFallback("listPattern/" + style + "/end").getString(),
ulocale);
} catch (MissingResourceException e) {
return new ListFormatter(
r.getWithFallback("listPattern/standard/2").getString(),
r.getWithFallback("listPattern/standard/start").getString(),
r.getWithFallback("listPattern/standard/middle").getString(),
r.getWithFallback("listPattern/standard/end").getString(),
ulocale);
}
}
}

View file

@ -6,8 +6,10 @@
*/
package com.ibm.icu.text;
import java.text.AttributedCharacterIterator;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@ -20,6 +22,7 @@ import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.util.TimePeriod;
import com.ibm.icu.util.TimeUnit;
import com.ibm.icu.util.TimeUnitAmount;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.ULocale.Category;
import com.ibm.icu.util.UResourceBundle;
@ -96,9 +99,9 @@ public class TimeUnitFormat extends MeasureFormat {
private transient Map<TimeUnit, Map<String, Object[]>> timeUnitToCountToPatterns;
private transient PluralRules pluralRules;
private transient ListFormatter listFormatter;
private transient MessageFormat hourMinute;
private transient MessageFormat minuteSecond;
private transient MessageFormat hourMinuteSecond;
private transient DateFormat hourMinute;
private transient DateFormat minuteSecond;
private transient DateFormat hourMinuteSecond;
private transient boolean isReady;
private int style;
@ -132,8 +135,7 @@ public class TimeUnitFormat extends MeasureFormat {
}
/**
* Create TimeUnitFormat given a ULocale and a formatting style: full or
* abbreviated.
* Create TimeUnitFormat given a ULocale and a formatting style.
* @param locale locale of this time unit formatter.
* @param style format style, either FULL_NAME or ABBREVIATED_NAME style.
* @throws IllegalArgumentException if the style is not FULL_NAME or
@ -150,8 +152,7 @@ public class TimeUnitFormat extends MeasureFormat {
}
/**
* Create TimeUnitFormat given a Locale and a formatting style: full or
* abbreviated.
* Create TimeUnitFormat given a Locale and a formatting style.
* @stable ICU 4.2
*/
public TimeUnitFormat(Locale locale, int style) {
@ -226,12 +227,18 @@ public class TimeUnitFormat extends MeasureFormat {
*/
public StringBuffer format(Object obj, StringBuffer toAppendTo,
FieldPosition pos) {
if ( !(obj instanceof TimeUnitAmount) ) {
throw new IllegalArgumentException("can not format non TimeUnitAmount object");
if ( !(obj instanceof TimeUnitAmount) && !(obj instanceof TimePeriod)) {
throw new IllegalArgumentException(
"can only format TimeUnitAmount or TimePeriod objects");
}
if (!isReady) {
setup();
}
if (obj instanceof TimePeriod) {
// TODO: set FieldPosition, see ICU tickets 10156 and 10157.
toAppendTo.append(formatTimePeriod((TimePeriod) obj));
return toAppendTo;
}
TimeUnitAmount amount = (TimeUnitAmount) obj;
Map<String, Object[]> countToPattern = timeUnitToCountToPatterns.get(amount.getTimeUnit());
double number = amount.getNumber().doubleValue();
@ -242,13 +249,7 @@ public class TimeUnitFormat extends MeasureFormat {
return pattern.format(new Object[]{amount.getNumber()}, toAppendTo, pos);
}
/**
* Formats a TimePeriod. Currently there is no way to parse a formatted TimePeriod.
* @param timePeriod the TimePeriod to format.
* @return the formatted string.
* @draft ICU 52
*/
public String formatTimePeriod(TimePeriod timePeriod) {
private String formatTimePeriod(TimePeriod timePeriod) {
if (!isReady) {
setup();
}
@ -258,7 +259,7 @@ public class TimeUnitFormat extends MeasureFormat {
return result;
}
}
String[] items = new String[timePeriod.size()];
String[] items = new String[timePeriod.length()];
int idx = 0;
for (TimeUnitAmount amount : timePeriod) {
items[idx++] = format(amount);
@ -267,7 +268,12 @@ public class TimeUnitFormat extends MeasureFormat {
}
/**
* Parse a TimeUnitAmount.
* Parse a TimeUnitAmount. Parsing TimePeriod objects is not supported.
* If parseObject is called on a formatted TimePeriod string, it try to parse it
* as a TimeUnitAmount. For example,
* <code>parseObject("5 hours and 34 minutes", pos)</code>
* returns a TimeUnitAmount representing 5 hours and updates pos to point to the
* space after the s in hours.
* @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
* @stable ICU 4.0
*/
@ -373,75 +379,112 @@ public class TimeUnitFormat extends MeasureFormat {
format = NumberFormat.getNumberInstance(locale);
}
pluralRules = PluralRules.forLocale(locale);
listFormatter = ListFormatter.getInstance(locale);
DateTimePatternGenerator df = DateTimePatternGenerator.getInstance(locale);
hourMinute = getPattern(df, "hm", locale, "{0}", "{1,number,00.###}", null);
minuteSecond = getPattern(df, "ms", locale, null, "{1}", "{2,number,00.###}");
hourMinuteSecond = getPattern(df, "hms", locale, "{0}", "{1,number,00}", "{2,number,00.###}");
if (style == FULL_NAME) {
listFormatter = ListFormatter.getInstance(locale, ListFormatter.Style.DURATION);
} else {
listFormatter = ListFormatter.getInstance(locale, ListFormatter.Style.DURATION_SHORT);
}
hourMinute = loadNumericDurationFormat(locale, "hm");
minuteSecond = loadNumericDurationFormat(locale, "ms");
hourMinuteSecond = loadNumericDurationFormat(locale, "hms");
timeUnitToCountToPatterns = new HashMap<TimeUnit, Map<String, Object[]>>();
Set<String> pluralKeywords = pluralRules.getKeywords();
setup("units/duration", timeUnitToCountToPatterns, FULL_NAME, pluralKeywords);
setup("unitsShort/duration", timeUnitToCountToPatterns, ABBREVIATED_NAME, pluralKeywords);
isReady = true;
}
private MessageFormat getPattern(DateTimePatternGenerator dtpg, String skeleton, ULocale locale,
String h, String m, String s) {
String pat = dtpg.getBestPattern(skeleton);
StringBuilder buffer = new StringBuilder();
for (Object item : new DateTimePatternGenerator.FormatParser().set(pat).getItems()) {
if (item instanceof DateTimePatternGenerator.VariableField) {
DateTimePatternGenerator.VariableField fld = (DateTimePatternGenerator.VariableField)item;
switch (fld.getType()) {
case DateTimePatternGenerator.HOUR: buffer.append(h); break;
case DateTimePatternGenerator.MINUTE: buffer.append(m); break;
case DateTimePatternGenerator.SECOND: buffer.append(s); break;
}
} else {
buffer.append(item);
}
}
return new MessageFormat(buffer.toString(), locale);
// type is one of "hm", "ms" or "hms"
private static DateFormat loadNumericDurationFormat(ULocale ulocale, String type) {
ICUResourceBundle r = (ICUResourceBundle)UResourceBundle.
getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, ulocale);
r = r.getWithFallback(String.format("durationUnits/%s", type));
// We replace 'h' with 'H' because 'h' does not make sense in the context of durations.
DateFormat result = new SimpleDateFormat(r.getString().replace("h", "H"));
result.setTimeZone(TimeZone.GMT_ZONE);
return result;
}
private String formatPeriodAsNumeric(TimePeriod timePeriod) {
TimeUnit biggestUnit = null, smallestUnit = null;
Number smallestUnitAmount = null;
for (TimeUnitAmount tua : timePeriod) {
if (biggestUnit == null) {
biggestUnit = tua.getTimeUnit();
}
smallestUnit = tua.getTimeUnit();
smallestUnitAmount = tua.getNumber();
}
// We have to trim the result of MessageFormat.format() not sure why.
long millis = (long) (((getAmountOrZero(timePeriod, TimeUnit.HOUR) * 60.0
+ getAmountOrZero(timePeriod, TimeUnit.MINUTE)) * 60.0
+ getAmountOrZero(timePeriod, TimeUnit.SECOND)) * 1000.0);
Date d = new Date(millis);
if (biggestUnit == TimeUnit.HOUR && smallestUnit == TimeUnit.SECOND) {
return hourMinuteSecond.format(new Object[]{
getZeroedAmount(timePeriod, TimeUnit.HOUR),
getZeroedAmount(timePeriod, TimeUnit.MINUTE),
getZeroedAmount(timePeriod, TimeUnit.SECOND)}).trim();
return numericFormat(
d, hourMinuteSecond, DateFormat.Field.SECOND, smallestUnitAmount);
}
if (biggestUnit == TimeUnit.MINUTE && smallestUnit == TimeUnit.SECOND) {
return minuteSecond.format(new Object[]{
null,
getZeroedAmount(timePeriod, TimeUnit.MINUTE),
getZeroedAmount(timePeriod, TimeUnit.SECOND)}).trim();
return numericFormat(
d, minuteSecond, DateFormat.Field.SECOND, smallestUnitAmount);
}
if (biggestUnit == TimeUnit.HOUR && smallestUnit == TimeUnit.MINUTE) {
return hourMinute.format(new Object[]{
getZeroedAmount(timePeriod, TimeUnit.HOUR),
getZeroedAmount(timePeriod, TimeUnit.MINUTE)}).trim();
return numericFormat(d, hourMinute, DateFormat.Field.MINUTE, smallestUnitAmount);
}
return null;
}
private Number getZeroedAmount(TimePeriod timePeriod, TimeUnit timeUnit) {
/**
* numericFormat allows us to show fractional durations using numeric
* style e.g 12:34:56.7. This function is necessary because there is no way to express
* fractions of durations other than seconds with current DateFormat objects.
*
* After formatting the duration using a DateFormat object in the usual way, it
* replaces the smallest field in the formatted string with the exact fractional
* amount of that smallest field formatted with this object's NumberFormat object.
*
* @param duration The duration to format in milliseconds. The loss of precision here
* is ok because we also pass in the exact amount of the smallest field.
* @param formatter formats the date.
* @param smallestField the smallest defined field in duration to be formatted.
* @param smallestAmount the exact fractional value of the smallest amount.
* @return duration formatted numeric style.
*/
private String numericFormat(
Date duration,
DateFormat formatter,
DateFormat.Field smallestField,
Number smallestAmount) {
// Format the smallest amount ahead of time.
String smallestAmountFormatted = format.format(smallestAmount);
// Format the duration using the provided DateFormat object. The smallest
// field in this result will be missing the fractional part.
AttributedCharacterIterator iterator = formatter.formatToCharacterIterator(duration);
// The final formatted duration will be written here.
StringBuilder builder = new StringBuilder();
// iterate through formatted text copying to 'builder' one character at a time.
// When we get to the smallest amount, skip over it and copy
// 'smallestAmountFormatted' to the builder instead.
for (iterator.first(); iterator.getIndex() < iterator.getEndIndex();) {
if (iterator.getAttributes().containsKey(smallestField)) {
builder.append(smallestAmountFormatted);
iterator.setIndex(iterator.getRunLimit(smallestField));
} else {
builder.append(iterator.current());
iterator.next();
}
}
return builder.toString();
}
private static double getAmountOrZero(TimePeriod timePeriod, TimeUnit timeUnit) {
TimeUnitAmount tua = timePeriod.getAmount(timeUnit);
if (tua == null) {
return Double.valueOf(0);
return 0.0;
}
return tua.getNumber();
return tua.getNumber().doubleValue();
}
private void setup(String resourceKey, Map<TimeUnit, Map<String, Object[]>> timeUnitToCountToPatterns,

View file

@ -26,68 +26,40 @@ import java.util.NoSuchElementException;
public final class TimePeriod implements Iterable<TimeUnitAmount> {
private final TimeUnitAmount[] fields;
private final int size;
private final int length;
private final int hash;
private TimePeriod(TimeUnitAmount[] fields, int size, int hash) {
this.fields = fields;
this.size = size;
this.hash = hash;
}
/**
* Returns a new TimePeriod that matches the given time unit amounts.
* @param amounts the TimeUnitAmounts. Must be non-empty. Normalization of the
* amounts and inclusion/exclusion of 0 amounts is up to caller. The Number
* in each TimeUnitAmount must either be a Byte, Short, Integer, Long, Float,
* Double, BigInteger, or BigDecimal or it must implement Cloneable and have
* a public clone method.
* @return the new TimePeriod object
* @throws IllegalArgumentException if multiple TimeUnitAmount objects match
* the same time unit or if any but the smallest TimeUnit has a fractional value
* Or if amounts is empty.
* @draft ICU 52
* @provisional This API might change or be removed in a future release.
*/
public static TimePeriod forAmounts(TimeUnitAmount ...amounts) {
return forAmounts(Arrays.asList(amounts));
}
/**
* Returns a new TimePeriod that matches the given time unit amounts.
* Constructor.
* @param amounts the TimeUnitAmounts. Must be non-empty. Normalization of the
* amounts and inclusion/exclusion of 0 amounts is up to caller. The Number
* object in each TimeUnitAmount must not change. Otherwise the created
* TimePeriod object may not work as expected.
* @return the new TimePeriod object
* @throws IllegalArgumentException if multiple TimeUnitAmount objects match
* the same time unit or if any but the smallest TimeUnit has a fractional value
* Or if amounts is empty.
* @draft ICU 52
* @provisional This API might change or be removed in a future release.
*/
public static TimePeriod forAmounts(Iterable<TimeUnitAmount> amounts) {
TimeUnitAmount[] fields = new TimeUnitAmount[TimeUnit.TIME_UNIT_COUNT];
int size = 0;
public TimePeriod(TimeUnitAmount ...amounts) {
fields = new TimeUnitAmount[TimeUnit.TIME_UNIT_COUNT];
int tempSize = 0;
for (TimeUnitAmount tua : amounts) {
int index = tua.getTimeUnit().getIndex();
if (fields[index] != null) {
throw new IllegalArgumentException(
"Only one TimeUnitAmount per unit allowed.");
}
// This line is necessary to guarantee immutability of the TimePeriod
// class. A Number object, which is in TimeUnitAmount, need not be immutable,
// but Double is immutable.
fields[index] = tua;
size++;
tempSize++;
}
if (size == 0) {
length = tempSize;
if (length == 0) {
throw new IllegalArgumentException(
"There must be at least one TimeUnitAmount.");
}
TimePeriod result = new TimePeriod(fields, size, computeHash(fields));
boolean fractionalFieldEncountered = false;
for (TimeUnitAmount tua : result) {
for (TimeUnitAmount tua : this) {
if (fractionalFieldEncountered) {
throw new IllegalArgumentException(
"Only the smallest time unit can have a fractional amount.");
@ -97,7 +69,7 @@ public final class TimePeriod implements Iterable<TimeUnitAmount> {
fractionalFieldEncountered = true;
}
}
return result;
hash = computeHash(fields);
}
/**
@ -126,11 +98,10 @@ public final class TimePeriod implements Iterable<TimeUnitAmount> {
/**
* Returns the number of TimeUnitAmount objects in this object.
* @internal
* @deprecated This API is ICU internal only.
* @draft ICU 52
*/
public int size() {
return size;
public int length() {
return length;
}
/**

View file

@ -23,26 +23,39 @@ import com.ibm.icu.util.ULocale;
*
*/
public class TimeUnitTest extends TestFmwk {
private static final TimePeriod _19m = TimePeriod.forAmounts(
private static final TimePeriod _19m = new TimePeriod(
new TimeUnitAmount(19.0, TimeUnit.MINUTE));
private static final TimePeriod _19m_28s = TimePeriod.forAmounts(
private static final TimePeriod _19m_28s = new TimePeriod(
new TimeUnitAmount(19.0, TimeUnit.MINUTE),
new TimeUnitAmount(28.0, TimeUnit.SECOND));
private static final TimePeriod _1h_23_5s = TimePeriod.forAmounts(
private static final TimePeriod _1h_23_5s = new TimePeriod(
new TimeUnitAmount(1.0, TimeUnit.HOUR),
new TimeUnitAmount(23.5, TimeUnit.SECOND));
private static final TimePeriod _1h_0m_23s = TimePeriod.forAmounts(
private static final TimePeriod _1h_23_5m = new TimePeriod(
new TimeUnitAmount(1.0, TimeUnit.HOUR),
new TimeUnitAmount(23.5, TimeUnit.MINUTE));
private static final TimePeriod _1h_0m_23s = new TimePeriod(
new TimeUnitAmount(1.0, TimeUnit.HOUR),
new TimeUnitAmount(0.0, TimeUnit.MINUTE),
new TimeUnitAmount(23.0, TimeUnit.SECOND));
private static final TimePeriod _5h_17m = TimePeriod.forAmounts(
private static final TimePeriod _5h_17m = new TimePeriod(
new TimeUnitAmount(5.0, TimeUnit.HOUR),
new TimeUnitAmount(17.0, TimeUnit.MINUTE));
private static final TimePeriod _2y_5M_3w_4d = TimePeriod.forAmounts(
private static final TimePeriod _2y_5M_3w_4d = new TimePeriod(
new TimeUnitAmount(2.0, TimeUnit.YEAR),
new TimeUnitAmount(5.0, TimeUnit.MONTH),
new TimeUnitAmount(3.0, TimeUnit.WEEK),
new TimeUnitAmount(4.0, TimeUnit.DAY));
private static final TimePeriod _0h_0m_17s = new TimePeriod(
new TimeUnitAmount(0.0, TimeUnit.HOUR),
new TimeUnitAmount(0.0, TimeUnit.MINUTE),
new TimeUnitAmount(17.0, TimeUnit.SECOND));
private static final TimePeriod _6h_56_92m = new TimePeriod(
new TimeUnitAmount(6.0, TimeUnit.HOUR),
new TimeUnitAmount(56.92, TimeUnit.MINUTE));
private static final TimePeriod _1m_59_9996s = new TimePeriod(
new TimeUnitAmount(1.0, TimeUnit.MINUTE),
new TimeUnitAmount(59.9996, TimeUnit.SECOND));
public static void main(String[] args) throws Exception{
new TimeUnitTest().run(args);
@ -358,33 +371,52 @@ public class TimeUnitTest extends TestFmwk {
public void TestFormatPeriodEn() {
Object[][] fullData = {
{_1m_59_9996s, "1 minute, 59.9996 seconds"},
{_19m, "19 minutes"},
{_1h_23_5s, "1 hour and 23.5 seconds"},
{_1h_0m_23s, "1 hour, 0 minutes, and 23 seconds"},
{_2y_5M_3w_4d, "2 years, 5 months, 3 weeks, and 4 days"}};
{_1h_23_5s, "1 hour, 23.5 seconds"},
{_1h_23_5m, "1 hour, 23.5 minutes"},
{_1h_0m_23s, "1 hour, 0 minutes, 23 seconds"},
{_2y_5M_3w_4d, "2 years, 5 months, 3 weeks, 4 days"}};
Object[][] abbrevData = {
{_1m_59_9996s, "1 min, 59.9996 secs"},
{_19m, "19 mins"},
{_1h_23_5s, "1 hr and 23.5 secs"},
{_1h_0m_23s, "1 hr, 0 mins, and 23 secs"},
{_2y_5M_3w_4d, "2 yrs, 5 mths, 3 wks, and 4 days"}};
{_1h_23_5s, "1 hr, 23.5 secs"},
{_1h_23_5m, "1 hr, 23.5 mins"},
{_1h_0m_23s, "1 hr, 0 mins, 23 secs"},
{_2y_5M_3w_4d, "2 yrs, 5 mths, 3 wks, 4 days"}};
Object[][] numericData = {
{_1m_59_9996s, "1:59.9996"},
{_19m, "19 mins"},
{_1h_23_5s, "1:00:23.5"},
{_1h_0m_23s, "1:00:23"},
{_1h_23_5m, "1:23.5"},
{_5h_17m, "5:17"},
{_19m_28s, "19:28"},
{_2y_5M_3w_4d, "2 yrs, 5 mths, 3 wks, and 4 days"}};
{_2y_5M_3w_4d, "2 yrs, 5 mths, 3 wks, 4 days"},
{_0h_0m_17s, "0:00:17"},
{_6h_56_92m, "6:56.92"}};
TimeUnitFormat tuf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.FULL_NAME);
NumberFormat nf = NumberFormat.getNumberInstance(ULocale.ENGLISH);
nf.setMaximumFractionDigits(4);
tuf.setNumberFormat(nf);
verifyFormatPeriod("en FULL", tuf, fullData);
tuf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.ABBREVIATED_NAME);
tuf.setNumberFormat(nf);
verifyFormatPeriod("en ABBREV", tuf, abbrevData);
tuf = new TimeUnitFormat(ULocale.ENGLISH, TimeUnitFormat.NUMERIC);
tuf.setNumberFormat(nf);
verifyFormatPeriod("en NUMERIC", tuf, numericData);
}
public void TestTimePeriodLength() {
assertEquals("length", 2, new TimePeriod(
new TimeUnitAmount(3.0, TimeUnit.HOUR),
new TimeUnitAmount(5.0, TimeUnit.MINUTE)).length());
}
public void TestTimePeriodForAmounts() {
try {
TimePeriod.forAmounts(
new TimePeriod(
new TimeUnitAmount(3.0, TimeUnit.HOUR),
new TimeUnitAmount(5.0, TimeUnit.HOUR));
errln("Expected IllegalArgumentException on duplicate TimeUnits.");
@ -392,13 +424,13 @@ public class TimeUnitTest extends TestFmwk {
// expected
}
try {
TimePeriod.forAmounts();
new TimePeriod();
errln("Expected IllegalArgumentException on missing TimeUnitAmounts.");
} catch (IllegalArgumentException e) {
// expected
}
try {
TimePeriod.forAmounts(
new TimePeriod(
new TimeUnitAmount(3.5, TimeUnit.HOUR),
new TimeUnitAmount(5.0, TimeUnit.MINUTE));
errln("Expected IllegalArgumentException. Only smallest time unit can have a fractional amount.");
@ -408,12 +440,12 @@ public class TimeUnitTest extends TestFmwk {
}
public void TestTimePeriodEqualsHashCode() {
TimePeriod our_19m_28s = TimePeriod.forAmounts(
TimePeriod our_19m_28s = new TimePeriod(
new TimeUnitAmount(28.0, TimeUnit.SECOND),
new TimeUnitAmount(19.0, TimeUnit.MINUTE));
assertEquals("TimePeriod equals", _19m_28s, our_19m_28s);
assertEquals("Hash code", _19m_28s.hashCode(), our_19m_28s.hashCode());
TimePeriod our_19m_29s = TimePeriod.forAmounts(
TimePeriod our_19m_29s = new TimePeriod(
new TimeUnitAmount(29.0, TimeUnit.SECOND),
new TimeUnitAmount(19.0, TimeUnit.MINUTE));
assertNotEquals("TimePeriod not equals", _19m_28s, our_19m_29s);
@ -427,7 +459,7 @@ public class TimeUnitTest extends TestFmwk {
StringBuilder builder = new StringBuilder();
boolean failure = false;
for (Object[] testCase : testData) {
String actual = tuf.formatTimePeriod((TimePeriod) testCase[0]);
String actual = tuf.format(testCase[0]);
if (!testCase[1].equals(actual)) {
builder.append(String.format("%s: Expected: '%s', got: '%s'\n", desc, testCase[1], actual));
failure = true;