Skip to content

Commit

Permalink
feat: add Date.subMonths method (#764)
Browse files Browse the repository at this point in the history
  • Loading branch information
marmichalski authored Aug 21, 2024
1 parent 4e1566f commit 55f2859
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 6 deletions.
37 changes: 31 additions & 6 deletions lib/Date.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,29 @@ public function addMonths(int $increment): self
$year++;
}

// @infection-ignore-all (IncrementInteger)
$daysInNewMonth = (int) DateTimeFactory::immutableFromFormat(
'Y-m-d',
\sprintf('%d-%02d-%02d', $year, $month, 1),
)->format('t');
return new self($year, $month, \min($this->day, $this->numberOfDaysInMonth($year, $month)));
}

/**
* @return self Instance decremented by the specified number of months.
* If the resulting month has fewer days than the current day, the day will be the last day of that month.
*
* @throws \InvalidArgumentException if $decrement is less than 1
*/
public function subMonths(int $decrement): self
{
if ($decrement < 1) {
throw new \InvalidArgumentException('Months decrement must be greater than 0.');
}

$month = $this->month - $decrement;
$year = $this->year;
while ($month < 1) {
$month += 12;
$year--;
}

return new self($year, $month, \min($this->day, $daysInNewMonth));
return new self($year, $month, \min($this->day, $this->numberOfDaysInMonth($year, $month)));
}

public function offsetByDays(int $days): self
Expand Down Expand Up @@ -217,4 +233,13 @@ private function modify(string $modification): self
{
return self::fromDateTime($this->startOfDay()->modify($modification));
}

private function numberOfDaysInMonth(int $year, int $month): int
{
// @infection-ignore-all (IncrementInteger)
return (int) DateTimeFactory::immutableFromFormat(
'Y-m-d',
\sprintf('%d-%02d-%02d', $year, $month, 1),
)->format('t');
}
}
47 changes: 47 additions & 0 deletions tests/unit/DateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,15 @@ public function it_throws_when_incrementing_month_by_less_than_1(int $increment)
Date::fromYearMonthDay(2018, 10, 10)->addMonths($increment);
}

#[Test]
#[DataProvider('provideInvalidDateMonthIncrements')]
public function it_throws_when_decrementing_month_by_less_than_1(int $decrement): void
{
$this->expectExceptionObject(new \InvalidArgumentException('Months decrement must be greater than 0.'));

Date::fromYearMonthDay(2018, 10, 10)->subMonths($decrement);
}

/**
* @return iterable<array{int}>
*/
Expand All @@ -579,6 +588,44 @@ public static function provideInvalidDateMonthIncrements(): iterable
yield [-10];
}

#[Test]
#[DataProvider('provideDatesForMonthDecrement')]
public function it_will_correctly_sub_months(
string $currentDate,
int $decrement,
string $expectedDate,
): void {
$this->assertSame(
$expectedDate,
Date::fromYearMonthDayString($currentDate)->subMonths($decrement)->toYearMonthDayString(),
);
}

/**
* @return iterable<array{string, positive-int, string}>
*/
public static function provideDatesForMonthDecrement(): iterable
{
yield ['2019-02-05', 1, '2019-01-05'];
yield ['2020-01-31', 1, '2019-12-31'];
yield ['2019-03-31', 1, '2019-02-28'];

yield ['2019-07-05', 6, '2019-01-05'];
yield ['2020-03-31', 5, '2019-10-31'];
yield ['2020-02-29', 6, '2019-08-29'];
yield ['2020-03-31', 6, '2019-09-30'];

yield ['2020-01-05', 12, '2019-01-05'];
yield ['2020-10-31', 12, '2019-10-31'];
yield ['2020-08-31', 12, '2019-08-31'];
yield ['2020-10-31', 12, '2019-10-31'];

yield ['2021-07-05', 30, '2019-01-05'];
yield ['2022-03-31', 30, '2019-09-30'];
yield ['2022-02-28', 30, '2019-08-28'];
yield ['2022-04-30', 30, '2019-10-30'];
}

#[Test]
#[DataProvider('provideValidDateDayChanges')]
public function it_can_change_day(int $day): void
Expand Down

0 comments on commit 55f2859

Please sign in to comment.