Skip to content

Commit

Permalink
YearMonth: deprecate int argument for month, add support for Month enum.
Browse files Browse the repository at this point in the history
  • Loading branch information
gnutix committed Mar 22, 2024
1 parent 4682c4e commit e9928ba
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 25 deletions.
64 changes: 39 additions & 25 deletions src/YearMonth.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,12 @@ final class YearMonth implements JsonSerializable, Stringable
* The year, from MIN_YEAR to MAX_YEAR.
*/
private readonly int $year;

/**
* The month, from 1 to 12.
*/
private readonly int $month;
private readonly Month $month;

/**
* @param int $year The year, validated from MIN_YEAR to MAX_YEAR.
* @param int $month The month, validated in the range 1 to 12.
*/
private function __construct(int $year, int $month)
private function __construct(int $year, Month $month)
{
$this->year = $year;
$this->month = $month;
Expand All @@ -45,14 +40,22 @@ private function __construct(int $year, int $month)
* Obtains an instance of `YearMonth` from a year and month.
*
* @param int $year The year, from MIN_YEAR to MAX_YEAR.
* @param int $month The month-of-year, from 1 (January) to 12 (December).
*
* @throws DateTimeException
*/
public static function of(int $year, int $month): YearMonth
public static function of(int $year, int|Month $month): YearMonth
{
Field\Year::check($year);
Field\MonthOfYear::check($month);

if (is_int($month)) {
// usually we don't use trigger_error() for deprecations, but we can't rely on @deprecated for a parameter type change;
// maybe we should revisit using trigger_error() unconditionally for deprecations in the future.
trigger_error('Passing an integer to YearMonth::of() second argument is deprecated, pass a Month instance instead.', E_USER_DEPRECATED);

Field\MonthOfYear::check($month);

$month = Month::from($month);
}

return new YearMonth($year, $month);
}
Expand Down Expand Up @@ -96,7 +99,10 @@ public static function now(TimeZone $timeZone, ?Clock $clock = null): YearMonth
{
$localDate = LocalDate::now($timeZone, $clock);

return new YearMonth($localDate->getYear(), $localDate->getMonthValue());
/** @todo Replace by getMonth() once it returns a Month */
$month = Month::from($localDate->getMonthValue());

return new YearMonth($localDate->getYear(), $month);
}

public function getYear(): int
Expand All @@ -110,15 +116,15 @@ public function getYear(): int
*/
public function getMonth(): int
{
return $this->month;
return $this->month->value;
}

/**
* Returns the month-of-year value from 1 to 12.
*/
public function getMonthValue(): int
{
return $this->month;
return $this->month->value;
}

/**
Expand All @@ -134,7 +140,7 @@ public function isLeapYear(): bool
*/
public function getLengthOfMonth(): int
{
return Month::from($this->month)->getLength($this->isLeapYear());
return $this->month->getLength($this->isLeapYear());
}

/**
Expand All @@ -156,10 +162,10 @@ public function compareTo(YearMonth $that): int
if ($this->year > $that->year) {
return 1;
}
if ($this->month < $that->month) {
if ($this->month->value < $that->month->value) {
return -1;
}
if ($this->month > $that->month) {
if ($this->month->value > $that->month->value) {
return 1;
}

Expand Down Expand Up @@ -209,17 +215,23 @@ public function withYear(int $year): YearMonth

/**
* Returns a copy of this YearMonth with the month-of-year altered.
*
* @throws DateTimeException If the month-of-year is not valid.
*/
public function withMonth(int $month): YearMonth
public function withMonth(int|Month $month): YearMonth
{
if (is_int($month)) {
// usually we don't use trigger_error() for deprecations, but we can't rely on @deprecated for a parameter type change;
// maybe we should revisit using trigger_error() unconditionally for deprecations in the future.
trigger_error('Passing an integer to Year::atMonth() is deprecated, pass a Month instance instead.', E_USER_DEPRECATED);

Field\MonthOfYear::check($month);

$month = Month::from($month);
}

if ($month === $this->month) {
return $this;
}

Field\MonthOfYear::check($month);

return new YearMonth($this->year, $month);
}

Expand All @@ -244,7 +256,7 @@ public function getLastDay(): LocalDate
*/
public function atDay(int $day): LocalDate
{
return LocalDate::of($this->year, $this->month, $day);
return LocalDate::of($this->year, $this->month->value, $day);
}

/**
Expand All @@ -268,14 +280,14 @@ public function plusMonths(int $months): YearMonth
return $this;
}

$month = $this->month + $months - 1;
$month = $this->month->value + $months - 1;

$yearDiff = Math::floorDiv($month, 12);
$month = Math::floorMod($month, 12) + 1;

$year = $this->year + $yearDiff;

return new YearMonth($year, $month);
return new YearMonth($year, Month::from($month));
}

/**
Expand Down Expand Up @@ -315,6 +327,8 @@ public function jsonSerialize(): string
*/
public function toISOString(): string
{
$month = $this->month->value;

// This code is optimized for high performance
return ($this->year < 1000 && $this->year > -1000
? (
Expand All @@ -325,7 +339,7 @@ public function toISOString(): string
: $this->year
)
. '-'
. ($this->month < 10 ? '0' . $this->month : $this->month);
. ($month < 10 ? '0' . $month : $month);
}

/**
Expand Down
4 changes: 4 additions & 0 deletions tests/YearMonthTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Brick\DateTime\Clock\FixedClock;
use Brick\DateTime\DateTimeException;
use Brick\DateTime\Instant;
use Brick\DateTime\Month;
use Brick\DateTime\TimeZone;
use Brick\DateTime\YearMonth;

Expand All @@ -22,6 +23,7 @@ class YearMonthTest extends AbstractTestCase
public function testOf(): void
{
self::assertYearMonthIs(2007, 7, YearMonth::of(2007, 7));
self::assertYearMonthIs(2007, 7, YearMonth::of(2007, Month::JULY));
}

/**
Expand Down Expand Up @@ -319,11 +321,13 @@ public function testWithYearWithSameYear(): void
public function testWithMonth(): void
{
self::assertYearMonthIs(2000, 12, YearMonth::of(2000, 1)->withMonth(12));
self::assertYearMonthIs(2000, 12, YearMonth::of(2000, 1)->withMonth(Month::DECEMBER));
}

public function testWithMonthWithSameMonth(): void
{
self::assertYearMonthIs(2000, 2, YearMonth::of(2000, 2)->withMonth(2));
self::assertYearMonthIs(2000, 2, YearMonth::of(2000, 2)->withMonth(Month::FEBRUARY));
}

public function testGetFirstDay(): void
Expand Down

0 comments on commit e9928ba

Please sign in to comment.