diff --git a/src/System/Time/Now.php b/src/System/Time/Now.php index 2279bdee..c35739fc 100644 --- a/src/System/Time/Now.php +++ b/src/System/Time/Now.php @@ -9,18 +9,18 @@ use System\Time\Traits\DateTimeFormatTrait; /** - * @property int $timestamp - * @property int $year - * @property int $month - * @property int $day - * @property int $hour - * @property int $minute - * @property int $second - * @property string $monthName - * @property string $dayName - * @property string $shortDay - * @property string $timeZone - * @property int|float $age + * @property int $timestamp + * @property int $year + * @property int $month + * @property int $day + * @property int $hour + * @property int $minute + * @property int $second + * @property string $monthName + * @property string $dayName + * @property string $shortDay + * @property string $timeZone + * @property int $age */ class Now { @@ -54,8 +54,7 @@ class Now private $timeZone; // other property - /** @var int|float */ - private $age; + private int $age; public function __construct(string $date_format = 'now', ?string $time_zone = null) { @@ -126,9 +125,7 @@ private function refresh(): void $this->timeZone = $this->date->format('e'); $this->shortDay = $this->date->format('D'); - $now = new \DateTime('now', new \DateTimeZone($this->timeZone)); - $interval = $now->diff($this->date); - $this->age = $interval->y; + $this->age = max(0, (int) floor((time() - $this->timestamp) / (365.25 * 24 * 60 * 60))); } private function current(string $format, int $timestamp): string diff --git a/tests/Time/TimeTravelTest.php b/tests/Time/TimeTravelTest.php index 44115c21..7ffb196f 100644 --- a/tests/Time/TimeTravelTest.php +++ b/tests/Time/TimeTravelTest.php @@ -150,14 +150,25 @@ public function itSameWithCustumeTime(): void $this->assertTrue($now->isSaturday(), 'day must same'); } - /** - * @test - */ - public function itCorrectAge(): void + /** @test */ + public function itCalculatesAgeCorrectlyForTypicalBirthday(): void { - $now = new Now('01/01/2000'); + $now = new Now('01/01/1990'); $currentYear = (int) date('Y'); - $expectedAge = $currentYear - 2000; + $expectedAge = $currentYear - 1990; + $this->assertSame( + $expectedAge, + $now->age, + 'the age must equal' + ); + } + + /** @test */ + public function itHandlesLeapYearBirthdayCorrectly(): void + { + $now = new Now('02/29/2000'); + $birthDateBefore = new DateTime(date('02/29/2000')); + $expectedAge = $birthDateBefore->diff(new DateTime())->y; $this->assertSame( $expectedAge, $now->age, @@ -165,6 +176,71 @@ public function itCorrectAge(): void ); } + /** @test */ + public function itHandlesFutureBirthdateCorrectly(): void + { + $now = new Now('next day'); + $this->assertSame( + 0, + $now->age, + 'the age must be 0 for a future birthdate' + ); + } + + /** @test */ + public function itCalculatesAgeAsZeroForTodayBirthdate(): void + { + $now = new Now('now', 'utc'); + $this->assertSame( + 0, + $now->age, + 'the age must be 0 for today\'s birthdate' + ); + } + + /** @test */ + public function itHandlesEdgeCasesAroundBirthdayCorrectly(): void + { + $nowBeforeBirthday = new Now(date('m/d/Y', strtotime('-1 day'))); + $birthDateBefore = new DateTime(date('m/d/Y', strtotime('-1 day'))); + $expectedAgeBefore = $birthDateBefore->diff(new DateTime())->y; + $this->assertSame( + $expectedAgeBefore, + $nowBeforeBirthday->age, + 'the age must be correct just before the birthday' + ); + + $nowAfterBirthday = new Now(date('m/d/Y', strtotime('+1 day'))); + $birthDateAfter = new DateTime(date('m/d/Y', strtotime('+1 day'))); + $expectedAgeAfter = $birthDateAfter->diff(new DateTime())->y; + $this->assertSame( + $expectedAgeAfter, + $nowAfterBirthday->age, + 'the age must be correct just after the birthday' + ); + } + + /** @test */ + public function itHandlesDifferentTimeZonesCorrectly(): void + { + $nowUTC = new Now('01/01/2000', 'UTC'); + $nowJKT = new Now('01/01/2000', 'Asia/Jakarta'); + $birthDate = new DateTime('01/01/2000'); + $expectedAge = $birthDate->diff(new DateTime())->y; + + $this->assertSame( + $expectedAge, + $nowUTC->age, + 'the age must be correct in UTC' + ); + + $this->assertSame( + $expectedAge, + $nowJKT->age, + 'the age must be correct in Asia/Jakarta' + ); + } + /** @test */ public function itCanGetFromPrivateProperty() {