From 76011f6940144385b792039fdb9036711608cc7f Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Fri, 2 Oct 2020 15:21:34 +0200 Subject: [PATCH] [Fix] Properly handle month periods in PeriodHelper --- .../li/strolch/utils/time/PeriodHelper.java | 24 +++++++++++++++++++ .../strolch/utils/time/PeriodHelperTest.java | 23 ++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/time/PeriodHelper.java b/li.strolch.utils/src/main/java/li/strolch/utils/time/PeriodHelper.java index f58b9c5bf..e1e0446a2 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/time/PeriodHelper.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/time/PeriodHelper.java @@ -9,6 +9,13 @@ import li.strolch.utils.dbc.DBC; public class PeriodHelper { + public static double monthsIn(PeriodDuration periodDuration) { + long hours = periodDuration.getDuration().toHours(); + Period period = periodDuration.getPeriod(); + long months = period.toTotalMonths(); + return (months + (period.getDays() / 30.0) + (hours / 24.0 / 30.0)); + } + public static double daysIn(PeriodDuration periodDuration) { return (daysIn(periodDuration.getPeriod()) + (periodDuration.getDuration().toHours() / 24.0)); } @@ -17,6 +24,10 @@ public class PeriodHelper { return (period.getYears() * 365.0) + (period.getMonths() * 30.0) + period.getDays(); } + private static double monthsIn(Period period) { + return (period.getYears() * 12.0) + (period.getMonths()); + } + /** * This special function allows us to shift a date by a multiple of the given {@link PeriodDuration} so that is * before the given to date. It does multiple tries to get as close as possible, due to the inexactness of 30 days @@ -35,7 +46,20 @@ public class PeriodHelper { PeriodDuration periodDuration) { DBC.PRE.assertTrue("date must be before to!", date.isBefore(to)); DBC.PRE.assertFalse("period duration may not be null!", periodDuration.isZero()); + + // see if we need to shift by months + long monthsInPeriod = (long) monthsIn(periodDuration); + if (monthsInPeriod > 0) { + Period between = between(date.toLocalDate(), to.toLocalDate()); + double monthsInBetween = monthsIn(between); + long shifts = (long) (monthsInBetween / monthsInPeriod); + if (shifts > 0) { + date = date.plusMonths(shifts); + } + } + Period between = between(date.toLocalDate(), to.toLocalDate()); + double daysInBetween = daysIn(between); double daysInPeriod = daysIn(periodDuration); long shifts = (long) (daysInBetween / daysInPeriod); diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/time/PeriodHelperTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/time/PeriodHelperTest.java index 55c5676a1..7acfa4946 100644 --- a/li.strolch.utils/src/test/java/li/strolch/utils/time/PeriodHelperTest.java +++ b/li.strolch.utils/src/test/java/li/strolch/utils/time/PeriodHelperTest.java @@ -7,7 +7,6 @@ import static org.junit.Assert.assertTrue; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.time.temporal.ChronoUnit; import org.junit.Test; @@ -68,6 +67,26 @@ public class PeriodHelperTest { assertEquals(30, daysIn(PeriodDuration.parse("P1M")), 0.0); } + @Test + public void shouldCalcMonths1() { + assertEquals(1, monthsIn(PeriodDuration.parse("P1M")), 0.0); + } + + @Test + public void shouldCalcMonths2() { + assertEquals(1, monthsIn(PeriodDuration.parse("P30D")), 0.0); + } + + @Test + public void shouldCalcMonths3() { + assertEquals(2, monthsIn(PeriodDuration.parse("P60D")), 0.0); + } + + @Test + public void shouldCalcMonths4() { + assertEquals(12, monthsIn(PeriodDuration.parse("P1Y")), 0.0); + } + @Test public void shouldCalcShiftDays1() { ZonedDateTime past = ZonedDateTime.now().minusDays(35); @@ -83,7 +102,7 @@ public class PeriodHelperTest { public void shouldCalcShiftDays2() { ZonedDateTime past = ZonedDateTime .parse("2007-12-03T10:15:30+01:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(systemDefault())); - ZonedDateTime now = ZonedDateTime.now().truncatedTo(ChronoUnit.DAYS); + ZonedDateTime now = ZonedDateTime.now(); PeriodDuration periodDuration = PeriodDuration.parse("P1M"); ZonedDateTime shiftedDate = shiftByMultipleOfPeriod(past, now, periodDuration);