ICU-6303 initial checkin

X-SVN-Rev: 24015
This commit is contained in:
Mark Davis 2008-05-28 06:50:14 +00:00
parent 342953342c
commit 9d6234899d
4 changed files with 343 additions and 0 deletions

View file

@ -0,0 +1,49 @@
/*
*******************************************************************************
* Copyright (C) 2008, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.dev.test.format;
import java.text.ParseException;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.text.TimeUnitFormat;
import com.ibm.icu.util.TimeUnit;
import com.ibm.icu.util.TimeUnitAmount;
import com.ibm.icu.util.ULocale;
/**
* @author markdavis
*
*/
public class TimeUnitTest extends TestFmwk {
public static void main(String[] args) throws Exception{
new TimeUnitTest().run(args);
}
public void TestBasic() {
TimeUnitFormat format = new TimeUnitFormat();
format.setLocale(ULocale.ENGLISH);
final TimeUnit[] values = TimeUnit.values();
for (int j = 0; j < values.length; ++j) {
final TimeUnit timeUnit = values[j];
double[] tests = {0, 0.5, 1, 1.5, 2, 5, 101.35};
for (int i = 0; i < tests.length; ++i) {
TimeUnitAmount source = new TimeUnitAmount(tests[i], timeUnit);
String formatted = format.format(source);
logln(tests[i] + " => " + formatted);
try {
TimeUnitAmount result = (TimeUnitAmount) format.parseObject(formatted);
if (result == null || !source.equals(result)) {
errln("No round trip: " + source + " => " + formatted + " => " + result);
}
} catch (ParseException e) {
errln(e.getMessage());
}
}
}
}
}

View file

@ -0,0 +1,180 @@
/*
*******************************************************************************
* Copyright (C) 2008, Google, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.text;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import com.ibm.icu.util.TimeUnit;
import com.ibm.icu.util.TimeUnitAmount;
import com.ibm.icu.util.ULocale;
/**
* Format or parse a TimeUnitAmount, using plural rules for the units where available.
* @see TimeUnitAmount
* @see TimeUnitFormat
* @author markdavis
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public class TimeUnitFormat extends MeasureFormat {
private NumberFormat format;
private ULocale locale;
private transient Map timeUnitToCountToPatterns = new HashMap();
private transient PluralRules pluralRules;
private transient boolean needToBuild = true;
/**
* Create empty format. Use setLocale and/or setFormat to modify.
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public TimeUnitFormat() {}
/**
* Set the locale used for formatting or parsing.
* @return this, for chaining.
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public TimeUnitFormat setLocale(ULocale locale) {
this.locale = locale;
needToBuild = true;
return this;
}
/**
* Set the locale used for formatting or parsing.
* @return this, for chaining.
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public TimeUnitFormat setLocale(Locale locale) {
this.locale = ULocale.forLocale(locale);
needToBuild = true;
return this;
}
/**
* Set the format used for formatting or parsing. If null or not available, use the getNumberInstance(locale).
* @return this, for chaining.
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public TimeUnitFormat setNumberFormat(NumberFormat format) {
this.format = format;
return this;
}
/**
* Format a TimeUnitAmount.
* @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
*/
public StringBuffer format(Object obj, StringBuffer toAppendTo,
FieldPosition pos) {
if (needToBuild) setup();
TimeUnitAmount amount = (TimeUnitAmount) obj;
Map countToPattern = (Map) timeUnitToCountToPatterns.get(amount.getTimeUnit());
double number = amount.getNumber().doubleValue();
String count = pluralRules.select(number);
MessageFormat pattern = (MessageFormat) countToPattern.get(count);
return pattern.format(new Object[]{amount.getNumber()}, toAppendTo, pos);
}
/**
* Parse a TimeUnitAmount.
*/
public Object parseObject(String source, ParsePosition pos) {
if (needToBuild) setup();
Number resultNumber = null;
TimeUnit resultTimeUnit = null;
int oldPos = pos.getIndex();
int newPos = -1;
// we don't worry too much about speed on parsing, but this can be optimized later if needed.
for (Iterator it = timeUnitToCountToPatterns.keySet().iterator(); it.hasNext();) {
TimeUnit timeUnit = (TimeUnit) it.next();
Map countToPattern = (Map) timeUnitToCountToPatterns.get(timeUnit);
for (Iterator it2 = countToPattern.keySet().iterator(); it2.hasNext();) {
String count = (String) it2.next();
MessageFormat pattern = (MessageFormat) countToPattern.get(count);
pos.setIndex(oldPos);
// see if we can parse
Object parsed = pattern.parseObject(source, pos);
if (parsed == null) {
continue;
}
// check to make sure that the timeUnit is consistent
Number temp = (Number)((Object[])parsed)[0];
String select = pluralRules.select(temp.doubleValue());
if (!count.equals(select)) {
continue;
}
resultNumber = temp;
resultTimeUnit = timeUnit;
newPos = pos.getIndex();
}
}
if (resultNumber == null) {
return null;
}
pos.setIndex(newPos);
pos.setErrorIndex(-1);
return new TimeUnitAmount(resultNumber, resultTimeUnit);
}
// *********************** Stubbed until we get CLDR data *******************************
// just do English for now
private static Object[][] data = {
{TimeUnit.SECOND, "one", "{0} second", "other", "{0} seconds"},
{TimeUnit.MINUTE, "one", "{0} minute", "other", "{0} minutes"},
{TimeUnit.HOUR, "one", "{0} hour", "other", "{0} hours"},
{TimeUnit.DAY, "one", "{0} day", "other", "{0} days"},
{TimeUnit.WEEK, "one", "{0} week", "other", "{0} weeks"},
{TimeUnit.MONTH, "one", "{0} month", "other", "{0} months"},
{TimeUnit.YEAR, "one", "{0} year", "other", "{0} years"}
};
// Initally, we are storing all of these as MessageFormats.
// I think it might actually be simpler to make them Decimal Formats later.
private void setup() {
if (locale == null) {
if (format != null) {
locale = format.getLocale(null);
}
if (locale == null) {
locale = ULocale.getDefault();
}
}
if (format == null) {
format = NumberFormat.getNumberInstance(locale);
}
pluralRules = PluralRules.forLocale(locale);
for (int i = 0; i < data.length; ++i) {
Map temp = new TreeMap();
for (int j = 1; j < data[i].length; j += 2) {
final MessageFormat messageFormat = new MessageFormat((String)data[i][j+1], locale);
if (format != null) {
messageFormat.setFormatByArgumentIndex(0, format);
}
temp.put(data[i][j], messageFormat);
}
timeUnitToCountToPatterns.put((TimeUnit)data[i][0], temp);
}
// it's an internal error if we get a count that we can't handle
// so check here to make sure that the rules are all covered
// TODO
needToBuild = false;
}
}

View file

@ -0,0 +1,66 @@
/*
*******************************************************************************
* Copyright (C) 2008, Google, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.util;
import java.util.Set;
import com.ibm.icu.text.TimeUnitFormat;
/**
* Measurement unit for time units.
* @see TimeUnitAmount
* @see TimeUnit
* @author markdavis
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public class TimeUnit extends MeasureUnit {
/**
* Supports selected time duration units
*/
private String name;
private static TimeUnit[] values = new TimeUnit[7]; // adjust count if new items are added
private static int valueCount = 0;
/**
* Constant value for supported time unit.
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public static TimeUnit
SECOND = new TimeUnit("SECOND"),
MINUTE = new TimeUnit("MINUTE"),
HOUR = new TimeUnit("HOUR"),
DAY = new TimeUnit("DAY"),
WEEK = new TimeUnit("WEEK"),
MONTH = new TimeUnit("MONTH"),
YEAR = new TimeUnit("YEAR");
private TimeUnit(String name) {
this.name = name;
values[valueCount++] = this; // store in values array
}
/**
* @return the available values
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public static TimeUnit[] values() {
return values.clone();
}
/**
* A string representation for debugging.
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public String toString() {
return name;
}
}

View file

@ -0,0 +1,48 @@
/*
*******************************************************************************
* Copyright (C) 2008, Google, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.util;
import com.ibm.icu.text.TimeUnitFormat;
/**
* Express a duration as a time unit and number. Patterned after Currency.
* <p>Immutable.
* @see TimeUnitAmount
* @see TimeUnitFormat
* @author markdavis
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public class TimeUnitAmount extends Measure {
/**
* Create from a number and unit.
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public TimeUnitAmount(Number number, TimeUnit unit) {
super(number, unit);
}
/**
* Create from a number and unit.
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public TimeUnitAmount(double number, TimeUnit unit) {
super(new Double(number), unit);
}
/**
* Get the unit (convenience to avoid cast).
* @draft ICU 4.0
* @provisional This API might change or be removed in a future release.
*/
public TimeUnit getTimeUnit() {
return (TimeUnit) getUnit();
}
}