diff --git a/src/main/java/org/apache/commons/lang3/time/DateUtils.java b/src/main/java/org/apache/commons/lang3/time/DateUtils.java index f8abf1429b7..09e0998c8a4 100644 --- a/src/main/java/org/apache/commons/lang3/time/DateUtils.java +++ b/src/main/java/org/apache/commons/lang3/time/DateUtils.java @@ -1115,6 +1115,8 @@ private static Calendar modify(final Calendar val, final int field, final Modify return val; } + final long originalMillis = val.getTimeInMillis(); + // Fix for LANG-59 START // see https://issues.apache.org/jira/browse/LANG-59 // @@ -1161,7 +1163,7 @@ private static Calendar modify(final Calendar val, final int field, final Modify for (final int element : aField) { if (element == field) { //This is our field... we stop looping - if (modType == ModifyType.CEILING || modType == ModifyType.ROUND && roundUp) { + if (modType == ModifyType.CEILING && originalMillis != val.getTimeInMillis() || modType == ModifyType.ROUND && roundUp) { if (field == SEMI_MONTH) { //This is a special case that's hard to generalize //If the date is 1, we round up to 16, otherwise diff --git a/src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java b/src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java index d4f7b0f5d81..23a85ecbb79 100644 --- a/src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java @@ -230,6 +230,7 @@ private static Stream testToLocalDateTimeTimeZone() { private Date date6; private Date date7; private Date date8; + private Date date9; private Calendar calAmPm1; private Calendar calAmPm2; private Calendar calAmPm3; @@ -283,6 +284,7 @@ public void setUp() throws Exception { dateTimeParser.setTimeZone(TIME_ZONE_DEFAULT); TimeZone.setDefault(TIME_ZONE_DEFAULT); } + date9 = dateTimeParser.parse("March 30, 2003 01:10:00.000"); calAmPm1 = Calendar.getInstance(); calAmPm1.setTime(dateAmPm1); calAmPm2 = Calendar.getInstance(); @@ -530,6 +532,24 @@ void testCeiling() throws Exception { assertEquals(dateTimeParser.parse("November 18, 2001 1:24:00.000"), DateUtils.ceiling(date2, Calendar.MINUTE), "ceiling minute-2 failed"); + // Edge cases (LANG-771) + assertEquals(dateTimeParser.parse("March 30, 2003 01:10:00.000"), + DateUtils.ceiling(date9, Calendar.MINUTE), + "ceiling minute boundary failed"); + final Date epoch = new Date(0); + assertEquals(epoch, + DateUtils.ceiling(epoch, Calendar.MINUTE), + "ceiling minute epoch failed"); + final Date negative = new Date(-1); + assertEquals(new Date(0), + DateUtils.ceiling(negative, Calendar.MINUTE), + "ceiling minute negative failed"); + assertThrows(ArithmeticException.class, + () -> DateUtils.ceiling(new Date(Long.MIN_VALUE), Calendar.MINUTE), + "ceiling minute Long.MIN_VALUE failed"); + assertThrows(ArithmeticException.class, + () -> DateUtils.ceiling(new Date(Long.MAX_VALUE), Calendar.MINUTE), + "ceiling minute Long.MAX_VALUE failed"); assertEquals(dateTimeParser.parse("February 12, 2002 12:34:57.000"), DateUtils.ceiling(date1, Calendar.SECOND), "ceiling second-1 failed");