[New] Added PeriodDuration.toMillis() with tests, etc.

This commit is contained in:
Robert von Burg 2019-09-09 14:35:17 +02:00
parent 704dc2b702
commit bd0ea5cd27
3 changed files with 810 additions and 566 deletions

View File

@ -0,0 +1,56 @@
package li.strolch.utils.time;
import static java.time.Period.between;
import java.time.Period;
import java.time.ZonedDateTime;
import li.strolch.utils.dbc.DBC;
public class PeriodHelper {
public static double daysIn(PeriodDuration periodDuration) {
return (daysIn(periodDuration.getPeriod()) + (periodDuration.getDuration().toHours() / 24.0));
}
public static double daysIn(Period period) {
return (period.getYears() * 365.0) + (period.getMonths() * 30.0) + period.getDays();
}
/**
* 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
* being one month, and 365 days being one year.
*
* @param date
* the date to shift
* @param to
* the date before which to stop shifting
* @param periodDuration
* the period shift in multiples by
*
* @return the shifted date
*/
public static ZonedDateTime shiftByMultipleOfPeriod(ZonedDateTime date, ZonedDateTime to,
PeriodDuration periodDuration) {
DBC.PRE.assertTrue("date must be before to!", date.isBefore(to));
DBC.PRE.assertFalse("period duration may not be null!", periodDuration.isZero());
Period between = between(date.toLocalDate(), to.toLocalDate());
double daysInBetween = daysIn(between);
double daysInPeriod = daysIn(periodDuration);
long shifts = (long) (daysInBetween / daysInPeriod);
if (shifts < 0)
return date;
ZonedDateTime shiftedDate = date.plusDays((long) (shifts * daysInPeriod));
// see if we are close enough now
between = between(shiftedDate.toLocalDate(), to.toLocalDate());
daysInBetween = daysIn(between);
shifts = (long) (daysInBetween / daysInPeriod);
if (shifts < 2)
return shiftedDate;
return shiftByMultipleOfPeriod(shiftedDate, to, periodDuration);
}
}

View File

@ -0,0 +1,116 @@
package li.strolch.utils.time;
import static java.time.ZoneId.systemDefault;
import static li.strolch.utils.time.PeriodHelper.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import org.junit.Test;
public class PeriodHelperTest {
@Test
public void shouldCalcHalfADay() {
assertEquals(0.5, daysIn(PeriodDuration.parse("PT12H")), 0.0);
}
@Test
public void shouldCalc1Day1() {
assertEquals(1.0, daysIn(PeriodDuration.parse("P1D")), 0.0);
}
@Test
public void shouldCalc1Day2() {
assertEquals(1.0, daysIn(PeriodDuration.parse("PT24H")), 0.0);
}
@Test
public void shouldCalc1AndAHalfDays() {
assertEquals(1.5, daysIn(PeriodDuration.parse("PT36H")), 0.0);
}
@Test
public void shouldCalc2Days1() {
assertEquals(2.0, daysIn(PeriodDuration.parse("P2D")), 0.0);
}
@Test
public void shouldCalc2Days2() {
assertEquals(2.0, daysIn(PeriodDuration.parse("PT48H")), 0.0);
}
@Test
public void shouldCalc2Days3() {
assertEquals(2.0, daysIn(PeriodDuration.parse("P1DT24H")), 0.0);
}
@Test
public void shouldCalc2AndAHalfDays0() {
assertEquals(2.5, daysIn(PeriodDuration.parse("P1DT36H")), 0.0);
}
@Test
public void shouldCalc3Days() {
assertEquals(3.0, daysIn(PeriodDuration.parse("PT71H60M")), 0.0);
}
@Test
public void shouldCalc2Days23H() {
assertEquals(2.958333333, daysIn(PeriodDuration.parse("PT71H")), 0.00001);
}
@Test
public void shouldCalcDays() {
assertEquals(30, daysIn(PeriodDuration.parse("P1M")), 0.0);
}
@Test
public void shouldCalcShiftDays1() {
ZonedDateTime past = ZonedDateTime.now().minusDays(35);
ZonedDateTime now = ZonedDateTime.now();
PeriodDuration periodDuration = PeriodDuration.parse("P1M");
ZonedDateTime shiftedDate = shiftByMultipleOfPeriod(past, now, periodDuration);
assertTrue(shiftedDate.isAfter(now.minusDays(29)));
assertTrue(shiftedDate.isBefore(now));
}
@Test
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();
PeriodDuration periodDuration = PeriodDuration.parse("P1M");
ZonedDateTime shiftedDate = shiftByMultipleOfPeriod(past, now, periodDuration);
// since P1M ist = 28 days, we have a rather inexact match, but it must certainly be before now() - P1M
assertTrue(shiftedDate.isAfter(now.minusDays(56)));
assertTrue(shiftedDate.isBefore(now.minusDays(28)));
}
@Test
public void shouldCalcShiftDays3() {
ZonedDateTime past = ZonedDateTime.now().minusDays(20);
ZonedDateTime now = ZonedDateTime.now();
PeriodDuration periodDuration = PeriodDuration.parse("P7D");
ZonedDateTime shiftedDate = shiftByMultipleOfPeriod(past, now, periodDuration);
assertTrue(shiftedDate.isAfter(now.minusDays(9)));
assertTrue(shiftedDate.isBefore(now));
}
@Test
public void shouldCalcShiftDays4() {
ZonedDateTime past = ZonedDateTime
.parse("2007-12-03T10:15:30+01:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(systemDefault()));
ZonedDateTime now = ZonedDateTime.now();
PeriodDuration periodDuration = PeriodDuration.parse("P7D");
ZonedDateTime shiftedDate = shiftByMultipleOfPeriod(past, now, periodDuration);
// since we are many years and months before now, and a year is 356 days and a month is 28 days, we inexact, but at least we must be a more than P7D before now
assertTrue(shiftedDate.isBefore(now));
}
}