[New] Added PeriodHelper.shiftMonths()

This commit is contained in:
Robert von Burg 2021-04-28 17:39:18 +02:00
parent 6eb3229a69
commit 0967b413ac
2 changed files with 155 additions and 0 deletions

View File

@ -28,6 +28,24 @@ public class PeriodHelper {
return (period.getYears() * 12.0) + (period.getMonths());
}
/**
* Special method to add the given number of months to the given date and making sure that the day always stays the
* same if possible. I.e. If the given date has the 3. day, then this will also be so on the returned date. But for
* the day 29, 30 or 31 the date might change to 28 or 30, depending on the month on which the result lies.
*
* @param date
* the date to shift
* @param nrOfMonths
* the number of months to shift the given date by
*
* @return the shifted date
*/
public static ZonedDateTime shiftMonths(ZonedDateTime date, int nrOfMonths) {
int selectedDayOfMonth = date.getDayOfMonth();
ZonedDateTime next = date.plusMonths(nrOfMonths);
return next.withDayOfMonth(Math.min(selectedDayOfMonth, next.toLocalDate().lengthOfMonth()));
}
/**
* 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

View File

@ -5,6 +5,8 @@ import static li.strolch.utils.time.PeriodHelper.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@ -87,6 +89,141 @@ public class PeriodHelperTest {
assertEquals(12, monthsIn(PeriodDuration.parse("P1Y")), 0.0);
}
@Test
public void shouldPlusMonthsNormal() {
int expectedDay = 4;
ZonedDateTime date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
assertEquals(expectedDay, date.getDayOfMonth());
// increase by single months
for (int i = 0; i < 5; i++) {
date = shiftMonths(date, 1);
assertEquals(expectedDay, date.getDayOfMonth());
}
// also when increase by multiple months
for (int i = 0; i < 5; i++) {
date = shiftMonths(date, 4);
assertEquals(expectedDay, date.getDayOfMonth());
}
}
@Test
public void shouldPlusMonths28() {
int expectedDay = 28;
ZonedDateTime date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
assertEquals(expectedDay, date.getDayOfMonth());
// increase by single months
for (int i = 0; i < 5; i++) {
date = shiftMonths(date, 1);
assertEquals(expectedDay, date.getDayOfMonth());
}
// also when increase by multiple months
for (int i = 0; i < 5; i++) {
date = shiftMonths(date, 4);
assertEquals(expectedDay, date.getDayOfMonth());
}
}
@Test
public void shouldPlusMonths29() {
int expectedDay = 29;
ZonedDateTime date;
// increase by single months
for (int i = 0; i < 5; i++) {
date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
date = shiftMonths(date, i);
if (date.getMonth() == Month.FEBRUARY)
assertEquals(28, date.getDayOfMonth());
else
assertEquals(expectedDay, date.getDayOfMonth());
}
// also when increase by multiple months
for (int i = 0; i < 5; i++) {
date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
date = shiftMonths(date, i);
if (date.getMonth() == Month.FEBRUARY)
assertEquals(28, date.getDayOfMonth());
else
assertEquals(expectedDay, date.getDayOfMonth());
}
}
@Test
public void shouldPlusMonths30() {
int expectedDay = 30;
ZonedDateTime date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
assertEquals(expectedDay, date.getDayOfMonth());
// increase by single months
for (int i = 0; i < 5; i++) {
date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
date = shiftMonths(date, i);
if (date.getMonth() == Month.FEBRUARY)
assertEquals(28, date.getDayOfMonth());
else
assertEquals(expectedDay, date.getDayOfMonth());
}
// also when increase by multiple months
for (int i = 0; i < 5; i++) {
date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
date = shiftMonths(date, i);
if (date.getMonth() == Month.FEBRUARY)
assertEquals(28, date.getDayOfMonth());
else
assertEquals(expectedDay, date.getDayOfMonth());
}
}
@Test
public void shouldPlusMonths31() {
int expectedDay = 31;
ZonedDateTime date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
assertEquals(date.getMonth().name(), expectedDay, date.getDayOfMonth());
// increase by single months
for (int i = 0; i < 5; i++) {
date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
date = shiftMonths(date, i);
if (date.getMonth() == Month.FEBRUARY) {
assertEquals(date.getMonth().name(), 28, date.getDayOfMonth());
} else if (date.getMonth() == Month.APRIL //
|| date.getMonth() == Month.JUNE //
|| date.getMonth() == Month.SEPTEMBER //
|| date.getMonth() == Month.NOVEMBER) {
assertEquals(date.getMonth().name(), 30, date.getDayOfMonth());
} else {
assertEquals(date.getMonth().name(), expectedDay, date.getDayOfMonth());
}
}
// also when increase by multiple months
for (int i = 0; i < 5; i++) {
date = LocalDate.of(2001, Month.JANUARY, expectedDay).atStartOfDay(systemDefault());
date = shiftMonths(date, i);
if (date.getMonth() == Month.FEBRUARY) {
assertEquals(date.getMonth().name(), 28, date.getDayOfMonth());
} else if (date.getMonth() == Month.APRIL //
|| date.getMonth() == Month.JUNE //
|| date.getMonth() == Month.SEPTEMBER //
|| date.getMonth() == Month.NOVEMBER) {
assertEquals(date.getMonth().name(), 30, date.getDayOfMonth());
} else {
assertEquals(date.getMonth().name(), expectedDay, date.getDayOfMonth());
}
}
}
@Test
public void shouldCalcShiftDays1() {
ZonedDateTime past = ZonedDateTime.now().minusDays(35);