Skip to content

Commit a9a0dd8

Browse files
LANG-771 Fix DateUtils.ceiling increment on exact boundary (#1609)
* LANG-771 Fix DateUtils.ceiling increment on exact boundary * Fix Checkstyle violations for LANG-771 * LANG-771 Add edge case tests for DateUtils.ceiling() Add tests for: - Epoch (0) - Negative date (-1) - Long.MIN_VALUE and Long.MAX_VALUE handling - Minute boundary case
1 parent b56c688 commit a9a0dd8

2 files changed

Lines changed: 23 additions & 1 deletion

File tree

src/main/java/org/apache/commons/lang3/time/DateUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,8 @@ private static Calendar modify(final Calendar val, final int field, final Modify
11151115
return val;
11161116
}
11171117

1118+
final long originalMillis = val.getTimeInMillis();
1119+
11181120
// Fix for LANG-59 START
11191121
// see https://issues.apache.org/jira/browse/LANG-59
11201122
//
@@ -1161,7 +1163,7 @@ private static Calendar modify(final Calendar val, final int field, final Modify
11611163
for (final int element : aField) {
11621164
if (element == field) {
11631165
//This is our field... we stop looping
1164-
if (modType == ModifyType.CEILING || modType == ModifyType.ROUND && roundUp) {
1166+
if (modType == ModifyType.CEILING && originalMillis != val.getTimeInMillis() || modType == ModifyType.ROUND && roundUp) {
11651167
if (field == SEMI_MONTH) {
11661168
//This is a special case that's hard to generalize
11671169
//If the date is 1, we round up to 16, otherwise

src/test/java/org/apache/commons/lang3/time/DateUtilsTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ private static Stream<Arguments> testToLocalDateTimeTimeZone() {
231231
private Date date6;
232232
private Date date7;
233233
private Date date8;
234+
private Date date9;
234235
private Calendar calAmPm1;
235236
private Calendar calAmPm2;
236237
private Calendar calAmPm3;
@@ -284,6 +285,7 @@ public void setUp() throws Exception {
284285
dateTimeParser.setTimeZone(TIME_ZONE_DEFAULT);
285286
TimeZone.setDefault(TIME_ZONE_DEFAULT);
286287
}
288+
date9 = dateTimeParser.parse("March 30, 2003 01:10:00.000");
287289
calAmPm1 = Calendar.getInstance();
288290
calAmPm1.setTime(dateAmPm1);
289291
calAmPm2 = Calendar.getInstance();
@@ -531,6 +533,24 @@ void testCeiling() throws Exception {
531533
assertEquals(dateTimeParser.parse("November 18, 2001 1:24:00.000"),
532534
DateUtils.ceiling(date2, Calendar.MINUTE),
533535
"ceiling minute-2 failed");
536+
// Edge cases (LANG-771)
537+
assertEquals(dateTimeParser.parse("March 30, 2003 01:10:00.000"),
538+
DateUtils.ceiling(date9, Calendar.MINUTE),
539+
"ceiling minute boundary failed");
540+
final Date epoch = new Date(0);
541+
assertEquals(epoch,
542+
DateUtils.ceiling(epoch, Calendar.MINUTE),
543+
"ceiling minute epoch failed");
544+
final Date negative = new Date(-1);
545+
assertEquals(new Date(0),
546+
DateUtils.ceiling(negative, Calendar.MINUTE),
547+
"ceiling minute negative failed");
548+
assertThrows(ArithmeticException.class,
549+
() -> DateUtils.ceiling(new Date(Long.MIN_VALUE), Calendar.MINUTE),
550+
"ceiling minute Long.MIN_VALUE failed");
551+
assertThrows(ArithmeticException.class,
552+
() -> DateUtils.ceiling(new Date(Long.MAX_VALUE), Calendar.MINUTE),
553+
"ceiling minute Long.MAX_VALUE failed");
534554
assertEquals(dateTimeParser.parse("February 12, 2002 12:34:57.000"),
535555
DateUtils.ceiling(date1, Calendar.SECOND),
536556
"ceiling second-1 failed");

0 commit comments

Comments
 (0)