ICU-6397 fix duration format milliseconds problem

X-SVN-Rev: 25248
This commit is contained in:
Doug Felt 2009-01-14 17:43:16 +00:00
parent a16b7c3c0c
commit 249f9598f3
3 changed files with 86 additions and 27 deletions

View File

@ -1,6 +1,6 @@
/*
******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* Copyright (C) 2007-2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
@ -114,6 +114,12 @@ class BasicDurationFormatterFactory implements DurationFormatterFactory {
public DurationFormatterFactory setLocale(String localeName) {
if (!localeName.equals(this.localeName)) {
this.localeName = localeName;
if (builder != null) {
builder = builder.withLocale(localeName);
}
if (formatter != null) {
formatter = formatter.withLocale(localeName);
}
reset();
}
return this;
@ -129,6 +135,9 @@ class BasicDurationFormatterFactory implements DurationFormatterFactory {
public DurationFormatterFactory setTimeZone(TimeZone timeZone) {
if (!timeZone.equals(this.timeZone)) {
this.timeZone = timeZone;
if (builder != null) {
builder = builder.withTimeZone(timeZone);
}
reset();
}
return this;
@ -144,11 +153,8 @@ class BasicDurationFormatterFactory implements DurationFormatterFactory {
if (fallback != null) {
fallback = fallback.withLocale(localeName).withTimeZone(timeZone);
}
formatter = getPeriodFormatter()
.withLocale(localeName);
builder = getPeriodBuilder()
.withLocale(localeName)
.withTimeZone(timeZone);
formatter = getPeriodFormatter();
builder = getPeriodBuilder();
f = createFormatter();
}
@ -162,7 +168,9 @@ class BasicDurationFormatterFactory implements DurationFormatterFactory {
*/
public PeriodFormatter getPeriodFormatter() {
if (formatter == null) {
formatter = ps.newPeriodFormatterFactory().getFormatter();
formatter = ps.newPeriodFormatterFactory()
.setLocale(localeName)
.getFormatter();
}
return formatter;
}
@ -174,7 +182,10 @@ class BasicDurationFormatterFactory implements DurationFormatterFactory {
*/
public PeriodBuilder getPeriodBuilder() {
if (builder == null) {
builder = ps.newPeriodBuilderFactory().getSingleUnitBuilder();
builder = ps.newPeriodBuilderFactory()
.setLocale(localeName)
.setTimeZone(timeZone)
.getSingleUnitBuilder();
}
return builder;
}

View File

@ -1,6 +1,6 @@
/*
******************************************************************************
* Copyright (C) 2007-2008, International Business Machines Corporation and *
* Copyright (C) 2007-2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
@ -41,7 +41,7 @@ class BasicPeriodBuilderFactory implements PeriodBuilderFactory {
int minLimit;
boolean allowZero = true;
boolean weeksAloneOnly;
boolean useMilliseconds = true;
boolean allowMillis = true;
Settings setUnits(int uset) {
if (this.uset == uset) {
@ -77,12 +77,25 @@ class BasicPeriodBuilderFactory implements PeriodBuilderFactory {
}
short effectiveSet() {
if (useMilliseconds) {
if (allowMillis) {
return uset;
}
return (short)(uset & ~(1 << TimeUnit.MILLISECOND.ordinal));
}
TimeUnit effectiveMinUnit() {
if (allowMillis || minUnit != TimeUnit.MILLISECOND) {
return minUnit;
}
// -1 to skip millisecond
for (int i = TimeUnit.units.length - 1; --i >= 0;) {
if (0 != (uset & (1 << i))) {
return TimeUnit.units[i];
}
}
return TimeUnit.SECOND; // default for pathological case
}
Settings setMaxLimit(float maxLimit) {
int val = maxLimit <= 0 ? 0 : (int)(maxLimit*1000);
if (maxLimit == val) {
@ -121,12 +134,12 @@ class BasicPeriodBuilderFactory implements PeriodBuilderFactory {
return result;
}
Settings setAllowMilliseconds(boolean useMilliseconds) {
if (this.useMilliseconds == useMilliseconds) {
Settings setAllowMilliseconds(boolean allowMillis) {
if (this.allowMillis == allowMillis) {
return this;
}
Settings result = inUse ? copy() : this;
result.useMilliseconds = useMilliseconds;
result.allowMillis = allowMillis;
return result;
}
@ -144,13 +157,21 @@ class BasicPeriodBuilderFactory implements PeriodBuilderFactory {
}
Period createLimited(long duration, boolean inPast) {
long maxUnitDuration = approximateDurationOf(maxUnit);
if (maxLimit > 0 && duration * 1000 > maxLimit * maxUnitDuration) {
return Period.moreThan(maxLimit/1000f, maxUnit).inPast(inPast);
if (maxLimit > 0) {
long maxUnitDuration = approximateDurationOf(maxUnit);
if (duration * 1000 > maxLimit * maxUnitDuration) {
return Period.moreThan(maxLimit/1000f, maxUnit).inPast(inPast);
}
}
long minUnitDuration = approximateDurationOf(minUnit);
if (minLimit > 0 && duration * 1000 < minLimit * minUnitDuration) {
return Period.lessThan(minLimit/1000f, minUnit).inPast(inPast);
if (minLimit > 0) {
TimeUnit emu = effectiveMinUnit();
long emud = approximateDurationOf(emu);
long eml = (emu == minUnit) ? minLimit :
Math.max(1000, (approximateDurationOf(minUnit) * minLimit) / emud);
if (duration * 1000 < eml * emud) {
return Period.lessThan(eml/1000f, emu).inPast(inPast);
}
}
return null;
}
@ -165,7 +186,7 @@ class BasicPeriodBuilderFactory implements PeriodBuilderFactory {
result.minLimit = minLimit;
result.allowZero = allowZero;
result.weeksAloneOnly = weeksAloneOnly;
result.useMilliseconds = useMilliseconds;
result.allowMillis = allowMillis;
return result;
}
}
@ -215,8 +236,8 @@ class BasicPeriodBuilderFactory implements PeriodBuilderFactory {
return this;
}
public PeriodBuilderFactory setAllowMilliseconds(boolean useMilliseconds) {
settings = settings.setAllowMilliseconds(useMilliseconds);
public PeriodBuilderFactory setAllowMilliseconds(boolean allow) {
settings = settings.setAllowMilliseconds(allow);
return this;
}
@ -224,6 +245,11 @@ class BasicPeriodBuilderFactory implements PeriodBuilderFactory {
settings = settings.setLocale(localeName);
return this;
}
public PeriodBuilderFactory setTimeZone(TimeZone timeZone) {
// ignore this
return this;
}
private Settings getSettings() {
if (settings.effectiveSet() == 0) {
@ -298,7 +324,7 @@ abstract class PeriodBuilderImpl implements PeriodBuilder {
if (ts == null) {
ts = handleCreate(duration, referenceDate, inPast);
if (ts == null) {
ts = Period.lessThan(1, settings.minUnit).inPast(inPast);
ts = Period.lessThan(1, settings.effectiveMinUnit()).inPast(inPast);
}
}
return ts;

View File

@ -1,12 +1,14 @@
/*
******************************************************************************
* Copyright (C) 2007-2008, International Business Machines Corporation and *
* Copyright (C) 2007-2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
******************************************************************************
*/
package com.ibm.icu.impl.duration;
import java.util.TimeZone;
/**
*/
public interface PeriodBuilderFactory {
@ -55,12 +57,25 @@ public interface PeriodBuilderFactory {
PeriodBuilderFactory setAllowZero(boolean allow);
/**
* Set whether weeks are used with other units, or only when
* Sets whether weeks are used with other units, or only when
* weeks are the only unit. For example '3 weeks and 2 days'
* versus '23 days'. Default is to use them alone only.
*/
PeriodBuilderFactory setWeeksAloneOnly(boolean aloneOnly);
/**
* Sets whether milliseconds are allowed. This is only examined
* when milliseconds are an available field. The default is to allow
* milliseconds to display normally.
* <p>
* This is intended to be used to set locale-specific behavior. Typically clients will
* not call this API and instead call {@link #setLocale}.
*
* @param allow whether milliseconds should be allowed.
* @return a builder
*/
PeriodBuilderFactory setAllowMilliseconds(boolean allow);
/**
* Sets the locale for the factory. Setting the locale can adjust
* the values for some or all of the other properties to reflect
@ -70,6 +85,13 @@ public interface PeriodBuilderFactory {
PeriodBuilderFactory setLocale(String localeName);
/**
* Sets the time zone for the factory. This can affect the timezone
* used for date computations.
* @param timeZone the timeZone
* @return a builder
*/
PeriodBuilderFactory setTimeZone(TimeZone timeZone);
/**
* Returns a builder that represents durations in terms of the single
* given TimeUnit. If the factory settings don't make the given unit
* available, this will return null.