Skip to content

Commit 847e4b1

Browse files
authored
Improve documentation coverage (#512)
* Improve documentation coverage - Expand README with ChronosTime, setTestNow, and ClockFactory examples - Improve ClockFactory class and method documentation - Add detailed docs for createInterval() explaining rollover behavior - Improve average() docs with example showing midpoint calculation - Improve diffFiltered() docs with callback signature and example - Improve nthOfMonth/Quarter/Year docs explaining false return case * Improve firstOf*/lastOf* and min/max documentation - Clarify @param for $dayOfWeek to specify Chronos constants - Improve min() docs explaining it returns the earlier datetime - Improve max() docs explaining it returns the later datetime - Document that null defaults to current time for min/max
1 parent e87a8d7 commit 847e4b1

File tree

4 files changed

+276
-80
lines changed

4 files changed

+276
-80
lines changed

README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,64 @@ echo $today->modify('+3 hours');
7777

7878
Like instances of `Chronos`, `ChronosDate` objects are also *immutable*.
7979

80+
# Time-only Values
81+
82+
When you need to work with just times (without dates), use `ChronosTime`:
83+
84+
```php
85+
use Cake\Chronos\ChronosTime;
86+
87+
$time = new ChronosTime('14:30:00');
88+
echo $time->format('g:i A'); // 2:30 PM
89+
90+
// Create from components
91+
$time = ChronosTime::create(14, 30, 0);
92+
93+
// Arithmetic
94+
$later = $time->addHours(2)->addMinutes(15);
95+
```
96+
97+
`ChronosTime` is useful for recurring schedules, business hours, or any scenario
98+
where the date is irrelevant.
99+
100+
# Testing with Chronos
101+
102+
Chronos provides `setTestNow()` to freeze time during testing:
103+
104+
```php
105+
use Cake\Chronos\Chronos;
106+
107+
// Freeze time for predictable tests
108+
Chronos::setTestNow('2024-01-15 10:00:00');
109+
110+
$now = Chronos::now(); // Always 2024-01-15 10:00:00
111+
112+
// Reset to real time
113+
Chronos::setTestNow(null);
114+
```
115+
116+
# PSR-20 Clock Interface
117+
118+
For dependency injection, use `ClockFactory` which implements PSR-20:
119+
120+
```php
121+
use Cake\Chronos\ClockFactory;
122+
123+
$clock = new ClockFactory('UTC');
124+
$now = $clock->now(); // Returns Chronos instance
125+
126+
// In your service
127+
class OrderService
128+
{
129+
public function __construct(private ClockInterface $clock) {}
130+
131+
public function createOrder(): Order
132+
{
133+
return new Order(createdAt: $this->clock->now());
134+
}
135+
}
136+
```
137+
80138
# Documentation
81139

82140
A more descriptive documentation can be found at [book.cakephp.org/chronos/3/](https://book.cakephp.org/chronos/3/).

src/Chronos.php

Lines changed: 122 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,22 @@ protected static function safeCreateDateTimeZone(DateTimeZone|string|null $objec
769769
/**
770770
* Create a new DateInterval instance from specified values.
771771
*
772+
* Values that exceed their natural limits will automatically roll over
773+
* to the next higher unit. For example, 90 minutes becomes 1 hour and
774+
* 30 minutes, 25 hours becomes 1 day and 1 hour.
775+
*
776+
* Rollover cascades upward: microseconds -> seconds -> minutes -> hours -> days.
777+
* Years, months, and weeks do not roll over.
778+
*
779+
* Example:
780+
* ```
781+
* // 90 seconds becomes 1 minute 30 seconds
782+
* $interval = Chronos::createInterval(seconds: 90);
783+
*
784+
* // 25 hours becomes 1 day 1 hour
785+
* $interval = Chronos::createInterval(hours: 25);
786+
* ```
787+
*
772788
* @param int|null $years The year to use.
773789
* @param int|null $months The month to use.
774790
* @param int|null $weeks The week to use.
@@ -1584,7 +1600,8 @@ public function endOfWeek(): static
15841600
* of the current day of the week. Use the supplied consts
15851601
* to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
15861602
*
1587-
* @param int|null $dayOfWeek The day of the week to move to.
1603+
* @param int|null $dayOfWeek The day of the week (use Chronos::MONDAY through
1604+
* Chronos::SUNDAY), or null for a sensible default.
15881605
* @return static
15891606
*/
15901607
public function next(?int $dayOfWeek = null): static
@@ -1604,7 +1621,8 @@ public function next(?int $dayOfWeek = null): static
16041621
* of the current day of the week. Use the supplied consts
16051622
* to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
16061623
*
1607-
* @param int|null $dayOfWeek The day of the week to move to.
1624+
* @param int|null $dayOfWeek The day of the week (use Chronos::MONDAY through
1625+
* Chronos::SUNDAY), or null for a sensible default.
16081626
* @return static
16091627
*/
16101628
public function previous(?int $dayOfWeek = null): static
@@ -1624,7 +1642,8 @@ public function previous(?int $dayOfWeek = null): static
16241642
* first day of the current month. Use the supplied consts
16251643
* to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
16261644
*
1627-
* @param int|null $dayOfWeek The day of the week to move to.
1645+
* @param int|null $dayOfWeek The day of the week (use Chronos::MONDAY through
1646+
* Chronos::SUNDAY), or null for a sensible default.
16281647
* @return static
16291648
*/
16301649
public function firstOfMonth(?int $dayOfWeek = null): static
@@ -1640,7 +1659,8 @@ public function firstOfMonth(?int $dayOfWeek = null): static
16401659
* last day of the current month. Use the supplied consts
16411660
* to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
16421661
*
1643-
* @param int|null $dayOfWeek The day of the week to move to.
1662+
* @param int|null $dayOfWeek The day of the week (use Chronos::MONDAY through
1663+
* Chronos::SUNDAY), or null for a sensible default.
16441664
* @return static
16451665
*/
16461666
public function lastOfMonth(?int $dayOfWeek = null): static
@@ -1651,14 +1671,22 @@ public function lastOfMonth(?int $dayOfWeek = null): static
16511671
}
16521672

16531673
/**
1654-
* Modify to the given occurrence of a given day of the week
1655-
* in the current month. If the calculated occurrence is outside the scope
1656-
* of the current month, then return false and no modifications are made.
1657-
* Use the supplied consts to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
1674+
* Get the nth occurrence of a day of the week in the current month.
16581675
*
1659-
* @param int $nth The offset to use.
1660-
* @param int $dayOfWeek The day of the week to move to.
1661-
* @return static|false
1676+
* Returns false if the requested occurrence doesn't exist in the month.
1677+
* For example, requesting the 5th Monday will return false for months
1678+
* that only have 4 Mondays.
1679+
*
1680+
* Example:
1681+
* ```
1682+
* $date = new Chronos('2024-01-15');
1683+
* $date->nthOfMonth(2, Chronos::TUESDAY); // 2nd Tuesday of January
1684+
* $date->nthOfMonth(5, Chronos::MONDAY); // false if no 5th Monday
1685+
* ```
1686+
*
1687+
* @param int $nth The occurrence number (1 = first, 2 = second, etc.).
1688+
* @param int $dayOfWeek The day of the week (use Chronos::MONDAY, etc.).
1689+
* @return static|false The date of the nth occurrence, or false if it doesn't exist.
16621690
*/
16631691
public function nthOfMonth(int $nth, int $dayOfWeek): static|false
16641692
{
@@ -1675,7 +1703,8 @@ public function nthOfMonth(int $nth, int $dayOfWeek): static|false
16751703
* first day of the current quarter. Use the supplied consts
16761704
* to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
16771705
*
1678-
* @param int|null $dayOfWeek The day of the week to move to.
1706+
* @param int|null $dayOfWeek The day of the week (use Chronos::MONDAY through
1707+
* Chronos::SUNDAY), or null for a sensible default.
16791708
* @return static
16801709
*/
16811710
public function firstOfQuarter(?int $dayOfWeek = null): static
@@ -1692,7 +1721,8 @@ public function firstOfQuarter(?int $dayOfWeek = null): static
16921721
* last day of the current quarter. Use the supplied consts
16931722
* to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
16941723
*
1695-
* @param int|null $dayOfWeek The day of the week to move to.
1724+
* @param int|null $dayOfWeek The day of the week (use Chronos::MONDAY through
1725+
* Chronos::SUNDAY), or null for a sensible default.
16961726
* @return static
16971727
*/
16981728
public function lastOfQuarter(?int $dayOfWeek = null): static
@@ -1704,14 +1734,20 @@ public function lastOfQuarter(?int $dayOfWeek = null): static
17041734
}
17051735

17061736
/**
1707-
* Modify to the given occurrence of a given day of the week
1708-
* in the current quarter. If the calculated occurrence is outside the scope
1709-
* of the current quarter, then return false and no modifications are made.
1710-
* Use the supplied consts to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
1737+
* Get the nth occurrence of a day of the week in the current quarter.
17111738
*
1712-
* @param int $nth The offset to use.
1713-
* @param int $dayOfWeek The day of the week to move to.
1714-
* @return static|false
1739+
* Returns false if the requested occurrence doesn't exist in the quarter.
1740+
* Quarters are: Q1 (Jan-Mar), Q2 (Apr-Jun), Q3 (Jul-Sep), Q4 (Oct-Dec).
1741+
*
1742+
* Example:
1743+
* ```
1744+
* $date = new Chronos('2024-02-15'); // Q1
1745+
* $date->nthOfQuarter(5, Chronos::FRIDAY); // 5th Friday of Q1
1746+
* ```
1747+
*
1748+
* @param int $nth The occurrence number (1 = first, 2 = second, etc.).
1749+
* @param int $dayOfWeek The day of the week (use Chronos::MONDAY, etc.).
1750+
* @return static|false The date of the nth occurrence, or false if it doesn't exist.
17151751
*/
17161752
public function nthOfQuarter(int $nth, int $dayOfWeek): static|false
17171753
{
@@ -1729,7 +1765,8 @@ public function nthOfQuarter(int $nth, int $dayOfWeek): static|false
17291765
* first day of the current year. Use the supplied consts
17301766
* to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
17311767
*
1732-
* @param int|null $dayOfWeek The day of the week to move to.
1768+
* @param int|null $dayOfWeek The day of the week (use Chronos::MONDAY through
1769+
* Chronos::SUNDAY), or null for a sensible default.
17331770
* @return static
17341771
*/
17351772
public function firstOfYear(?int $dayOfWeek = null): static
@@ -1745,7 +1782,8 @@ public function firstOfYear(?int $dayOfWeek = null): static
17451782
* last day of the current year. Use the supplied consts
17461783
* to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
17471784
*
1748-
* @param int|null $dayOfWeek The day of the week to move to.
1785+
* @param int|null $dayOfWeek The day of the week (use Chronos::MONDAY through
1786+
* Chronos::SUNDAY), or null for a sensible default.
17491787
* @return static
17501788
*/
17511789
public function lastOfYear(?int $dayOfWeek = null): static
@@ -1756,13 +1794,20 @@ public function lastOfYear(?int $dayOfWeek = null): static
17561794
}
17571795

17581796
/**
1759-
* Modify to the given occurrence of a given day of the week
1760-
* in the current year. If the calculated occurrence is outside the scope
1761-
* of the current year, then return false and no modifications are made.
1762-
* Use the supplied consts to indicate the desired dayOfWeek, ex. Chronos::MONDAY.
1797+
* Get the nth occurrence of a day of the week in the current year.
1798+
*
1799+
* Returns false if the requested occurrence doesn't exist in the year
1800+
* (e.g., requesting the 53rd Monday in a year with only 52).
17631801
*
1764-
* @param int $nth The offset to use.
1765-
* @param int $dayOfWeek The day of the week to move to.
1802+
* Example:
1803+
* ```
1804+
* $date = new Chronos('2024-06-15');
1805+
* $date->nthOfYear(1, Chronos::MONDAY); // First Monday of the year
1806+
* $date->nthOfYear(52, Chronos::FRIDAY); // 52nd Friday of the year
1807+
* ```
1808+
*
1809+
* @param int $nth The occurrence number (1 = first, 2 = second, etc.).
1810+
* @param int $dayOfWeek The day of the week (use Chronos::MONDAY, etc.).
17661811
* @return static|false
17671812
*/
17681813
public function nthOfYear(int $nth, int $dayOfWeek): static|false
@@ -1914,10 +1959,13 @@ public function farthest(DateTimeInterface $first, DateTimeInterface $second, Da
19141959
}
19151960

19161961
/**
1917-
* Get the minimum instance between a given instance (default now) and the current instance.
1962+
* Get the earlier of this instance and another.
19181963
*
1919-
* @param \DateTimeInterface|null $other The instance to compare with.
1920-
* @return static
1964+
* Returns whichever datetime comes first chronologically.
1965+
* If no other instance is provided, compares against the current time.
1966+
*
1967+
* @param \DateTimeInterface|null $other The instance to compare with. Defaults to now.
1968+
* @return static The earlier of the two datetimes.
19211969
*/
19221970
public function min(?DateTimeInterface $other = null): static
19231971
{
@@ -1931,10 +1979,13 @@ public function min(?DateTimeInterface $other = null): static
19311979
}
19321980

19331981
/**
1934-
* Get the maximum instance between a given instance (default now) and the current instance.
1982+
* Get the later of this instance and another.
19351983
*
1936-
* @param \DateTimeInterface|null $other The instance to compare with.
1937-
* @return static
1984+
* Returns whichever datetime comes last chronologically.
1985+
* If no other instance is provided, compares against the current time.
1986+
*
1987+
* @param \DateTimeInterface|null $other The instance to compare with. Defaults to now.
1988+
* @return static The later of the two datetimes.
19381989
*/
19391990
public function max(?DateTimeInterface $other = null): static
19401991
{
@@ -1948,10 +1999,21 @@ public function max(?DateTimeInterface $other = null): static
19481999
}
19492000

19502001
/**
1951-
* Modify the current instance to the average of a given instance (default now) and the current instance.
2002+
* Get the midpoint between this instance and another.
19522003
*
1953-
* @param \DateTimeInterface|null $other The instance to compare with.
1954-
* @return static
2004+
* Calculates the datetime that is exactly halfway between the current
2005+
* instance and the given instance. If no other instance is provided,
2006+
* uses the current time (now).
2007+
*
2008+
* Example:
2009+
* ```
2010+
* $jan1 = new Chronos('2024-01-01 00:00:00');
2011+
* $jan3 = new Chronos('2024-01-03 00:00:00');
2012+
* $midpoint = $jan1->average($jan3); // 2024-01-02 00:00:00
2013+
* ```
2014+
*
2015+
* @param \DateTimeInterface|null $other The instance to find midpoint with. Defaults to now.
2016+
* @return static The datetime exactly between this instance and the other.
19552017
*/
19562018
public function average(?DateTimeInterface $other = null): static
19572019
{
@@ -2303,14 +2365,31 @@ public function isWithinNext(string|int $timeInterval): bool
23032365
}
23042366

23052367
/**
2306-
* Get the difference by the given interval using a filter callable
2368+
* Get the difference by the given interval using a filter callback.
23072369
*
2308-
* @param \DateInterval $interval An interval to traverse by
2309-
* @param callable $callback The callback to use for filtering.
2310-
* @param \DateTimeInterface|null $other The instance to difference from.
2311-
* @param bool $absolute Get the absolute of the difference
2370+
* Iterates through the date range at the given interval and counts
2371+
* how many times the callback returns true.
2372+
*
2373+
* Example:
2374+
* ```
2375+
* // Count weekdays between two dates
2376+
* $start = new Chronos('2024-01-01');
2377+
* $end = new Chronos('2024-01-31');
2378+
* $weekdays = $start->diffFiltered(
2379+
* new DateInterval('P1D'),
2380+
* fn($date) => !$date->isWeekend(),
2381+
* $end
2382+
* );
2383+
* ```
2384+
*
2385+
* @param \DateInterval $interval An interval to traverse by (e.g., P1D for daily).
2386+
* @param callable $callback Filter function that receives each date in the range.
2387+
* Should return true to count the date, false to skip it.
2388+
* Signature: `function(Chronos $date): bool`
2389+
* @param \DateTimeInterface|null $other The end date. Defaults to now.
2390+
* @param bool $absolute Get the absolute of the difference.
23122391
* @param int $options DatePeriod options, {@see https://www.php.net/manual/en/class.dateperiod.php}
2313-
* @return int
2392+
* @return int The count of intervals where the callback returned true.
23142393
*/
23152394
public function diffFiltered(
23162395
DateInterval $interval,

0 commit comments

Comments
 (0)