Skip to content

Commit 8af7a8d

Browse files
committed
LocalDate 値オブジェクトの min/max をオーバーライドできるようにする
Fixes #65
1 parent 67f56b5 commit 8af7a8d

File tree

2 files changed

+107
-10
lines changed

2 files changed

+107
-10
lines changed

src/DateTime/LocalDate.php

Lines changed: 88 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,75 @@
3131
*/
3232
final public const int MIN_YEAR = -9999;
3333

34+
/**
35+
* NOTE: 実装クラスでのオーバーライド用メソッド
36+
*/
37+
protected static function minYear(): int
38+
{
39+
return self::MIN_YEAR;
40+
}
41+
42+
final public const int MIN_MONTH = 1;
43+
44+
/**
45+
* NOTE: 実装クラスでのオーバーライド用メソッド
46+
*
47+
* @return int<1,12>
48+
*/
49+
protected static function minMonth(): int
50+
{
51+
return self::MIN_MONTH;
52+
}
53+
54+
final public const int MIN_DAY = 1;
55+
56+
/**
57+
* NOTE: 実装クラスでのオーバーライド用メソッド
58+
*
59+
* @return int<1,31>
60+
*/
61+
protected static function minDay(): int
62+
{
63+
return self::MIN_DAY;
64+
}
65+
3466
/**
3567
* The maximum supported year for instances of `LocalDate`.
3668
*/
3769
final public const int MAX_YEAR = 9999;
3870

71+
/**
72+
* NOTE: 実装クラスでのオーバーライド用メソッド
73+
*/
74+
protected static function maxYear(): int
75+
{
76+
return self::MAX_YEAR;
77+
}
78+
79+
final public const int MAX_MONTH = 12;
80+
81+
/**
82+
* NOTE: 実装クラスでのオーバーライド用メソッド
83+
*
84+
* @return int<1,12>
85+
*/
86+
protected static function maxMonth(): int
87+
{
88+
return self::MAX_MONTH;
89+
}
90+
91+
final public const int MAX_DAY = 31;
92+
93+
/**
94+
* NOTE: 実装クラスでのオーバーライド用メソッド
95+
*
96+
* @return int<1,31>
97+
*/
98+
protected static function maxDay(): int
99+
{
100+
return self::MAX_DAY;
101+
}
102+
39103
/**
40104
* The number of days from year zero to year 1970.
41105
*/
@@ -162,7 +226,12 @@ final public static function now(DateTimeZone $timeZone = new DateTimeZone('Asia
162226

163227
final public static function max(): static
164228
{
165-
return static::of(self::MAX_YEAR, 12, 31);
229+
return static::of(static::maxYear(), static::maxMonth(), static::maxDay());
230+
}
231+
232+
final public static function min(): static
233+
{
234+
return static::of(static::minYear(), static::minMonth(), static::minDay());
166235
}
167236

168237
/**
@@ -216,14 +285,17 @@ final public static function ofEpochDay(int $epochDay): static
216285
*/
217286
final protected static function isValidYear(int $year): Result
218287
{
219-
if ($year < self::MIN_YEAR || $year > self::MAX_YEAR) {
288+
$minYear = static::minYear() > self::MIN_YEAR ? static::minYear() : self::MIN_YEAR;
289+
$maxYear = static::maxYear() < self::MAX_YEAR ? static::maxYear() : self::MAX_YEAR;
290+
291+
if ($year < $minYear || $year > $maxYear) {
220292
return Result\err(
221293
ValueObjectError::dateTime()->invalidRange(
222294
className: static::class,
223295
attributeName: '',
224296
value: (string)$year,
225-
minValue: (string)self::MIN_YEAR,
226-
maxValue: (string)self::MAX_YEAR,
297+
minValue: (string)$minYear,
298+
maxValue: (string)$maxYear,
227299
)
228300
);
229301
}
@@ -237,14 +309,17 @@ className: static::class,
237309
*/
238310
final protected static function isValidMonth(int $month): Result
239311
{
240-
if ($month < 1 || $month > 12) {
312+
$minMonth = static::minMonth() > self::MIN_MONTH ? static::minMonth() : self::MIN_MONTH;
313+
$maxMonth = static::maxMonth() < self::MAX_MONTH ? static::maxMonth() : self::MAX_MONTH;
314+
315+
if ($month < $minMonth || $month > $maxMonth) {
241316
return Result\err(
242317
ValueObjectError::dateTime()->invalidRange(
243318
className: static::class,
244319
attributeName: '',
245320
value: (string)$month,
246-
minValue: '1',
247-
maxValue: '12',
321+
minValue: (string)$minMonth,
322+
maxValue: (string)$maxMonth,
248323
)
249324
);
250325
}
@@ -258,14 +333,17 @@ className: static::class,
258333
*/
259334
final protected static function isValidDay(int $day): Result
260335
{
261-
if ($day < 1 || $day > 31) {
336+
$minDay = static::minDay() > self::MIN_DAY ? static::minDay() : self::MIN_DAY;
337+
$maxDay = static::maxDay() < self::MAX_DAY ? static::maxDay() : self::MAX_DAY;
338+
339+
if ($day < $minDay || $day > $maxDay) {
262340
return Result\err(
263341
ValueObjectError::dateTime()->invalidRange(
264342
className: static::class,
265343
attributeName: '',
266344
value: (string)$day,
267-
minValue: '1',
268-
maxValue: '31',
345+
minValue: (string)$minDay,
346+
maxValue: (string)$maxDay,
269347
)
270348
);
271349
}

tests/Unit/DateTime/LocalDateTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,4 +440,23 @@ public function privateコンストラクタへのアクセスを試みるとエ
440440
/** @phpstan-ignore-next-line */
441441
$date = new LocalDate(2023, 5, 15);
442442
}
443+
444+
#[Test]
445+
public function maxメソッドで正常にインスタンスが作成できる(): void
446+
{
447+
$date = LocalDate::max();
448+
449+
$this->assertSame(LocalDate::MAX_YEAR, $date->getYear());
450+
$this->assertSame(LocalDate::MAX_MONTH, $date->getMonth());
451+
$this->assertSame(LocalDate::MAX_DAY, $date->getDay());
452+
}
453+
454+
#[Test]
455+
public function minメソッドで正常にインスタンスが作成できる(): void
456+
{
457+
$date = LocalDate::min();
458+
$this->assertSame(LocalDate::MIN_YEAR, $date->getYear());
459+
$this->assertSame(LocalDate::MIN_MONTH, $date->getMonth());
460+
$this->assertSame(LocalDate::MIN_DAY, $date->getDay());
461+
}
443462
}

0 commit comments

Comments
 (0)