LANG-984 DurationFormatUtils does not handle large durations correctly
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1573749 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ddc06197e4
commit
cf4138d7bc
|
@ -21,6 +21,10 @@
|
||||||
</properties>
|
</properties>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
<release version="3.4" date="TBA" description="TBA">
|
||||||
|
<action issue="LANG-984" type="fix" dev="sebb">DurationFormatUtils does not handle large durations correctly</action>
|
||||||
|
</release>
|
||||||
|
|
||||||
<release version="3.3" date="TBA" description="Bug fixes and and new features including: DifferenceBuilder, ClassPathUtils, RandomUtils and Jaro-Winkler String distance metric">
|
<release version="3.3" date="TBA" description="Bug fixes and and new features including: DifferenceBuilder, ClassPathUtils, RandomUtils and Jaro-Winkler String distance metric">
|
||||||
<action issue="LANG-621" type="fix" dev="kinow" due-to="Philip Hodges, Thomas Neidhart">ReflectionToStringBuilder.toString does not debug 3rd party object fields within 3rd party object</action>
|
<action issue="LANG-621" type="fix" dev="kinow" due-to="Philip Hodges, Thomas Neidhart">ReflectionToStringBuilder.toString does not debug 3rd party object fields within 3rd party object</action>
|
||||||
<action issue="LANG-955" type="add" dev="britter" due-to="Adam Hooper">Add methods for removing all invalid characters according to XML 1.0 and XML 1.1 in an input string to StringEscapeUtils</action>
|
<action issue="LANG-955" type="add" dev="britter" due-to="Adam Hooper">Add methods for removing all invalid characters according to XML 1.0 and XML 1.1 in an input string to StringEscapeUtils</action>
|
||||||
|
|
|
@ -123,30 +123,30 @@ public class DurationFormatUtils {
|
||||||
|
|
||||||
final Token[] tokens = lexx(format);
|
final Token[] tokens = lexx(format);
|
||||||
|
|
||||||
int days = 0;
|
long days = 0;
|
||||||
int hours = 0;
|
long hours = 0;
|
||||||
int minutes = 0;
|
long minutes = 0;
|
||||||
int seconds = 0;
|
long seconds = 0;
|
||||||
int milliseconds = 0;
|
long milliseconds = 0;
|
||||||
|
|
||||||
if (Token.containsTokenWithValue(tokens, d) ) {
|
if (Token.containsTokenWithValue(tokens, d) ) {
|
||||||
days = (int) (durationMillis / DateUtils.MILLIS_PER_DAY);
|
days = durationMillis / DateUtils.MILLIS_PER_DAY;
|
||||||
durationMillis = durationMillis - (days * DateUtils.MILLIS_PER_DAY);
|
durationMillis = durationMillis - (days * DateUtils.MILLIS_PER_DAY);
|
||||||
}
|
}
|
||||||
if (Token.containsTokenWithValue(tokens, H) ) {
|
if (Token.containsTokenWithValue(tokens, H) ) {
|
||||||
hours = (int) (durationMillis / DateUtils.MILLIS_PER_HOUR);
|
hours = durationMillis / DateUtils.MILLIS_PER_HOUR;
|
||||||
durationMillis = durationMillis - (hours * DateUtils.MILLIS_PER_HOUR);
|
durationMillis = durationMillis - (hours * DateUtils.MILLIS_PER_HOUR);
|
||||||
}
|
}
|
||||||
if (Token.containsTokenWithValue(tokens, m) ) {
|
if (Token.containsTokenWithValue(tokens, m) ) {
|
||||||
minutes = (int) (durationMillis / DateUtils.MILLIS_PER_MINUTE);
|
minutes = durationMillis / DateUtils.MILLIS_PER_MINUTE;
|
||||||
durationMillis = durationMillis - (minutes * DateUtils.MILLIS_PER_MINUTE);
|
durationMillis = durationMillis - (minutes * DateUtils.MILLIS_PER_MINUTE);
|
||||||
}
|
}
|
||||||
if (Token.containsTokenWithValue(tokens, s) ) {
|
if (Token.containsTokenWithValue(tokens, s) ) {
|
||||||
seconds = (int) (durationMillis / DateUtils.MILLIS_PER_SECOND);
|
seconds = durationMillis / DateUtils.MILLIS_PER_SECOND;
|
||||||
durationMillis = durationMillis - (seconds * DateUtils.MILLIS_PER_SECOND);
|
durationMillis = durationMillis - (seconds * DateUtils.MILLIS_PER_SECOND);
|
||||||
}
|
}
|
||||||
if (Token.containsTokenWithValue(tokens, S) ) {
|
if (Token.containsTokenWithValue(tokens, S) ) {
|
||||||
milliseconds = (int) durationMillis;
|
milliseconds = durationMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros);
|
return format(tokens, 0, 0, days, hours, minutes, seconds, milliseconds, padWithZeros);
|
||||||
|
@ -411,8 +411,8 @@ public class DurationFormatUtils {
|
||||||
* @param padWithZeros whether to pad
|
* @param padWithZeros whether to pad
|
||||||
* @return the formatted string
|
* @return the formatted string
|
||||||
*/
|
*/
|
||||||
static String format(final Token[] tokens, final int years, final int months, final int days, final int hours, final int minutes, final int seconds,
|
static String format(final Token[] tokens, final long years, final long months, final long days, final long hours, final long minutes, final long seconds,
|
||||||
int milliseconds, final boolean padWithZeros) {
|
long milliseconds, final boolean padWithZeros) {
|
||||||
final StringBuilder buffer = new StringBuilder();
|
final StringBuilder buffer = new StringBuilder();
|
||||||
boolean lastOutputSeconds = false;
|
boolean lastOutputSeconds = false;
|
||||||
final int sz = tokens.length;
|
final int sz = tokens.length;
|
||||||
|
@ -424,40 +424,32 @@ public class DurationFormatUtils {
|
||||||
buffer.append(value.toString());
|
buffer.append(value.toString());
|
||||||
} else {
|
} else {
|
||||||
if (value == y) {
|
if (value == y) {
|
||||||
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(years), count, '0') : Integer
|
buffer.append(paddedValue(years, padWithZeros, count));
|
||||||
.toString(years));
|
|
||||||
lastOutputSeconds = false;
|
lastOutputSeconds = false;
|
||||||
} else if (value == M) {
|
} else if (value == M) {
|
||||||
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(months), count, '0') : Integer
|
buffer.append(paddedValue(months, padWithZeros, count));
|
||||||
.toString(months));
|
|
||||||
lastOutputSeconds = false;
|
lastOutputSeconds = false;
|
||||||
} else if (value == d) {
|
} else if (value == d) {
|
||||||
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(days), count, '0') : Integer
|
buffer.append(paddedValue(days, padWithZeros, count));
|
||||||
.toString(days));
|
|
||||||
lastOutputSeconds = false;
|
lastOutputSeconds = false;
|
||||||
} else if (value == H) {
|
} else if (value == H) {
|
||||||
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(hours), count, '0') : Integer
|
buffer.append(paddedValue(hours, padWithZeros, count));
|
||||||
.toString(hours));
|
|
||||||
lastOutputSeconds = false;
|
lastOutputSeconds = false;
|
||||||
} else if (value == m) {
|
} else if (value == m) {
|
||||||
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(minutes), count, '0') : Integer
|
buffer.append(paddedValue(minutes, padWithZeros, count));
|
||||||
.toString(minutes));
|
|
||||||
lastOutputSeconds = false;
|
lastOutputSeconds = false;
|
||||||
} else if (value == s) {
|
} else if (value == s) {
|
||||||
buffer.append(padWithZeros ? StringUtils.leftPad(Integer.toString(seconds), count, '0') : Integer
|
buffer.append(paddedValue(seconds, padWithZeros, count));
|
||||||
.toString(seconds));
|
|
||||||
lastOutputSeconds = true;
|
lastOutputSeconds = true;
|
||||||
} else if (value == S) {
|
} else if (value == S) {
|
||||||
if (lastOutputSeconds) {
|
if (lastOutputSeconds) {
|
||||||
milliseconds += 1000;
|
milliseconds += 1000;
|
||||||
final String str = padWithZeros
|
final String str = padWithZeros
|
||||||
? StringUtils.leftPad(Integer.toString(milliseconds), count, '0')
|
? StringUtils.leftPad(Long.toString(milliseconds), count, '0')
|
||||||
: Integer.toString(milliseconds);
|
: Long.toString(milliseconds);
|
||||||
buffer.append(str.substring(1));
|
buffer.append(str.substring(1));
|
||||||
} else {
|
} else {
|
||||||
buffer.append(padWithZeros
|
buffer.append(paddedValue(milliseconds, padWithZeros, count));
|
||||||
? StringUtils.leftPad(Integer.toString(milliseconds), count, '0')
|
|
||||||
: Integer.toString(milliseconds));
|
|
||||||
}
|
}
|
||||||
lastOutputSeconds = false;
|
lastOutputSeconds = false;
|
||||||
}
|
}
|
||||||
|
@ -466,6 +458,12 @@ public class DurationFormatUtils {
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper method to simplify repetive code in format method above
|
||||||
|
private static String paddedValue(final long value, final boolean padWithZeros, final int count) {
|
||||||
|
final String longString = Long.toString(value);
|
||||||
|
return padWithZeros ? StringUtils.leftPad(longString, count, '0') : longString;
|
||||||
|
}
|
||||||
|
|
||||||
static final Object y = "y";
|
static final Object y = "y";
|
||||||
static final Object M = "M";
|
static final Object M = "M";
|
||||||
static final Object d = "d";
|
static final Object d = "d";
|
||||||
|
|
|
@ -519,7 +519,17 @@ public class DurationFormatUtilsTest {
|
||||||
new int[] { 1997, 1, 28, 0, 0, 0 }, "M d");
|
new int[] { 1997, 1, 28, 0, 0, 0 }, "M d");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLANG984() { // Long durations
|
||||||
|
assertEquals("0", DurationFormatUtils.formatDuration(0, "S"));
|
||||||
|
assertEquals(Integer.toString(Integer.MAX_VALUE), DurationFormatUtils.formatDuration(Integer.MAX_VALUE, "S"));
|
||||||
|
long maxIntPlus=Integer.MAX_VALUE;
|
||||||
|
maxIntPlus++;
|
||||||
|
assertEquals(Long.toString(maxIntPlus), DurationFormatUtils.formatDuration(maxIntPlus, "S"));
|
||||||
|
assertEquals(Long.toString(Long.MAX_VALUE), DurationFormatUtils.formatDuration(Long.MAX_VALUE, "S"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDurationsByBruteForce() {
|
public void testDurationsByBruteForce() {
|
||||||
bruteForce(2006, 0, 1, "d", Calendar.DAY_OF_MONTH);
|
bruteForce(2006, 0, 1, "d", Calendar.DAY_OF_MONTH);
|
||||||
|
|
Loading…
Reference in New Issue