*/
public static final int NUMERIC = 2;
- // For now we don't consider NUMERIC a full-fledged style. NUMERIC is
- // congruent to ABBREVIATED_NAME unless formatPeriod() is being called.
- private static final int TOTAL_STYLES = 2;
+ private static final int TOTAL_STYLES = 3;
private static final long serialVersionUID = -3707773153184971529L;
private transient MessageFormat hourMinuteSecond;
private transient boolean isReady;
private int style;
-
- // When style is set to NUMERIC, this field is set to true and the style
- // field becomes ABBREVIATED_NAME.
- private boolean isNumericStyle;
/**
* Create empty format using full name style, for example, "hours".
* @stable ICU 4.2
*/
public TimeUnitFormat(ULocale locale, int style) {
- if (style == NUMERIC) {
- style = ABBREVIATED_NAME;
- isNumericStyle = true;
- }
if (style < FULL_NAME || style >= TOTAL_STYLES) {
throw new IllegalArgumentException("style should be either FULL_NAME or ABBREVIATED_NAME style");
}
Map<String, Object[]> countToPattern = timeUnitToCountToPatterns.get(amount.getTimeUnit());
double number = amount.getNumber().doubleValue();
String count = pluralRules.select(number);
- MessageFormat pattern = (MessageFormat)(countToPattern.get(count))[style];
+ // A hack since NUMERIC really isn't a full fledged style
+ int effectiveStyle = (style == NUMERIC) ? ABBREVIATED_NAME : style;
+ MessageFormat pattern = (MessageFormat)(countToPattern.get(count))[effectiveStyle];
return pattern.format(new Object[]{amount.getNumber()}, toAppendTo, pos);
}
if (!isReady) {
setup();
}
- if (isNumericStyle) {
+ if (style == NUMERIC) {
String result = formatPeriodAsNumeric(timePeriod);
if (result != null) {
return result;
for (Entry<String, Object[]> patternEntry : countToPattern.entrySet()) {
String count = patternEntry.getKey();
for (int styl = FULL_NAME; styl < TOTAL_STYLES; ++styl) {
+ if (styl == NUMERIC) {
+ // Numeric isn't a real style, so skip it.
+ continue;
+ }
MessageFormat pattern = (MessageFormat)(patternEntry.getValue())[styl];
pos.setErrorIndex(-1);
pos.setIndex(oldPos);
*/
package com.ibm.icu.util;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.math.BigInteger;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
-import com.ibm.icu.math.BigDecimal;
-
/**
* TimePeriod represents a time period. TimePeriod objects are immutable.
* <p>Example usage:
* 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.
+ * 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
// 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] = cloneIfNecessary(tua);
+ fields[index] = tua;
size++;
}
if (size == 0) {
* @draft ICU 52
*/
public TimeUnitAmount getAmount(TimeUnit timeUnit) {
- return cloneIfNecessary(fields[timeUnit.getIndex()]);
+ return fields[timeUnit.getIndex()];
}
/**
return result;
}
- private static TimeUnitAmount cloneIfNecessary(TimeUnitAmount tua) {
- if (tua == null) {
- return null;
- }
- Number number = tua.getNumber();
- if (number instanceof Double || number instanceof Integer ||
- number instanceof Long || number instanceof Float ||
- number instanceof Byte || number instanceof Short ||
- number instanceof BigInteger || number instanceof BigDecimal) {
- return tua;
- }
- return new TimeUnitAmount(cloneNumber(number), tua.getTimeUnit());
- }
-
- private static Number cloneNumber(Number number) {
- // Since Number doesn't implement Cloneable, we have to use reflection
- // to find the clone() method. If this method throws an exception, it
- // means that the subclass of Number can't be cloned.
- Class<? extends Number> clz = number.getClass();
- Method cloneMethod;
- try {
- cloneMethod = clz.getMethod("clone");
- cloneMethod.setAccessible(true);
- return (Number) cloneMethod.invoke(number);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException(e);
- } catch (SecurityException e) {
- throw new RuntimeException(e);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- } catch (IllegalArgumentException e) {
- throw new RuntimeException(e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- }
-
private class TPIterator implements Iterator<TimeUnitAmount> {
private int index = 0;
}
public void TestAPI() {
+ try {
TimeUnitFormat format = new TimeUnitFormat();
format.setLocale(new ULocale("pt_BR"));
formatParsing(format);
format = new TimeUnitFormat(new Locale("ja"));
format.setNumberFormat(NumberFormat.getNumberInstance(new Locale("en")));
formatParsing(format);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
}
/*
}
}
- public void TestTimePeriodWithMutableNumber() {
- MutableInt mutableInput = new MutableInt(3);
- TimePeriod tp = TimePeriod.forAmounts(
- new TimeUnitAmount(mutableInput, TimeUnit.HOUR));
- mutableInput.set(5);
- MutableInt mutableOutput = (MutableInt) tp.getAmount(TimeUnit.HOUR).getNumber();
- assertEquals(
- "Mutating input shouldn't affect TimePeriod.",
- 3,
- mutableOutput.intValue());
- mutableOutput.set(5);
- assertEquals(
- "Mutating output shouldn't affect TimePeriod.",
- 3,
- ((MutableInt) tp.getAmount(TimeUnit.HOUR).getNumber()).intValue());
+ public void TestTimePeriodEqualsHashCode() {
+ TimePeriod our_19m_28s = TimePeriod.forAmounts(
+ 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(
+ new TimeUnitAmount(29.0, TimeUnit.SECOND),
+ new TimeUnitAmount(19.0, TimeUnit.MINUTE));
+ assertNotEquals("TimePeriod not equals", _19m_28s, our_19m_29s);
+
+ // It may be possible for non-equal objects to have equal hashCodes, but we
+ // are betting on the probability of that to be miniscule.
+ assertNotEquals("TimePeriod hash not equals", _19m_28s.hashCode(), our_19m_29s.hashCode());
}
private void verifyFormatPeriod(String desc, TimeUnitFormat tuf, Object[][] testData) {
errln(builder.toString());
}
}
-
- private static class MutableInt extends Number implements Cloneable {
-
- private int value;
-
- public MutableInt(int x) {
- value = x;
- }
-
- @Override
- public int intValue() {
- return value;
- }
-
- @Override
- public long longValue() {
- return value;
- }
-
- @Override
- public float floatValue() {
- return value;
- }
-
- @Override
- public double doubleValue() {
- return value;
- }
-
- public void set(int x) {
- value = x;
- }
-
- @Override
- public MutableInt clone() {
- try {
- return (MutableInt) super.clone();
- } catch (CloneNotSupportedException e) {
- return null;
- }
- }
- }
}