PHPackages                             digital-craftsman/datetime-parts - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. digital-craftsman/datetime-parts

Abandoned → [digital-craftsman/date-time-precision](/?search=digital-craftsman%2Fdate-time-precision)Symfony-bundle[Utility &amp; Helpers](/categories/utility)

digital-craftsman/datetime-parts
================================

A Symfony bundle for more precise date and time handling through value objects

0.14.0(1mo ago)03.2k[5 issues](https://github.com/digital-craftsman-de/date-time-precision/issues)[2 PRs](https://github.com/digital-craftsman-de/date-time-precision/pulls)MITPHPPHP 8.4.\*|8.5.\*CI passing

Since Oct 7Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/digital-craftsman-de/date-time-precision)[ Packagist](https://packagist.org/packages/digital-craftsman/datetime-parts)[ RSS](/packages/digital-craftsman-datetime-parts/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (16)Versions (30)Used By (0)

Using `DateTime` with precision
===============================

[](#using-datetime-with-precision)

The only class in the PHP SPL to work with dates and times is `DateTime` (and it's immutable counterpart). It represents a specific moment in time in a specific timezone (whether that timezone/offset is explicitly defined or not). Unfortunately dates are complex and there is more than just a moment in time. For example there are

- time of day which is relevant on every day (like business hours).
- a specific date (like Christmas) which isn't bound to a timezone.
- a subset of a date time like time, date, month or year.

Basically, every time you're not talking about a specific moment, the `DateTime` classes contain not just more informationen then needed, but even misleading information.

This bundle / package tries to solve this issue by introducing a wrapper value object `Moment` for a moment in time and value objects for the more precise sub sets like `Time`, `Date`, `Month` and `Year`. It's only a thin wrapper over `DateTime` and uses it internally for all modifications and comparisons. This way you don't have to make sure that your `DateTime` is

- at a specific date to compare times.
- at midnight to compare dates.
- at the first of the month to compare months.
- at the first of the year to compare years.

Additionally, the package provides a streamlined way to have the system running in `UTC` but still do the modifications in the relevant timezone. The internal `DateTime` is always in `UTC` and only internally converted to the relevant timezone for modifications. This way you can be sure that you're not missing or receiving an hour due to a switch of summer-time to winter-time in the relevant timezone.

There are also classes like `Day` or `Weekday` and collections like `Days` or `Weekdays`.

This Symfony bundle includes Symfony normalizers for automatic normalization and denormalization and Doctrine types to store the objects directly in the database.

As it's a central part of an application, it's tested thoroughly (including mutation testing). Currently, more than 80% of the lines of code in this repository are tests.

[![Latest Stable Version](https://camo.githubusercontent.com/3f0ad91bee56cb808c6e0c38c5204496082499f303b85f6fc61fd8a7f7ca7cf3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f737461626c652d302e31342e302d626c7565)](https://packagist.org/packages/digital-craftsman/date-time-precision)[![PHP Version Require](https://camo.githubusercontent.com/2f2005e31dc46e3c057be679d712cd9c4486aafcd26810f33ab48992af8d4971/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d382e34253743382e352d356235643935)](https://packagist.org/packages/digital-craftsman/date-time-precision)[![codecov](https://camo.githubusercontent.com/e8d0220dc3221bcc4bc8b1599a06087f1c7c37b16e506d88780385ab8132908f/68747470733a2f2f636f6465636f762e696f2f67682f6469676974616c2d6372616674736d616e2d64652f646174652d74696d652d707265636973696f6e2f6272616e63682f6d61696e2f67726170682f62616467652e7376673f746f6b656e3d765a3049764b506a3266)](https://codecov.io/gh/digital-craftsman-de/date-time-precision)[![Packagist Downloads](https://camo.githubusercontent.com/a6c52d52d057ba6b1bb4e1d46866d201c99aec5ea1827581e53de18be0c68c02/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6469676974616c2d6372616674736d616e2f646174652d74696d652d707265636973696f6e)](https://camo.githubusercontent.com/a6c52d52d057ba6b1bb4e1d46866d201c99aec5ea1827581e53de18be0c68c02/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6469676974616c2d6372616674736d616e2f646174652d74696d652d707265636973696f6e)[![Packagist License](https://camo.githubusercontent.com/9af058e800631c909447bc64a3fff5d1ccaac0e6d0d89a2d4a43db26b1369722/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6469676974616c2d6372616674736d616e2f646174652d74696d652d707265636973696f6e)](https://camo.githubusercontent.com/9af058e800631c909447bc64a3fff5d1ccaac0e6d0d89a2d4a43db26b1369722/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6469676974616c2d6372616674736d616e2f646174652d74696d652d707265636973696f6e)

Installation and configuration
------------------------------

[](#installation-and-configuration)

Install package through composer:

```
composer require digital-craftsman/date-time-precision
```

> ⚠️ This bundle can be used (and is being used) in production, but hasn't reached version 1.0 yet. Therefore, there will be breaking changes between minor versions. I'd recommend that you require the bundle only with the current minor version like `composer require digital-craftsman/date-time-precision:0.14.*`. Breaking changes are described in the releases and [the changelog](./CHANGELOG.md). Updates are described in the [upgrade guide](./UPGRADE.md).

When would I need that?
-----------------------

[](#when-would-i-need-that)

Basically whenever you use a `DateTime` object for something other than a single moment.

Storing more information in those cases just lead to more questions, like "When storing the month, do we store the first day of month at midnight, and if so, in which time zone?" and therefore increases complexity. Additionally, you need mutate or reduce the point in time to be able to compare it. With the package it will be as easy as:

```
if ($now->isBeforeInTimeZone($facility->openFrom, $facilityTimeZone)) {
    throw new FacilityIsNotOpenYet();
}
```

`$now` is a `Moment` (in UTC) and `$facility->openFrom` is a `Time` (in the timezone of the facility).

The idea is that your system can run in `UTC` and all moments are in the timezone `UTC`. But all values that have an implicit time zone like a date or a time of day will be stored with just the data needed. This way we're getting rid of additional data that creates more surface for possible bugs. Through precise value objects and specific comparison functions, the code is more readable than before.

```
if ($now->isBeforeInTimeZone($facility->earliestDayOfBooking)) {
    throw new BookingNotPossibleYet();
}
```

`$now` is a `Moment` (in UTC) and `$facility->earliestDayOfBooking` is a `Date` (in the timezone of the facility). The same method `isBeforeInTimeZone` that is used previously for the time comparison is the same that is used here. Depending on the type of the second parameter, the comparison is done on the relevant part of the moment.

Modifications work the same way.

```
$bookingsAllowedFrom = $now->modifyInTimeZone('+ 7 days', $facilityTimeZone);
```

The resulting `$bookingsAllowedFrom` is still a date time with timezone `UTC` but the modification is done in the relevant timezone.

Integration
-----------

[](#integration)

For the best code readability, it's best to use the `Moment` provided with the package as a full replacement for `\DateTime` or `\DateTimeImmutable` when you're speaking about a moment in time and the others value objects for the rest. The package integrates with the normalizers of `digital-craftsman/self-aware-normalizers` and provides Doctrine types (that use those interfaces) for `Moment` and all parts.

The value objects implement the relevant interfaces for the doctrine types and therefore can be used directly in your doctrine entities like the following:

```
