[Fix] Properly handle month periods in PeriodHelper

This commit is contained in:
Robert von Burg 2020-10-02 15:21:34 +02:00
parent 4f52c1852f
commit 76011f6940
2 changed files with 45 additions and 2 deletions

View File

@ -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);

View File

@ -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);