mirror of
https://github.com/apache/commons-lang.git
synced 2025-02-09 11:34:55 +00:00
removed the weak assumptions for number of millis in a month/year from DateUtils. Implemented a second format method that relies on a start and an end in DurationFormatUtils, though I found that TimeZone was very important in the overloaded millis version. The two methods hand off to each other depending on whether the time is > or < than 28 days
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137935 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
fc447adfef
commit
177d40989f
@ -31,7 +31,7 @@
|
|||||||
* @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
|
* @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
|
||||||
* @author Phil Steitz
|
* @author Phil Steitz
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @version $Id: DateUtils.java,v 1.29 2004/09/26 05:45:33 bayard Exp $
|
* @version $Id: DateUtils.java,v 1.30 2004/09/27 03:14:15 bayard Exp $
|
||||||
*/
|
*/
|
||||||
public class DateUtils {
|
public class DateUtils {
|
||||||
|
|
||||||
@ -56,10 +56,6 @@ public class DateUtils {
|
|||||||
*/
|
*/
|
||||||
public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
|
public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
|
||||||
|
|
||||||
// hmm. not very accurate. used by DurationFormatUtils
|
|
||||||
static final long MILLIS_PER_YEAR = 365 * MILLIS_PER_DAY + 6 * MILLIS_PER_HOUR;
|
|
||||||
static final long MILLIS_PER_MONTH = MILLIS_PER_YEAR / 12;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is half a month, so this represents whether a date is in the top
|
* This is half a month, so this represents whether a date is in the top
|
||||||
* or bottom half of the month.
|
* or bottom half of the month.
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Duration formatting utilities and constants.</p>
|
* <p>Duration formatting utilities and constants.</p>
|
||||||
*
|
*
|
||||||
@ -27,7 +30,7 @@
|
|||||||
* @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
|
* @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a>
|
||||||
* @author Henri Yandell
|
* @author Henri Yandell
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @version $Id: DurationFormatUtils.java,v 1.14 2004/09/26 05:45:33 bayard Exp $
|
* @version $Id: DurationFormatUtils.java,v 1.15 2004/09/27 03:14:15 bayard Exp $
|
||||||
*/
|
*/
|
||||||
public class DurationFormatUtils {
|
public class DurationFormatUtils {
|
||||||
|
|
||||||
@ -101,9 +104,18 @@ public static String format(long millis, String format) {
|
|||||||
return format(millis, format, true);
|
return format(millis, format, true);
|
||||||
}
|
}
|
||||||
public static String format(long millis, String format, boolean padWithZeros) {
|
public static String format(long millis, String format, boolean padWithZeros) {
|
||||||
StringBuffer buffer = new StringBuffer();
|
return format(millis, format, padWithZeros, TimeZone.getDefault());
|
||||||
|
}
|
||||||
|
public static String format(long millis, String format, boolean padWithZeros, TimeZone timezone) {
|
||||||
|
|
||||||
|
if(millis > 28 * DateUtils.MILLIS_PER_DAY) {
|
||||||
|
Calendar c = Calendar.getInstance(timezone);
|
||||||
|
c.set(1970, 0, 1, 0, 0, 0);
|
||||||
|
c.set(Calendar.MILLISECOND, 0);
|
||||||
|
return format(c.getTime().getTime(), millis, format, padWithZeros, timezone);
|
||||||
|
}
|
||||||
|
|
||||||
Token[] tokens = lexx(format);
|
Token[] tokens = lexx(format);
|
||||||
int sz = tokens.length;
|
|
||||||
|
|
||||||
int years = 0;
|
int years = 0;
|
||||||
int months = 0;
|
int months = 0;
|
||||||
@ -113,6 +125,7 @@ public static String format(long millis, String format, boolean padWithZeros) {
|
|||||||
int seconds = 0;
|
int seconds = 0;
|
||||||
int milliseconds = 0;
|
int milliseconds = 0;
|
||||||
|
|
||||||
|
/* This will never be evaluated
|
||||||
if(Token.containsTokenWithValue(tokens, y) ) {
|
if(Token.containsTokenWithValue(tokens, y) ) {
|
||||||
years = (int) (millis / DateUtils.MILLIS_PER_YEAR);
|
years = (int) (millis / DateUtils.MILLIS_PER_YEAR);
|
||||||
millis = millis - (years * DateUtils.MILLIS_PER_YEAR);
|
millis = millis - (years * DateUtils.MILLIS_PER_YEAR);
|
||||||
@ -126,6 +139,7 @@ public static String format(long millis, String format, boolean padWithZeros) {
|
|||||||
months = 0;
|
months = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
if(Token.containsTokenWithValue(tokens, d) ) {
|
if(Token.containsTokenWithValue(tokens, d) ) {
|
||||||
days = (int) (millis / DateUtils.MILLIS_PER_DAY);
|
days = (int) (millis / DateUtils.MILLIS_PER_DAY);
|
||||||
millis = millis - (days * DateUtils.MILLIS_PER_DAY);
|
millis = millis - (days * DateUtils.MILLIS_PER_DAY);
|
||||||
@ -146,7 +160,15 @@ public static String format(long millis, String format, boolean padWithZeros) {
|
|||||||
milliseconds = (int) millis;
|
milliseconds = (int) millis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return formatDuration(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String formatDuration(Token[] tokens, int years, int months, int days, int hours,
|
||||||
|
int minutes, int seconds, int milliseconds, boolean padWithZeros)
|
||||||
|
{
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
int sz = tokens.length;
|
||||||
for(int i=0; i<sz; i++) {
|
for(int i=0; i<sz; i++) {
|
||||||
Token token = tokens[i];
|
Token token = tokens[i];
|
||||||
Object value = token.getValue();
|
Object value = token.getValue();
|
||||||
@ -181,6 +203,87 @@ public static String format(long millis, String format, boolean padWithZeros) {
|
|||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// slower than the above I presume
|
||||||
|
public static String format(long startMillis, long endMillis, String format, boolean padWithZeros) {
|
||||||
|
return format(startMillis, endMillis, format, padWithZeros, TimeZone.getDefault());
|
||||||
|
}
|
||||||
|
public static String format(long startMillis, long endMillis, String format, boolean padWithZeros, TimeZone timezone) {
|
||||||
|
|
||||||
|
long millis = endMillis - startMillis;
|
||||||
|
if(millis < 28 * DateUtils.MILLIS_PER_DAY) {
|
||||||
|
return format(millis, format, padWithZeros, timezone);
|
||||||
|
}
|
||||||
|
|
||||||
|
Token[] tokens = lexx(format);
|
||||||
|
|
||||||
|
// timezones get funky around 0, so normalizing everything to GMT
|
||||||
|
// stops the hours being off
|
||||||
|
Calendar start = Calendar.getInstance(timezone);
|
||||||
|
start.setTimeInMillis(startMillis);
|
||||||
|
Calendar end = Calendar.getInstance(timezone);
|
||||||
|
end.setTimeInMillis(endMillis);
|
||||||
|
|
||||||
|
// initial estimates
|
||||||
|
int years = end.get(Calendar.YEAR) - start.get(Calendar.YEAR);
|
||||||
|
int months = end.get(Calendar.MONTH) - start.get(Calendar.MONTH);
|
||||||
|
// each initial estimate is adjusted in case it is under 0
|
||||||
|
while(months < 0) {
|
||||||
|
months += 12;
|
||||||
|
years -= 1;
|
||||||
|
}
|
||||||
|
int days = end.get(Calendar.DAY_OF_MONTH) - start.get(Calendar.DAY_OF_MONTH);
|
||||||
|
while(days < 0) {
|
||||||
|
days += 31; // such overshooting is taken care of later on
|
||||||
|
days -= 1;
|
||||||
|
}
|
||||||
|
int hours = end.get(Calendar.HOUR_OF_DAY) - start.get(Calendar.HOUR_OF_DAY);
|
||||||
|
while(hours < 0) {
|
||||||
|
hours += 24;
|
||||||
|
days -= 1;
|
||||||
|
}
|
||||||
|
int minutes = end.get(Calendar.MINUTE) - start.get(Calendar.MINUTE);
|
||||||
|
while(minutes < 0) {
|
||||||
|
minutes += 60;
|
||||||
|
hours -= 1;
|
||||||
|
}
|
||||||
|
int seconds = end.get(Calendar.SECOND) - start.get(Calendar.SECOND);
|
||||||
|
while(seconds < 0) {
|
||||||
|
seconds += 60;
|
||||||
|
minutes -= 1;
|
||||||
|
}
|
||||||
|
int milliseconds = end.get(Calendar.MILLISECOND) - start.get(Calendar.MILLISECOND);
|
||||||
|
while(milliseconds < 0) {
|
||||||
|
milliseconds += 1000;
|
||||||
|
seconds -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// take estimates off of end to see if we can equal start, when it overshoots recalculate
|
||||||
|
milliseconds -= reduceAndCorrect( start, end, Calendar.MILLISECOND, milliseconds );
|
||||||
|
seconds -= reduceAndCorrect( start, end, Calendar.SECOND, seconds );
|
||||||
|
minutes -= reduceAndCorrect( start, end, Calendar.MINUTE, minutes );
|
||||||
|
hours -= reduceAndCorrect( start, end, Calendar.HOUR_OF_DAY, hours );
|
||||||
|
days -= reduceAndCorrect( start, end, Calendar.DAY_OF_MONTH, days );
|
||||||
|
months -= reduceAndCorrect( start, end, Calendar.MONTH, months );
|
||||||
|
years -= reduceAndCorrect( start, end, Calendar.YEAR, years );
|
||||||
|
|
||||||
|
return formatDuration(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduces by difference, then if it overshot, calculates the overshot amount and
|
||||||
|
// fixes and returns the amount to change by
|
||||||
|
private static int reduceAndCorrect(Calendar start, Calendar end, int field, int difference) {
|
||||||
|
end.add( field, -1 * difference );
|
||||||
|
int endValue = end.get(field);
|
||||||
|
int startValue = start.get(field);
|
||||||
|
if(endValue < startValue) {
|
||||||
|
int newdiff = startValue - endValue;
|
||||||
|
end.add( field, newdiff );
|
||||||
|
return newdiff;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Format an elapsed time into a plurialization correct string.</p>
|
* <p>Format an elapsed time into a plurialization correct string.</p>
|
||||||
*
|
*
|
||||||
|
@ -157,16 +157,13 @@ public void testISODurationFormat(){
|
|||||||
text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(cal);
|
text = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(cal);
|
||||||
assertEquals("2002-02-23T09:11:12-03:00", text);
|
assertEquals("2002-02-23T09:11:12-03:00", text);
|
||||||
// test fixture is the same as above, but now with extended format.
|
// test fixture is the same as above, but now with extended format.
|
||||||
text = DurationFormatUtils.format(cal.getTime().getTime(), DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false);
|
text = DurationFormatUtils.format(cal.getTime().getTime(), DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
|
||||||
// TODO: The 1H41M here should be 9H11M. Again the year/month assumption.
|
assertEquals("P32Y1M22DT9H11M12.1S", text);
|
||||||
System.err.println("T: "+text);
|
|
||||||
assertEquals("P32Y1M23DT1H41M12.1S", text);
|
|
||||||
// test fixture from example in http://www.w3.org/TR/xmlschema-2/#duration
|
// test fixture from example in http://www.w3.org/TR/xmlschema-2/#duration
|
||||||
cal.set(1971, 1, 3, 10, 30, 0);
|
cal.set(1971, 1, 3, 10, 30, 0);
|
||||||
cal.set(Calendar.MILLISECOND, 0);
|
cal.set(Calendar.MILLISECOND, 0);
|
||||||
text = DurationFormatUtils.format(cal.getTime().getTime(), DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false);
|
text = DurationFormatUtils.format(cal.getTime().getTime(), DurationFormatUtils.ISO_EXTENDED_FORMAT_PATTERN, false, timeZone);
|
||||||
// TODO: The 2D21H here is wrong and should be larger. The Year/Month assumption in DurationFormatUtils.
|
assertEquals("P1Y1M2DT10H30M0.0S", text);
|
||||||
assertEquals("P1Y1M2DT21H0M0.0S", text);
|
|
||||||
// want a way to say 'don't print the seconds in format()' or other fields for that matter:
|
// want a way to say 'don't print the seconds in format()' or other fields for that matter:
|
||||||
//assertEquals("P1Y2M3DT10H30M", text);
|
//assertEquals("P1Y2M3DT10H30M", text);
|
||||||
}
|
}
|
||||||
@ -194,6 +191,7 @@ public void testFormat() {
|
|||||||
assertEquals( "60000", DurationFormatUtils.format(time, "S") );
|
assertEquals( "60000", DurationFormatUtils.format(time, "S") );
|
||||||
assertEquals( "01:00", DurationFormatUtils.format(time, "mm:ss") );
|
assertEquals( "01:00", DurationFormatUtils.format(time, "mm:ss") );
|
||||||
|
|
||||||
|
/*
|
||||||
time = 3 * DateUtils.MILLIS_PER_YEAR + 7 * DateUtils.MILLIS_PER_MONTH;
|
time = 3 * DateUtils.MILLIS_PER_YEAR + 7 * DateUtils.MILLIS_PER_MONTH;
|
||||||
assertEquals( "37", DurationFormatUtils.format(time, "yM") );
|
assertEquals( "37", DurationFormatUtils.format(time, "yM") );
|
||||||
assertEquals( "3 years 7 months", DurationFormatUtils.format(time, "y' years 'M' months'") );
|
assertEquals( "3 years 7 months", DurationFormatUtils.format(time, "y' years 'M' months'") );
|
||||||
@ -211,6 +209,7 @@ public void testFormat() {
|
|||||||
assertEquals( "48", DurationFormatUtils.format(time, "M") );
|
assertEquals( "48", DurationFormatUtils.format(time, "M") );
|
||||||
assertEquals( "48", DurationFormatUtils.format(time, "MM") );
|
assertEquals( "48", DurationFormatUtils.format(time, "MM") );
|
||||||
assertEquals( "048", DurationFormatUtils.format(time, "MMM") );
|
assertEquals( "048", DurationFormatUtils.format(time, "MMM") );
|
||||||
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user