# CakePHP Chronos for Immutable PHP Date Handling

> CakePHP Chronos is a standalone PHP library for immutable date, datetime, calendar-date, and time-only values. It provides focused objects for predictable time handling, test clocks, PSR-20 integration, and schedules, while diverging from Carbon rather than extending PHP's native date classes.

**cakephp/chronos** — A standalone DateTime library originally based off of Carbon

- Repository: https://github.com/cakephp/chronos
- Website: http://book.cakephp.org/chronos
- Stars: 1,362 · Forks: 71
- Language: PHP
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/cakephp-chronos

## Why Chronos Exists in PHP Applications

Chronos addresses a specific class of PHP application errors: date values changing when code did not intend to change them. It is aimed at developers who need date and time objects as application values rather than mutable values that can be altered by any code holding a reference. The library is standalone and does not depend on CakePHP's wider framework stack. Its primary focus is immutable date and datetime behavior.

The README identifies immutable objects as the central design choice. In an immutable model, an operation such as adding hours produces a new object. The original value remains available for callers that still need it. This is particularly relevant when a date is passed through services, jobs, form handlers, or persistence code, because an accidental modification can otherwise affect code outside the immediate expression that performed it.

Chronos covers several related value types rather than treating every scheduling need as the same problem. `Chronos` represents a date and time, `ChronosDate` represents a calendar date with its time fixed at `00:00:00`, and `ChronosTime` represents a time without a date. That separation gives an application a clearer vocabulary for recurring schedules, business hours, calendar records, and timestamped events. The choice is about preventing a date with an irrelevant time component from being treated as a full datetime.

## Chronos Immutable Object Model and Data Flow

The central data flow is reassignment. A `Chronos` instance is created from a date string, and a modification returns a new object. The README makes the distinction explicit:

```php
<?php
use Cake\Chronos\Chronos;

$date = new Chronos('2015-10-21 16:29:00');
$date = $date->modify('+2 hours');
```

The returned value contains the modification, while the original object is not changed. The README also shows the pattern that loses modifications:

```php
<?php
use Cake\Chronos\Chronos;

$date = new Chronos('2015-10-21 16:29:00');
$date->modify('+2 hours');
```

Because the result of the second `modify()` call is not assigned, the code does not retain the changed value. This is a migration concern for developers accustomed to mutable date objects. Existing code must be reviewed for every place where a modification is called without being reassigned.

Chronos does not extend PHP's `DateTime` or `DateTimeImmutable` classes. That is a material difference from the project's earlier Carbon-compatible direction and from PHP applications that depend on native `DateTime` inheritance. Code expecting a native `DateTime` instance, or relying on methods inherited from it, needs inspection before migration.

The library also provides a clock boundary for dependency injection. `ClockFactory` implements PSR-20 and returns a `Chronos` instance from `now()`. This lets services receive time through an injected interface instead of calling a global time source directly. The README does not document broader compatibility guarantees for every PSR-20 implementation, so the documented `ClockFactory` example is the relevant integration point.

## Calendar Dates, Time-Only Values, and Test Clocks

PHP's native extension exposes datetime objects, while Chronos adds separate conveniences for calendar and time-only data. `ChronosDate` freezes its time to `00:00:00` and uses the server default timezone. The documented example demonstrates why this type differs from `Chronos`: modifying a `ChronosDate` by three hours still prints the same calendar date because the time component is not part of the intended value.

```php
<?php
use Cake\Chronos\ChronosDate;

$today = new ChronosDate();
echo $today;
// Outputs '2015-10-21'

echo $today->modify('+3 hours');
// Outputs '2015-10-21'
```

`ChronosDate` is therefore a reasonable choice for values such as a due date, a service day, or a date in a calendar-oriented API where carrying a timestamp would create ambiguity. The server default timezone is part of the documented behavior, so applications with multiple deployment environments should account for that setting rather than assuming a stored UTC timezone.

`ChronosTime` handles values where the date is irrelevant. It supports formatting, creation from components, and arithmetic:

```php
<?php
use Cake\Chronos\ChronosTime;

$time = new ChronosTime('14:30:00');
echo $time->format('g:i A'); // 2:30 PM

$time = ChronosTime::create(14, 30, 0);
$later = $time->addHours(2)->addMinutes(15);
```

For tests, `Chronos::setTestNow()` freezes the value returned by `now()`. Passing `null` resets it to real time. This is useful for deterministic assertions, but it also means tests must clean up the override when they share process state. The README documents reset behavior but does not describe automatic cleanup.

## Installing Chronos and Making the First Call

Chronos is installed through Composer. The README gives the package command directly:

```bash
composer require cakephp/chronos
```

The README links to a version map for minimum and maximum PHP versions, but it does not state those versions in its installation section. Check that version map before selecting a release. After installation, the documented first use loads Composer's autoloader and creates the current value:

```php
<?php
require 'vendor/autoload.php';

use Cake\Chronos\Chronos;

printf("Now: %s", Chronos::now());
```

This example calls `Chronos::now()` and prints the result with `printf()`. It is a real first call against the library, but it does not specify a timezone or a frozen test time. If a process must produce UTC values consistently, the application should establish its timezone policy explicitly rather than infer one from this example.

For dependency injection, the README uses `ClockFactory`:

```php
<?php
use Cake\Chronos\ClockFactory;

$clock = new ClockFactory('UTC');
$now = $clock->now();
```

The constructor receives `UTC`, and `now()` returns a `Chronos` instance. In a service, the README shows a constructor parameter typed as `ClockInterface`, followed by `createOrder()` calling `$this->clock->now()`. The exact service and `Order` definitions are not included in the example, so the snippet is a usage pattern rather than a complete application.

The repository also contains a `Dockerfile`, but it is configured to build the documentation site with Node.js and serve the generated files through Angie on port `80`. It is not presented as an application image for installing Chronos into a PHP service.

## Chronos Limitations Compared with Carbon and Native PHP Dates

The clearest limitation is compatibility. The README states that Chronos was originally compatible with Carbon but has diverged and no longer extends PHP's `DateTime` and `DateTimeImmutable` classes. A migration therefore needs more than changing a namespace. Code that checks `instanceof DateTime`, passes a Chronos object to an API requiring a native PHP date, or relies on inherited native methods cannot be assumed to work unchanged.

Chronos was originally compatible with Carbon but has diverged. Chronos instead offers a separate object family with immutable semantics and dedicated calendar and time-only types. The practical difference is the relationship between the returned object type and PHP's native class hierarchy, plus the expectations carried by code written for Carbon.

Chronos is also a poor fit for code that intentionally relies on in-place mutation. Its design requires developers to retain the result of operations such as `modify()`. Ignoring that return value does not produce the changed timestamp. This is intentional for predictability, but it creates review work and can expose old bugs in code migrating from mutable objects.

The README does not document a migration command, automatic Carbon compatibility layer, database serialization format, or rollback procedure. It links to version 3 documentation and API documentation, so those are the appropriate places to verify behavior beyond the examples here. The repository states an MIT license. This review does not interpret the license terms or provide legal advice.

## Maintenance Signals and Upgrade Surface

The repository is not archived. Its last push was on 2026-10-16, and the release history includes Chronos 3.5.1 on 2026-09-06, 3.5.0 on 2026-04-10, and 3.4.0 on 2026-03-25. Those dates show repository activity, but they do not describe compatibility between releases or the scope of future maintenance.

The default branch is `3.x`, while the README's build badge refers to `master`. That difference should be checked before interpreting CI status or assuming that documentation on one branch exactly describes the other. The repository contains `composer.json`, PHPUnit configuration, PHPStan configuration, PHP_CodeSniffer configuration, Rector configuration, tests, and documentation. Based on the repository layout, Chronos has a conventional library test and analysis setup, but the README does not state the exact upgrade procedure or migration policy for consumers.

Upgrading can involve more than replacing a package version. Consumers should check PHP compatibility through the linked version map, review changes in the release notes for the selected branch, and search their codebase for ignored immutable return values. Code that depends on native `DateTime` inheritance needs particular attention because that relationship has been removed.

## Choosing Chronos for a PHP Service

Chronos is suited to services that value explicit value objects and can make immutable reassignment part of their coding conventions. It is especially relevant where calendar dates must not gain accidental time information, where recurring schedules need a date-free time type, where tests need a controllable clock, or where PSR-20 dependency injection is already part of the application design. The available object types give teams a way to distinguish `Chronos`, `ChronosDate`, and `ChronosTime` instead of forcing every schedule into one datetime value.

It is less suitable for projects that require transparent compatibility with PHP's native date classes or Carbon's established API. It is also less suitable when a large codebase depends on in-place mutation and cannot be reviewed and updated. The README does not provide migration or rollback instructions, so those projects should inspect the version 3 documentation and API pages before selecting Chronos.

The first checks are concrete: confirm the PHP version supported by the chosen release, locate every call whose immutable result is currently discarded, inspect type declarations requiring `DateTime` or `DateTimeImmutable`, and confirm the intended timezone policy. After those checks, Chronos fits PHP code that wants immutable dates, calendar dates, time-only values, test clocks, and PSR-20 injection in one focused library.

## Conclusion

Choose Chronos when your PHP application needs immutable date and time values, especially for calendar dates, schedules, predictable tests, or PSR-20 clock injection. Do not choose it as a drop-in Carbon replacement, because Chronos no longer extends PHP's DateTime or DateTimeImmutable classes. Verify the PHP version supported by the selected Chronos release, confirm that immutable reassignment fits your code style, and review the handling of timezone and time-only values before adoption.

## FAQ

### How do I install cakephp/chronos in PHP?

The README documents Composer installation with `composer require cakephp/chronos`. It links to a version map for the minimum and maximum PHP versions, but those exact versions are not included in the installation section.

### What is the difference between Chronos and nesbot/carbon?

Chronos was originally compatible with Carbon, but the README says it has diverged and no longer extends PHP's `DateTime` and `DateTimeImmutable` classes. Code that depends on Carbon or native PHP date inheritance should not be assumed to be compatible without review.

### How does Chronos handle immutable date modifications?

An operation such as `modify()` returns a modified Chronos object, so the caller must assign the result. The README warns that calling `$date->modify('+2 hours')` without assigning it loses the modification.

## Sources

- [cakephp/chronos on GitHub](https://github.com/cakephp/chronos)
- [License: MIT](https://github.com/cakephp/chronos/blob/3.x/LICENSE)
- [Project website](http://book.cakephp.org/chronos)
- [README](https://github.com/cakephp/chronos/blob/3.x/README.md)
- [Releases](https://github.com/cakephp/chronos/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cakephp-chronos
