Skip to content

Commit b3b3652

Browse files
authored
Merge pull request #1230 from heiglandreas/modifyMetaDoc
Modify meta doc
2 parents d82fd79 + 7176ea4 commit b3b3652

File tree

1 file changed

+33
-40
lines changed

1 file changed

+33
-40
lines changed

proposed/clock-meta.md

Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,19 @@
22

33
## 1. Summary
44

5-
The purpose of using the `ClockInterface` is to provide a standard way to access the system
6-
time, that would allow interopability when testing code that relies on the current time
7-
rather than relying on installing PHP extensions or use hacks like re-declaring the `time()`
8-
function in other namespaces.
5+
Getting the current time in applications is typically achieved using the `time()` or `microtime` functions, or by using a `new \DateTimeImmutable()` class.
6+
7+
Due to the nature of time progression these methods cannot be used when predictable results are needed, such as during testing.
8+
9+
This `ClockInterface` aims to provide a standard way to consume time that allows interoperability not only when consuming the "real" time but also when predictable results need to be available. This avoids the need to use PHP extensions for testing or redeclare the `time()` function in a local namespace.
910

1011
## 2. Why Bother?
1112

12-
There are currently a few libraries that provide this functionality, however
13-
there is no interopability between these different libraries, as they ship with their own
14-
clock interfaces. Symfony provides a package called `symfony/phpunit-bridge` that has a
15-
`Symfony\Bridge\PhpUnit\ClockMock` class, which allows mocking PHP's built-in time & date
16-
functions, however this does not solve mocking calls to `new \DateTimeImmutable()`. It does
17-
not fully mock time when called from other libraries that rely on the system time.
18-
`Cake\Chronos\Chronos` does provide mocking, however it is set via a global (static class
19-
property), and this has its own pitfalls as it provides no isolation.
13+
There are currently a few libraries that provide this functionality, however there is no interopability between these different libraries, as they ship with their own clock interfaces.
14+
15+
Symfony provides a package called `symfony/phpunit-bridge` that has a `Symfony\Bridge\PhpUnit\ClockMock` class, which allows mocking PHP's built-in time and date functions, however this does not solve mocking calls to `new \DateTimeImmutable()`. It also does not fully mock time when called from other libraries that rely on the system time.
16+
17+
`Carbon\Carbon`, and its fork `Cake\Chronos\Chronos`, do provide mocking via a static `setTestNow()` method, but this provides no isolation and must be called again to stop mocking.
2018

2119
Pros:
2220

@@ -41,17 +39,36 @@ calling `time()` or `date()`.
4139
described in this document, so it is not a coding standard;
4240
* This PSR does not provide a recommendation on how to handle timezones when
4341
retrieving the current time. This is left up to the implementation.
42+
* This PSR does not handle any scheduling methods like `sleep()` or `wait()` because such methods are not related to retrieving the current time.
4443

4544
## 4. Approaches
4645

4746
### 4.1 Chosen Approach
4847

49-
We have decided to formalize the existing practices, used by several other packages
50-
out in the wild. Some of the popular packages providing this functionality are:
51-
`lcobucci/clock`, `kreait/clock`, `ergebnis/clock`, and `mangoweb/clock`. Some providing
52-
interfaces, and some relying on overloading (extending) the Clock class to mock the
48+
We have decided to formalize the existing practices used by several other packages. Some popular packages providing this functionality are:
49+
50+
* [`lcobucci/clock`](https://packagist.org/packages/lcobucci/clock)
51+
* [`kreait/clock`](https://packagist.org/packages/kreait/clock)
52+
* [`ergebnis/clock`](https://packagist.org/packages/ergebnis/clock)
53+
* [`mangoweb/clock`](https://packagist.org/packages/mangoweb/clock)
54+
55+
(This list is not exhaustive!)
56+
57+
Some of these provide interfaces and some rely on extending a clock class to mock the
5358
current time.
5459

60+
These implementations all provide a `now()` method which returns a `DateTimeImmutable` object. As the `DateTimeImmutable` object allows retrieving the Unix timestamp, by calling `getTimestamp()` or `format('u.U')`, this interface does not define any special methods to retrieve a Unix timestamp or any other time information that is not available from a `DateTimeImmutable` object.
61+
62+
### 4.2 Timezones
63+
64+
Time by now is defined by interaction of electromagnetic radiation with the excited states of certain atoms where the SI defines one second as the duration of 9192631770 cycles of radiation corresponding to the transition between two energy levels of the ground state of the caesium-133 atom at 0K. This means that retrieving the current time will always return the same time, no matter where it is observed. While the timezone defines *where* the time was observed it does not modify the actual "slice" of time.
65+
66+
This means that for the sake of this PSR the timezone is considered an implementation detail of the interface.
67+
68+
It is up to the implementation to make sure that the timezone is handled according to the business logic of the application. That is either by making sure that a call to `now()` will only return a `DateTimeImmutable` object with a known timezone (implicit contract) or by explicitly changing the timezone to be correct for the application. This can be done by calling `setTimezone()` to create a new `DateTimeImmutable` object with the given timezone.
69+
70+
These actions are not defined in this interface.
71+
5572

5673
### 4.2 Example Implementations
5774

@@ -64,25 +81,6 @@ final class SystemClock implements \Psr\Clock\ClockInterface
6481
}
6582
}
6683

67-
//
68-
69-
final class UTCClock implements \Psr\Clock\ClockInterface
70-
{
71-
private \DateTimeZone $utcTimeZone;
72-
73-
public function __construct()
74-
{
75-
$this->utcTimeZone = new \DateTimeZone('UTC');
76-
}
77-
78-
public function now(): \DateTimeImmutable
79-
{
80-
return new \DateTimeImmutable('now', $this->utcTimeZone);
81-
}
82-
}
83-
84-
//
85-
8684
final class FrozenClock implements \Psr\Clock\ClockInterface
8785
{
8886
private \DateTimeImmutable $now;
@@ -96,11 +94,6 @@ final class FrozenClock implements \Psr\Clock\ClockInterface
9694
{
9795
return clone $this->now;
9896
}
99-
100-
public function advance(DateInterval $interval): void
101-
{
102-
$this->now = $this->now->add($interval);
103-
}
10497
}
10598

10699
```

0 commit comments

Comments
 (0)