diff --git a/docs/en/index.rst b/docs/en/index.rst index d9accc23..43cf032b 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -290,6 +290,7 @@ Other properties that can be accessed are: - daysInMonth - timestamp - quarter +- half Testing Aids ------------ diff --git a/docs/fr/index.rst b/docs/fr/index.rst index 33d96e74..a8419604 100644 --- a/docs/fr/index.rst +++ b/docs/fr/index.rst @@ -302,6 +302,7 @@ Les autres propriétés accessibles sont: - daysInMonth - timestamp - quarter +- half Aides aux Tests --------------- diff --git a/docs/ja/index.rst b/docs/ja/index.rst index 3f2de6c2..9798a5c8 100644 --- a/docs/ja/index.rst +++ b/docs/ja/index.rst @@ -276,6 +276,7 @@ Chronos は、出力した日時オブジェクトを表示するための多く - daysInMonth - timestamp - quarter +- half テストの支援 ------------ diff --git a/docs/pt/index.rst b/docs/pt/index.rst index f2cfdea2..faa07f91 100644 --- a/docs/pt/index.rst +++ b/docs/pt/index.rst @@ -258,6 +258,7 @@ Outras propriedades que podem ser acessadas são: - daysInMonth - timestamp - quarter +- half Auxílio para testes ------------------- diff --git a/src/Chronos.php b/src/Chronos.php index 969802b7..374d5f9d 100644 --- a/src/Chronos.php +++ b/src/Chronos.php @@ -29,23 +29,24 @@ * * @property-read int $year * @property-read int $yearIso - * @property-read int $month - * @property-read int $day - * @property-read int $hour - * @property-read int $minute - * @property-read int $second - * @property-read int $micro - * @property-read int $microsecond + * @property-read int<1, 12> $month + * @property-read int<1, 31> $day + * @property-read int<0, 23> $hour + * @property-read int<0, 59> $minute + * @property-read int<0, 59> $second + * @property-read int<0, 999999> $micro + * @property-read int<0, 999999> $microsecond * @property-read int $timestamp seconds since the Unix Epoch * @property-read \DateTimeZone $timezone the current timezone * @property-read \DateTimeZone $tz alias of timezone - * @property-read int $dayOfWeek 1 (for Monday) through 7 (for Sunday) - * @property-read int $dayOfYear 0 through 365 - * @property-read int $weekOfMonth 1 through 5 - * @property-read int $weekOfYear ISO-8601 week number of year, weeks starting on Monday - * @property-read int $daysInMonth number of days in the given month + * @property-read int<1, 7> $dayOfWeek 1 (for Monday) through 7 (for Sunday) + * @property-read int<0, 365> $dayOfYear 0 through 365 + * @property-read int<1, 5> $weekOfMonth 1 through 5 + * @property-read int<1, 53> $weekOfYear ISO-8601 week number of year, weeks starting on Monday + * @property-read int<1, 31> $daysInMonth number of days in the given month * @property-read int $age does a diffInYears() with default parameters - * @property-read int $quarter the quarter of this instance, 1 - 4 + * @property-read int<1, 4> $quarter the quarter of this instance, 1 - 4 + * @property-read int<1, 2> $half the half of the year, with 1 for months Jan...Jun and 2 for Jul...Dec. * @property-read int $offset the timezone offset in seconds from UTC * @property-read int $offsetHours the timezone offset in hours from UTC * @property-read bool $dst daylight savings time indicator, true if DST, false otherwise @@ -2055,6 +2056,26 @@ public function isLastYear(): bool return $this->year === static::now($this->tz)->subYears(1)->year; } + /** + * Determines if the instance is within the first half of year + * + * @return bool + */ + public function isFirstHalf(): bool + { + return $this->half === 1; + } + + /** + * Determines if the instance is within the second half of year + * + * @return bool + */ + public function isSecondHalf(): bool + { + return $this->half === 2; + } + /** * Determines if the instance is in the future, ie. greater (after) than now * @@ -2592,6 +2613,9 @@ public function __get(string $name): string|float|int|bool|DateTimeZone case $name === 'quarter': return (int)ceil($this->month / 3); + case $name === 'half': + return $this->month <= 6 ? 1 : 2; + case $name === 'offset': return $this->getOffset(); diff --git a/src/ChronosDate.php b/src/ChronosDate.php index 941b5158..9af0b597 100644 --- a/src/ChronosDate.php +++ b/src/ChronosDate.php @@ -30,15 +30,16 @@ * * @property-read int $year * @property-read int $yearIso - * @property-read int $month - * @property-read int $day - * @property-read int $dayOfWeek 1 (for Monday) through 7 (for Sunday) - * @property-read int $dayOfYear 0 through 365 - * @property-read int $weekOfMonth 1 through 5 - * @property-read int $weekOfYear ISO-8601 week number of year, weeks starting on Monday - * @property-read int $daysInMonth number of days in the given month + * @property-read int<1, 12> $month + * @property-read int<1, 31> $day + * @property-read int<1, 7> $dayOfWeek 1 (for Monday) through 7 (for Sunday) + * @property-read int<0, 365> $dayOfYear 0 through 365 + * @property-read int<1, 5> $weekOfMonth 1 through 5 + * @property-read int<1, 53> $weekOfYear ISO-8601 week number of year, weeks starting on Monday + * @property-read int<1, 31> $daysInMonth number of days in the given month * @property-read int $age does a diffInYears() with default parameters - * @property-read int $quarter the quarter of this instance, 1 - 4 + * @property-read int<1, 4> $quarter the quarter of this instance, 1 - 4 + * @property-read int<1, 2> $half the half of the year, with 1 for months Jan...Jun and 2 for Jul...Dec. * @psalm-immutable * @psalm-consistent-constructor */ @@ -1225,6 +1226,26 @@ public function isLastYear(DateTimeZone|string|null $timezone = null): bool return $this->year === static::now($timezone)->subYears(1)->year; } + /** + * Determines if the instance is within the first half of year + * + * @return bool + */ + public function isFirstHalf(): bool + { + return $this->half === 1; + } + + /** + * Determines if the instance is within the second half of year + * + * @return bool + */ + public function isSecondHalf(): bool + { + return $this->half === 2; + } + /** * Determines if the instance is in the future, ie. greater (after) than now * @@ -1566,6 +1587,9 @@ public function __get(string $name): string|float|int|bool case $name === 'quarter': return (int)ceil($this->month / 3); + case $name === 'half': + return $this->month <= 6 ? 1 : 2; + default: throw new InvalidArgumentException(sprintf("Unknown getter '%s'", $name)); } diff --git a/tests/TestCase/Date/GettersTest.php b/tests/TestCase/Date/GettersTest.php new file mode 100644 index 00000000..409a0bc8 --- /dev/null +++ b/tests/TestCase/Date/GettersTest.php @@ -0,0 +1,29 @@ +assertSame($expectedHalfOfYear, $d->half); + } +} diff --git a/tests/TestCase/Date/IsTest.php b/tests/TestCase/Date/IsTest.php index abe00902..0374e88b 100644 --- a/tests/TestCase/Date/IsTest.php +++ b/tests/TestCase/Date/IsTest.php @@ -17,6 +17,7 @@ use Cake\Chronos\Chronos; use Cake\Chronos\ChronosDate; use Cake\Chronos\Test\TestCase\TestCase; +use PHPUnit\Framework\Attributes\TestWith; class IsTest extends TestCase { @@ -364,4 +365,23 @@ public function testIsWithinNext() $this->assertTrue((new Chronos('+1 week'))->isWithinNext('7 day')); $this->assertTrue((new Chronos('+1 month'))->isWithinNext('1 month')); } + + #[TestWith([1, true, false])] + #[TestWith([2, true, false])] + #[TestWith([3, true, false])] + #[TestWith([4, true, false])] + #[TestWith([5, true, false])] + #[TestWith([6, true, false])] + #[TestWith([7, false, true])] + #[TestWith([8, false, true])] + #[TestWith([9, false, true])] + #[TestWith([10, false, true])] + #[TestWith([11, false, true])] + #[TestWith([12, false, true])] + public function testIsFirstOrSecondHalfOfYear(int $month, bool $isFirstHalfOfYear, bool $isSecondHalfOfYear): void + { + $d = Chronos::createFromDate(2023, $month, 1); + $this->assertSame($isFirstHalfOfYear, $d->isFirstHalf()); + $this->assertSame($isSecondHalfOfYear, $d->isSecondHalf()); + } } diff --git a/tests/TestCase/DateTime/GettersTest.php b/tests/TestCase/DateTime/GettersTest.php index 419bcd0c..8d2fe591 100644 --- a/tests/TestCase/DateTime/GettersTest.php +++ b/tests/TestCase/DateTime/GettersTest.php @@ -18,6 +18,7 @@ use Cake\Chronos\Chronos; use Cake\Chronos\Test\TestCase\TestCase; use InvalidArgumentException; +use PHPUnit\Framework\Attributes\TestWith; class GettersTest extends TestCase { @@ -162,6 +163,24 @@ public function testGetQuarterFirstLast() $this->assertSame(4, $d->quarter); } + #[TestWith([1, 1])] + #[TestWith([2, 1])] + #[TestWith([3, 1])] + #[TestWith([4, 1])] + #[TestWith([5, 1])] + #[TestWith([6, 1])] + #[TestWith([7, 2])] + #[TestWith([8, 2])] + #[TestWith([9, 2])] + #[TestWith([10, 2])] + #[TestWith([11, 2])] + #[TestWith([12, 2])] + public function testHalfOfYear(int $month, int $expectedHalfOfYear): void + { + $d = Chronos::createFromDate(2012, $month, 1); + $this->assertSame($expectedHalfOfYear, $d->half); + } + public function testGetLocalTrue() { // Default timezone has been set to America/Toronto in TestCase.php diff --git a/tests/TestCase/DateTime/IsTest.php b/tests/TestCase/DateTime/IsTest.php index 4ce8ef0d..1a521945 100644 --- a/tests/TestCase/DateTime/IsTest.php +++ b/tests/TestCase/DateTime/IsTest.php @@ -16,7 +16,9 @@ namespace Cake\Chronos\Test\TestCase\DateTime; use Cake\Chronos\Chronos; +use Cake\Chronos\ChronosDate; use Cake\Chronos\Test\TestCase\TestCase; +use PHPUnit\Framework\Attributes\TestWith; class IsTest extends TestCase { @@ -440,4 +442,23 @@ public function testIsWithinNext() $this->assertTrue((new Chronos('+1 second'))->isWithinNext('1 minute')); $this->assertTrue((new Chronos('+1 month'))->isWithinNext('1 month')); } + + #[TestWith([1, true, false])] + #[TestWith([2, true, false])] + #[TestWith([3, true, false])] + #[TestWith([4, true, false])] + #[TestWith([5, true, false])] + #[TestWith([6, true, false])] + #[TestWith([7, false, true])] + #[TestWith([8, false, true])] + #[TestWith([9, false, true])] + #[TestWith([10, false, true])] + #[TestWith([11, false, true])] + #[TestWith([12, false, true])] + public function testIsFirstOrSecondHalfOfYear(int $month, bool $isFirstHalfOfYear, bool $isSecondHalfOfYear): void + { + $d = ChronosDate::create(2023, $month, 1); + $this->assertSame($isFirstHalfOfYear, $d->isFirstHalf()); + $this->assertSame($isSecondHalfOfYear, $d->isSecondHalf()); + } } diff --git a/tests/TestCase/DateTime/IssetTest.php b/tests/TestCase/DateTime/IssetTest.php index 3d8c6d54..3ce6744e 100644 --- a/tests/TestCase/DateTime/IssetTest.php +++ b/tests/TestCase/DateTime/IssetTest.php @@ -47,6 +47,7 @@ public function testIssetReturnTrueForProperties() 'timezoneName', 'tz', 'tzName', + 'half', ]; foreach ($properties as $property) {