Adding Niall's fix for LANG-59 - an edge case in date truncation - and his enhancement
for the unit test that was there. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@424192 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c62bd30765
commit
9cbf70d822
|
@ -621,6 +621,51 @@ public class DateUtils {
|
||||||
throw new ArithmeticException("Calendar value too large for accurate calculations");
|
throw new ArithmeticException("Calendar value too large for accurate calculations");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field == Calendar.MILLISECOND) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------- Fix for LANG-59 ---------------------- START ---------------
|
||||||
|
// see http://issues.apache.org/jira/browse/LANG-59
|
||||||
|
//
|
||||||
|
// Manually truncate milliseconds, seconds and minutes, rather than using
|
||||||
|
// Calendar methods.
|
||||||
|
|
||||||
|
Date date = val.getTime();
|
||||||
|
long time = date.getTime();
|
||||||
|
boolean done = false;
|
||||||
|
|
||||||
|
// truncate milliseconds
|
||||||
|
int millisecs = val.get(Calendar.MILLISECOND);
|
||||||
|
if (!round || millisecs < 500) {
|
||||||
|
time = time - millisecs;
|
||||||
|
if (field == Calendar.SECOND) {
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate seconds
|
||||||
|
int seconds = val.get(Calendar.SECOND);
|
||||||
|
if (!done && (!round || seconds < 30)) {
|
||||||
|
time = time - (seconds * 1000L);
|
||||||
|
if (field == Calendar.MINUTE) {
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// truncate minutes
|
||||||
|
int minutes = val.get(Calendar.MINUTE);
|
||||||
|
if (!done && (!round || minutes < 30)) {
|
||||||
|
time = time - (minutes * 60000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset time
|
||||||
|
if (date.getTime() != time) {
|
||||||
|
date.setTime(time);
|
||||||
|
val.setTime(date);
|
||||||
|
}
|
||||||
|
// ----------------- Fix for LANG-59 ----------------------- END ----------------
|
||||||
|
|
||||||
boolean roundUp = false;
|
boolean roundUp = false;
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
for (int j = 0; j < fields[i].length; j++) {
|
for (int j = 0; j < fields[i].length; j++) {
|
||||||
|
@ -689,7 +734,9 @@ public class DateUtils {
|
||||||
roundUp = offset > ((max - min) / 2);
|
roundUp = offset > ((max - min) / 2);
|
||||||
}
|
}
|
||||||
//We need to remove this field
|
//We need to remove this field
|
||||||
val.set(fields[i][0], val.get(fields[i][0]) - offset);
|
if (offset != 0) {
|
||||||
|
val.set(fields[i][0], val.get(fields[i][0]) - offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException("The field " + field + " is not supported");
|
throw new IllegalArgumentException("The field " + field + " is not supported");
|
||||||
|
|
||||||
|
|
|
@ -882,6 +882,81 @@ public class DateUtilsTest extends TestCase {
|
||||||
assertEquals(0, cal.get(Calendar.HOUR));
|
assertEquals(0, cal.get(Calendar.HOUR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for LANG-59
|
||||||
|
*
|
||||||
|
* see http://issues.apache.org/jira/browse/LANG-59
|
||||||
|
*/
|
||||||
|
public void testTruncateLang59() throws Exception {
|
||||||
|
|
||||||
|
// Set TimeZone to Mountain Time
|
||||||
|
TimeZone MST_MDT = TimeZone.getTimeZone("MST7MDT");
|
||||||
|
TimeZone.setDefault(MST_MDT);
|
||||||
|
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS z");
|
||||||
|
format.setTimeZone(MST_MDT);
|
||||||
|
|
||||||
|
Date oct31_01MDT = new Date(1099206000000L);
|
||||||
|
|
||||||
|
Date oct31MDT = new Date(oct31_01MDT.getTime() - 3600000L); // - 1 hour
|
||||||
|
Date oct31_01_02MDT = new Date(oct31_01MDT.getTime() + 120000L); // + 2 minutes
|
||||||
|
Date oct31_01_02_03MDT = new Date(oct31_01_02MDT.getTime() + 3000L); // + 3 seconds
|
||||||
|
Date oct31_01_02_03_04MDT = new Date(oct31_01_02_03MDT.getTime() + 4L); // + 4 milliseconds
|
||||||
|
|
||||||
|
assertEquals("Check 00:00:00.000", "2004-10-31 00:00:00.000 MDT", format.format(oct31MDT));
|
||||||
|
assertEquals("Check 01:00:00.000", "2004-10-31 01:00:00.000 MDT", format.format(oct31_01MDT));
|
||||||
|
assertEquals("Check 01:02:00.000", "2004-10-31 01:02:00.000 MDT", format.format(oct31_01_02MDT));
|
||||||
|
assertEquals("Check 01:02:03.000", "2004-10-31 01:02:03.000 MDT", format.format(oct31_01_02_03MDT));
|
||||||
|
assertEquals("Check 01:02:03.004", "2004-10-31 01:02:03.004 MDT", format.format(oct31_01_02_03_04MDT));
|
||||||
|
|
||||||
|
// ------- Demonstrate Problem -------
|
||||||
|
Calendar gval = Calendar.getInstance();
|
||||||
|
gval.setTime(new Date(oct31_01MDT.getTime()));
|
||||||
|
gval.set(Calendar.MINUTE, gval.get(Calendar.MINUTE)); // set minutes to the same value
|
||||||
|
assertEquals("Demonstrate Problem", gval.getTime().getTime(), oct31_01MDT.getTime() + 3600000L);
|
||||||
|
|
||||||
|
// ---------- Test Truncate ----------
|
||||||
|
assertEquals("Truncate Calendar.MILLISECOND",
|
||||||
|
oct31_01_02_03_04MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.MILLISECOND));
|
||||||
|
|
||||||
|
assertEquals("Truncate Calendar.SECOND",
|
||||||
|
oct31_01_02_03MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.SECOND));
|
||||||
|
|
||||||
|
assertEquals("Truncate Calendar.MINUTE",
|
||||||
|
oct31_01_02MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.MINUTE));
|
||||||
|
|
||||||
|
assertEquals("Truncate Calendar.HOUR_OF_DAY",
|
||||||
|
oct31_01MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.HOUR_OF_DAY));
|
||||||
|
|
||||||
|
assertEquals("Truncate Calendar.HOUR",
|
||||||
|
oct31_01MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.HOUR));
|
||||||
|
|
||||||
|
assertEquals("Truncate Calendar.DATE",
|
||||||
|
oct31MDT, DateUtils.truncate(oct31_01_02_03_04MDT, Calendar.DATE));
|
||||||
|
|
||||||
|
|
||||||
|
// ---------- Test Round (down) ----------
|
||||||
|
assertEquals("Round Calendar.MILLISECOND",
|
||||||
|
oct31_01_02_03_04MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.MILLISECOND));
|
||||||
|
|
||||||
|
assertEquals("Round Calendar.SECOND",
|
||||||
|
oct31_01_02_03MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.SECOND));
|
||||||
|
|
||||||
|
assertEquals("Round Calendar.MINUTE",
|
||||||
|
oct31_01_02MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.MINUTE));
|
||||||
|
|
||||||
|
assertEquals("Round Calendar.HOUR_OF_DAY",
|
||||||
|
oct31_01MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.HOUR_OF_DAY));
|
||||||
|
|
||||||
|
assertEquals("Round Calendar.HOUR",
|
||||||
|
oct31_01MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.HOUR));
|
||||||
|
|
||||||
|
assertEquals("Round Calendar.DATE",
|
||||||
|
oct31MDT, DateUtils.round(oct31_01_02_03_04MDT, Calendar.DATE));
|
||||||
|
|
||||||
|
// restore default time zone
|
||||||
|
TimeZone.setDefault(defaultZone);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the iterator exceptions
|
* Tests the iterator exceptions
|
||||||
*/
|
*/
|
||||||
|
@ -978,14 +1053,6 @@ public class DateUtilsTest extends TestCase {
|
||||||
dateParser.parse("December 2, 2001"));
|
dateParser.parse("December 2, 2001"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests LANG-59
|
|
||||||
public void testLang59() throws Exception {
|
|
||||||
// truncate 2004-10-31 01:00:00 MDT
|
|
||||||
Date oct31_01MDT = new Date(1099206000000L);
|
|
||||||
Date result = DateUtils.truncate(oct31_01MDT, Calendar.HOUR_OF_DAY);
|
|
||||||
assertEquals(oct31_01MDT, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This checks that this is a 7 element iterator of Calendar objects
|
* This checks that this is a 7 element iterator of Calendar objects
|
||||||
* that are dates (no time), and exactly 1 day spaced after each other.
|
* that are dates (no time), and exactly 1 day spaced after each other.
|
||||||
|
|
Loading…
Reference in New Issue