Skip to content

Commit d994972

Browse files
authored
Add ChronosInterval class (#495)
* Add ChronosInterval class Implements a DateInterval wrapper using the decorator pattern as discussed. This addresses the need for a proper interval class with: - ISO 8601 duration string formatting via __toString() - Factory methods: create(), createFromValues(), instance() - toNative() for compatibility with code expecting DateInterval - Convenience methods: totalSeconds(), totalDays(), isNegative(), isZero() - Property access proxy to underlying DateInterval Related to #444 * Add @phpstan-consistent-constructor annotation Fixes PHPStan level 8 'Unsafe usage of new static()' errors. * Add arithmetic methods, createFromDateString and toDateString - add() and sub() methods for combining intervals - createFromDateString() factory wrapping DateInterval method - toDateString() for strtotime-compatible output format * Fix CS * Add documentation for ChronosInterval class Document the new ChronosInterval wrapper class including: - Factory methods (create, createFromValues, createFromDateString, instance) - Property access for DateInterval fields - Formatting methods (toIso8601String, format, toDateString) - Calculation methods (totalSeconds, totalDays) - State checking (isZero, isNegative) - Arithmetic (add, sub) - Native interop (toNative)
1 parent c6816fd commit d994972

File tree

3 files changed

+841
-0
lines changed

3 files changed

+841
-0
lines changed

docs/en/index.rst

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Chronos provides a zero-dependency ``DateTimeImmutable`` extension, Date-only an
66
* ``Cake\Chronos\Chronos`` extends ``DateTimeImmutable`` and provides many helpers.
77
* ``Cake\Chronos\ChronosDate`` represents calendar dates unaffected by time or time zones.
88
* ``Cake\Chronos\ChronosTime`` represents clock times independent of date or time zones.
9+
* ``Cake\Chronos\ChronosInterval`` wraps ``DateInterval`` with ISO 8601 formatting and convenience methods.
910
* Only safe, immutable objects.
1011
* A pluggable translation system. Only English translations are included in the
1112
library. However, ``cakephp/i18n`` can be used for full language support.
@@ -223,6 +224,105 @@ timeline::
223224
// Difference from another point in time.
224225
echo $date->diffForHumans($other); // 1 hour ago;
225226

227+
Interval Objects
228+
----------------
229+
230+
PHP's ``DateInterval`` class represents a duration of time, but lacks convenient
231+
methods for formatting and manipulation. Chronos provides ``ChronosInterval``
232+
which wraps ``DateInterval`` using the decorator pattern, adding ISO 8601 duration
233+
formatting and useful convenience methods::
234+
235+
use Cake\Chronos\ChronosInterval;
236+
237+
// Create from an ISO 8601 duration spec
238+
$interval = ChronosInterval::create('P1Y2M3D');
239+
echo $interval; // "P1Y2M3D"
240+
241+
// Create from individual values using named arguments
242+
$interval = ChronosInterval::createFromValues(hours: 2, minutes: 30);
243+
echo $interval; // "PT2H30M"
244+
245+
// Create from a relative date string
246+
$interval = ChronosInterval::createFromDateString('1 year + 3 days');
247+
248+
// Wrap an existing DateInterval
249+
$diff = $date1->diff($date2);
250+
$interval = ChronosInterval::instance($diff);
251+
252+
``ChronosInterval`` proxies all standard ``DateInterval`` properties::
253+
254+
$interval = ChronosInterval::create('P1Y2M3DT4H5M6S');
255+
echo $interval->y; // 1
256+
echo $interval->m; // 2
257+
echo $interval->d; // 3
258+
echo $interval->h; // 4
259+
echo $interval->i; // 5
260+
echo $interval->s; // 6
261+
echo $interval->invert; // 0
262+
263+
When working with code that requires a native ``DateInterval``, use ``toNative()``::
264+
265+
$interval = ChronosInterval::create('P1D');
266+
someFunctionExpectingDateInterval($interval->toNative());
267+
268+
Formatting Intervals
269+
~~~~~~~~~~~~~~~~~~~~
270+
271+
``ChronosInterval`` provides multiple ways to format intervals::
272+
273+
$interval = ChronosInterval::createFromValues(years: 1, months: 2, days: 3, hours: 4);
274+
275+
// ISO 8601 duration (also used by __toString)
276+
echo $interval->toIso8601String(); // "P1Y2M3DT4H"
277+
echo $interval; // "P1Y2M3DT4H"
278+
279+
// Standard DateInterval formatting
280+
echo $interval->format('%y years, %m months, %d days');
281+
282+
// Human-readable relative format
283+
echo $interval->toDateString(); // "1 year 2 months 3 days 4 hours"
284+
285+
Interval Calculations
286+
~~~~~~~~~~~~~~~~~~~~~
287+
288+
You can get totals from intervals::
289+
290+
$interval = ChronosInterval::createFromValues(days: 2, hours: 12);
291+
292+
// Approximate total seconds (uses 30 days/month, 365 days/year)
293+
echo $interval->totalSeconds(); // 216000
294+
295+
// Total days (exact if created from diff(), otherwise approximated)
296+
echo $interval->totalDays(); // 2
297+
298+
Interval State
299+
~~~~~~~~~~~~~~
300+
301+
Check the state of an interval::
302+
303+
$interval = ChronosInterval::create('PT0S');
304+
$interval->isZero(); // true
305+
306+
$past = Chronos::now()->diff(Chronos::yesterday());
307+
ChronosInterval::instance($past)->isNegative(); // depends on order of diff
308+
309+
Interval Arithmetic
310+
~~~~~~~~~~~~~~~~~~~
311+
312+
You can add and subtract intervals::
313+
314+
$interval1 = ChronosInterval::createFromValues(hours: 2);
315+
$interval2 = ChronosInterval::createFromValues(hours: 1, minutes: 30);
316+
317+
$sum = $interval1->add($interval2);
318+
echo $sum; // "PT3H30M"
319+
320+
$diff = $interval1->sub($interval2);
321+
echo $diff; // "PT0H30M"
322+
323+
Note: Arithmetic performs simple component addition/subtraction without
324+
normalization (e.g., 70 minutes stays as 70 minutes rather than 1 hour 10 minutes).
325+
226326
Formatting Strings
227327
------------------
228328

0 commit comments

Comments
 (0)