ICU-10017 Rollback TimePeriod additions.

X-SVN-Rev: 34137
This commit is contained in:
Travis Keep 2013-08-30 00:17:33 +00:00
parent be5eec1c83
commit 33c0acf233
4 changed files with 7 additions and 468 deletions

1
.gitattributes vendored
View file

@ -267,7 +267,6 @@ 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/util/TimePeriod.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

View file

@ -19,10 +19,8 @@ import java.util.Set;
import java.util.TreeMap;
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;
@ -75,14 +73,7 @@ public class TimeUnitFormat extends MeasureFormat {
*/
public static final int ABBREVIATED_NAME = 1;
/**
* Constant for numeric style format.
* NUMERIC strives to be as brief as possible. For example: 3:05:47.
* @draft ICU 52
*/
public static final int NUMERIC = 2;
private static final int TOTAL_STYLES = 3;
private static final int TOTAL_STYLES = 2;
private static final long serialVersionUID = -3707773153184971529L;
@ -98,10 +89,6 @@ public class TimeUnitFormat extends MeasureFormat {
private ULocale locale;
private transient Map<TimeUnit, Map<String, Object[]>> timeUnitToCountToPatterns;
private transient PluralRules pluralRules;
private transient ListFormatter listFormatter;
private transient DateFormat hourMinute;
private transient DateFormat minuteSecond;
private transient DateFormat hourMinuteSecond;
private transient boolean isReady;
private int style;
@ -227,53 +214,23 @@ public class TimeUnitFormat extends MeasureFormat {
*/
public StringBuffer format(Object obj, StringBuffer toAppendTo,
FieldPosition pos) {
if ( !(obj instanceof TimeUnitAmount) && !(obj instanceof TimePeriod)) {
if ( !(obj instanceof TimeUnitAmount) ) {
throw new IllegalArgumentException(
"can only format TimeUnitAmount or TimePeriod objects");
"cannot format a non TimeUnitAmount object");
}
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();
String count = pluralRules.select(number);
// 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];
MessageFormat pattern = (MessageFormat)(countToPattern.get(count))[style];
return pattern.format(new Object[]{amount.getNumber()}, toAppendTo, pos);
}
private String formatTimePeriod(TimePeriod timePeriod) {
if (!isReady) {
setup();
}
if (style == NUMERIC) {
String result = formatPeriodAsNumeric(timePeriod);
if (result != null) {
return result;
}
}
String[] items = new String[timePeriod.length()];
int idx = 0;
for (TimeUnitAmount amount : timePeriod) {
items[idx++] = format(amount);
}
return listFormatter.format((Object[]) items);
}
/**
* 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.
* Parse a TimeUnitAmount.
* @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
* @stable ICU 4.0
*/
@ -295,10 +252,6 @@ public class TimeUnitFormat extends MeasureFormat {
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);
@ -379,14 +332,6 @@ public class TimeUnitFormat extends MeasureFormat {
format = NumberFormat.getNumberInstance(locale);
}
pluralRules = PluralRules.forLocale(locale);
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);
@ -394,99 +339,6 @@ public class TimeUnitFormat extends MeasureFormat {
isReady = true;
}
// 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();
}
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 numericFormat(
d, hourMinuteSecond, DateFormat.Field.SECOND, smallestUnitAmount);
}
if (biggestUnit == TimeUnit.MINUTE && smallestUnit == TimeUnit.SECOND) {
return numericFormat(
d, minuteSecond, DateFormat.Field.SECOND, smallestUnitAmount);
}
if (biggestUnit == TimeUnit.HOUR && smallestUnit == TimeUnit.MINUTE) {
return numericFormat(d, hourMinute, DateFormat.Field.MINUTE, smallestUnitAmount);
}
return null;
}
/**
* 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 0.0;
}
return tua.getNumber().doubleValue();
}
private void setup(String resourceKey, Map<TimeUnit, Map<String, Object[]>> timeUnitToCountToPatterns,
int style, Set<String> pluralKeywords) {
// fill timeUnitToCountToPatterns from resource file

View file

@ -1,171 +0,0 @@
/*
*******************************************************************************
* Copyright (C) 2013, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.util;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* TimePeriod represents a time period. TimePeriod objects are immutable.
* <p>Example usage:
* <pre>
* Period p = Period.forAmounts(
* new TimeUnitAmount (TimeUnit.WEEK, 5),
* new TimeUnitAmount (TimeUnit.DAY, 40),
* new TimeUnitAmount (TimeUnit.HOUR, 2),
* new TimeUnitAmount (TimeUnit.SECOND, 8));
* </pre>
* @draft ICU 52
* @provisional This API might change or be removed in a future release.
*/
public final class TimePeriod implements Iterable<TimeUnitAmount> {
private final TimeUnitAmount[] fields;
private final int length;
private final int hash;
/**
* 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.
* @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 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.");
}
fields[index] = tua;
tempSize++;
}
length = tempSize;
if (length == 0) {
throw new IllegalArgumentException(
"There must be at least one TimeUnitAmount.");
}
boolean fractionalFieldEncountered = false;
for (TimeUnitAmount tua : this) {
if (fractionalFieldEncountered) {
throw new IllegalArgumentException(
"Only the smallest time unit can have a fractional amount.");
}
double value = tua.getNumber().doubleValue();
if (value != Math.floor(value)) {
fractionalFieldEncountered = true;
}
}
hash = computeHash(fields);
}
/**
* Gets the value for a specific time unit.
* @param timeUnit the time unit.
* @return the TimeUnitAmount or null if no value is present for given TimeUnit.
* A non-existing value and a zero value are two different things.
* @draft ICU 52
* @provisional This API might change or be removed in a future release.
*/
public TimeUnitAmount getAmount(TimeUnit timeUnit) {
return fields[timeUnit.getIndex()];
}
/**
* Returned iterator iterates over all TimeUnitAmount objects in this object.
* Iterated TimeUnitAmount objects are ordered from largest TimeUnit to
* smallest TimeUnit. Remove method on returned iterator throws an
* UnsupportedOperationException.
* @draft ICU 52
* @provisional This API might change or be removed in a future release.
*/
public Iterator<TimeUnitAmount> iterator() {
return new TPIterator();
}
/**
* Returns the number of TimeUnitAmount objects in this object.
* @draft ICU 52
*/
public int length() {
return length;
}
/**
* Two TimePeriod objects are equal if they contain equal TimeUnitAmount objects.
* @draft ICU 52
* @provisional This API might change or be removed in a future release.
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof TimePeriod)) {
return false;
}
TimePeriod rhs = (TimePeriod) o;
if (this.hash != rhs.hash) {
return false;
}
return Arrays.equals(fields, rhs.fields);
}
/**
* Overrides hashCode().
* @draft ICU 52
* @provisional This API might change or be removed in a future release.
*/
@Override
public int hashCode() {
return hash;
}
private static int computeHash(TimeUnitAmount[] fields) {
int result = 0;
for (TimeUnitAmount amount : fields) {
result *= 31;
if (amount != null) {
result += amount.hashCode();
}
}
return result;
}
private class TPIterator implements Iterator<TimeUnitAmount> {
private int index = 0;
public boolean hasNext() {
while (index < fields.length && fields[index] == null) {
index++;
}
return index < fields.length;
}
public TimeUnitAmount next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return fields[index++];
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}

View file

@ -13,7 +13,6 @@ import java.util.Locale;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.TimeUnitFormat;
import com.ibm.icu.util.TimePeriod;
import com.ibm.icu.util.TimeUnit;
import com.ibm.icu.util.TimeUnitAmount;
import com.ibm.icu.util.ULocale;
@ -23,40 +22,6 @@ import com.ibm.icu.util.ULocale;
*
*/
public class TimeUnitTest extends TestFmwk {
private static final TimePeriod _19m = new TimePeriod(
new TimeUnitAmount(19.0, TimeUnit.MINUTE));
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 = new TimePeriod(
new TimeUnitAmount(1.0, TimeUnit.HOUR),
new TimeUnitAmount(23.5, TimeUnit.SECOND));
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 = new TimePeriod(
new TimeUnitAmount(5.0, TimeUnit.HOUR),
new TimeUnitAmount(17.0, TimeUnit.MINUTE));
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);
}
@ -68,11 +33,10 @@ public class TimeUnitTest extends TestFmwk {
TimeUnitFormat[] formats = new TimeUnitFormat[] {
new TimeUnitFormat(new ULocale(locales[locIndex]), TimeUnitFormat.FULL_NAME),
new TimeUnitFormat(new ULocale(locales[locIndex]), TimeUnitFormat.ABBREVIATED_NAME),
new TimeUnitFormat(new ULocale(locales[locIndex]), TimeUnitFormat.NUMERIC)
};
for (int style = TimeUnitFormat.FULL_NAME;
style <= TimeUnitFormat.NUMERIC;
style <= TimeUnitFormat.ABBREVIATED_NAME;
++style) {
final TimeUnit[] values = TimeUnit.values();
for (int j = 0; j < values.length; ++j) {
@ -85,7 +49,7 @@ public class TimeUnitTest extends TestFmwk {
logln(tests[i] + " => " + formatted);
try {
// Style should not matter when parsing.
for (int parseStyle = TimeUnitFormat.FULL_NAME; parseStyle <= TimeUnitFormat.NUMERIC; parseStyle++) {
for (int parseStyle = TimeUnitFormat.FULL_NAME; parseStyle <= TimeUnitFormat.ABBREVIATED_NAME; parseStyle++) {
TimeUnitAmount result = (TimeUnitAmount) formats[parseStyle].parseObject(formatted);
if (result == null || !source.equals(result)) {
errln("No round trip: " + source + " => " + formatted + " => " + result);
@ -101,7 +65,6 @@ public class TimeUnitTest extends TestFmwk {
}
public void TestAPI() {
try {
TimeUnitFormat format = new TimeUnitFormat();
format.setLocale(new ULocale("pt_BR"));
formatParsing(format);
@ -124,9 +87,6 @@ public class TimeUnitTest extends TestFmwk {
format = new TimeUnitFormat(new Locale("ja"));
format.setNumberFormat(NumberFormat.getNumberInstance(new Locale("en")));
formatParsing(format);
} catch (Exception e) {
e.printStackTrace();
}
}
/*
@ -368,105 +328,4 @@ public class TimeUnitTest extends TestFmwk {
tuf1.setNumberFormat(NumberFormat.getInstance());
tuf1.parseObject("", new ParsePosition(0));
}
public void TestFormatPeriodEn() {
Object[][] fullData = {
{_1m_59_9996s, "1 minute, 59.9996 seconds"},
{_19m, "19 minutes"},
{_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, 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, 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 {
new TimePeriod(
new TimeUnitAmount(3.0, TimeUnit.HOUR),
new TimeUnitAmount(5.0, TimeUnit.HOUR));
errln("Expected IllegalArgumentException on duplicate TimeUnits.");
} catch (IllegalArgumentException e) {
// expected
}
try {
new TimePeriod();
errln("Expected IllegalArgumentException on missing TimeUnitAmounts.");
} catch (IllegalArgumentException e) {
// expected
}
try {
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.");
} catch (IllegalArgumentException e) {
// expected
}
}
public void TestTimePeriodEqualsHashCode() {
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 = new TimePeriod(
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) {
StringBuilder builder = new StringBuilder();
boolean failure = false;
for (Object[] testCase : testData) {
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;
}
}
if (failure) {
errln(builder.toString());
}
}
}