Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This command is intended to be run on your computer
serve-doc:
docker run --rm -it -p 8000:8000 -v ${PWD}:/docs squidfunk/mkdocs-material

build-doc:
docker run --rm -it -v ${PWD}:/docs squidfunk/mkdocs-material build
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
[![codecov](https://codecov.io/gh/innmind/time/branch/develop/graph/badge.svg)](https://codecov.io/gh/innmind/time)
[![Type Coverage](https://shepherd.dev/github/innmind/time/coverage.svg)](https://shepherd.dev/github/innmind/time)

Description
This library allows you to handle time down to the millisecond. The point was to also be explicit for every component of dates, this is why every php _magic strings_ have been converted into objects.

**All objects are immutable.**

## Installation

Expand All @@ -14,4 +16,29 @@ composer require innmind/time

## Usage

Todo
```php
use Innmind\Time\{
Clock,
Point,
Format,
};
use Innmind\Immutable\Attempt;

$clock = Clock::live();
$now = $clock->now(); // return an instance of Point
echo $now->toString(); // 2016-10-11T12:17:30.123456+02:00

$epoch = $clock->at(
'1970-01-01T00:00:00.000000+00:00',
Format::iso8601(),
); // Attempt<Point>
```

Here we reference 2 points in time, the first is the exact moment we call `now` down to the microsecond and the second one is the epoch time.

The method `at()` accepts any string that is allowed by `\DateTimeImmutable`.

## Documentation

Full documentation is available at <https://innmind.org/time/>.

8 changes: 6 additions & 2 deletions blackbox.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Application,
Runner\Load,
Runner\CodeCoverage,
PHPUnit,
};

Application::new($argv)
Expand All @@ -15,7 +16,7 @@
static fn(Application $app) => $app->scenariiPerProof((int) \getenv('BLACKBOX_SET_SIZE')),
)
->when(
\get_env('ENABLE_COVERAGE') !== false,
\getenv('ENABLE_COVERAGE') !== false,
static fn(Application $app) => $app
->scenariiPerProof(1)
->codeCoverage(
Expand All @@ -27,5 +28,8 @@
->enableWhen(true),
),
)
->tryToProve(Load::everythingIn(__DIR__.'/proofs/'))
->tryToProve(static function() {
yield from Load::everythingIn(__DIR__.'/proofs/')();
yield from PHPUnit\Load::testsAt(__DIR__.'/tests/');
})
->exit();
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,14 @@
"issues": "http://github.com/innmind/time/issues"
},
"require": {
"php": "~8.4"
"php": "~8.4",
"innmind/immutable": "~6.0",
"psr/log": "~3.0"
},
"autoload": {
"psr-4": {
"Innmind\\Time\\": "src/"
"Innmind\\Time\\": "src/",
"Fixtures\\Innmind\\Time\\": "fixtures/"
}
},
"require-dev": {
Expand Down
Binary file added docs/assets/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/fonts/MonaspaceNeon-Regular.woff
Binary file not shown.
24 changes: 24 additions & 0 deletions docs/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
113 changes: 113 additions & 0 deletions docs/assets/stylesheets/extra.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
@font-face {
font-family: "Monaspace Neon";
font-weight: normal;
font-style: normal;
src: url("../fonts/MonaspaceNeon-Regular.woff");
}

:root {
--md-code-font: "Monaspace Neon";
}

:root {
--light-md-code-hl-number-color: #f76d47;
--light-md-code-hl-function-color: #6384b9;
--light-md-code-hl-operator-color: #39adb5;
--light-md-code-hl-constant-color: #7c4dff;
--light-md-code-hl-string-color: #9fc06f;
--light-md-code-hl-punctuation-color: #39adb5;
--light-md-code-hl-keyword-color: #7c4dff;
--light-md-code-hl-variable-color: #80cbc4;
--light-md-code-hl-comment-color: #ccd7da;
--light-md-code-bg-color: #fafafa;
--light-md-code-fg-color: #ffb62c;
--light-md-code-hl-variable-color: #6384b9;
--dark-md-code-hl-number-color: #f78c6c;
--dark-md-code-hl-function-color: #82aaff;
--dark-md-code-hl-operator-color: #89ddff;
--dark-md-code-hl-constant-color: #c792ea;
--dark-md-code-hl-string-color: #c3e88d;
--dark-md-code-hl-punctuation-color: #89ddff;
--dark-md-code-hl-keyword-color: #c792ea;
--dark-md-code-hl-variable-color: #e8f9f9;
--dark-md-code-hl-comment-color: #546e7a;
--dark-md-code-bg-color: #263238;
--dark-md-code-fg-color: #ffcb6b;
--dark-md-code-hl-variable-color: #82aaff;
}

@media (prefers-color-scheme: light) {
.language-php > * {
--md-code-hl-number-color: var(--light-md-code-hl-number-color);
--md-code-hl-function-color: var(--light-md-code-hl-function-color);
--md-code-hl-operator-color: var(--light-md-code-hl-operator-color);
--md-code-hl-constant-color: var(--light-md-code-hl-constant-color);
--md-code-hl-string-color: var(--light-md-code-hl-string-color);
--md-code-hl-punctuation-color: var(--light-md-code-hl-punctuation-color);
--md-code-hl-keyword-color: var(--light-md-code-hl-keyword-color);
--md-code-hl-variable-color: var(--light-md-code-hl-variable-color);
--md-code-hl-comment-color: var(--light-md-code-hl-comment-color);
--md-code-bg-color: var(--light-md-code-bg-color);
--md-code-fg-color: var(--light-md-code-fg-color);
}

.language-php .na {
--md-code-hl-variable-color: var(--light-md-code-hl-variable-color);
}
}

[data-md-color-media="(prefers-color-scheme: light)"] .language-php > * {
--md-code-hl-number-color: var(--light-md-code-hl-number-color);
--md-code-hl-function-color: var(--light-md-code-hl-function-color);
--md-code-hl-operator-color: var(--light-md-code-hl-operator-color);
--md-code-hl-constant-color: var(--light-md-code-hl-constant-color);
--md-code-hl-string-color: var(--light-md-code-hl-string-color);
--md-code-hl-punctuation-color: var(--light-md-code-hl-punctuation-color);
--md-code-hl-keyword-color: var(--light-md-code-hl-keyword-color);
--md-code-hl-variable-color: var(--light-md-code-hl-variable-color);
--md-code-hl-comment-color: var(--light-md-code-hl-comment-color);
--md-code-bg-color: var(--light-md-code-bg-color);
--md-code-fg-color: var(--light-md-code-fg-color);
}

[data-md-color-media="(prefers-color-scheme: light)"] .language-php .na {
--md-code-hl-variable-color: var(--light-md-code-hl-variable-color);
}

@media (prefers-color-scheme: dark) {
.language-php > * {
--md-code-hl-number-color: var(--dark-md-code-hl-number-color);
--md-code-hl-function-color: var(--dark-md-code-hl-function-color);
--md-code-hl-operator-color: var(--dark-md-code-hl-operator-color);
--md-code-hl-constant-color: var(--dark-md-code-hl-constant-color);
--md-code-hl-string-color: var(--dark-md-code-hl-string-color);
--md-code-hl-punctuation-color: var(--dark-md-code-hl-punctuation-color);
--md-code-hl-keyword-color: var(--dark-md-code-hl-keyword-color);
--md-code-hl-variable-color: var(--dark-md-code-hl-variable-color);
--md-code-hl-comment-color: var(--dark-md-code-hl-comment-color);
--md-code-bg-color: var(--dark-md-code-bg-color);
--md-code-fg-color: var(--dark-md-code-fg-color);
}

.language-php .na {
--md-code-hl-variable-color: var(--dark-md-code-hl-variable-color);
}
}

[data-md-color-media="(prefers-color-scheme: dark)"] .language-php > * {
--md-code-hl-number-color: var(--dark-md-code-hl-number-color);
--md-code-hl-function-color: var(--dark-md-code-hl-function-color);
--md-code-hl-operator-color: var(--dark-md-code-hl-operator-color);
--md-code-hl-constant-color: var(--dark-md-code-hl-constant-color);
--md-code-hl-string-color: var(--dark-md-code-hl-string-color);
--md-code-hl-punctuation-color: var(--dark-md-code-hl-punctuation-color);
--md-code-hl-keyword-color: var(--dark-md-code-hl-keyword-color);
--md-code-hl-variable-color: var(--dark-md-code-hl-variable-color);
--md-code-hl-comment-color: var(--dark-md-code-hl-comment-color);
--md-code-bg-color: var(--dark-md-code-bg-color);
--md-code-fg-color: var(--dark-md-code-fg-color);
}

[data-md-color-media="(prefers-color-scheme: dark)"] .language-php .na {
--md-code-hl-variable-color: var(--dark-md-code-hl-variable-color);
}
88 changes: 88 additions & 0 deletions docs/getting-started/clocks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Clocks

!!! success "Dependency injection"
A `Clock` should be treated as a singleton and instanciated once in your program and then passed as argument everywhere you need it in your program.

## Live

This is the clock you should use in your programs. By default it's set to the [UTC](https://en.wikipedia.org/wiki/UTC%2B00:00) [timezone](timezones.md) (no matter the configuration of your machine).

To access the current time you would do:

```php
use Innmind\TimeContinuum\{
Clock,
PointInTime,
};

$clock = Clock::live();
$point = $clock->now(); // instance of PointInTime
echo $point->toString(); // prints something like 2024-11-24T12:34:25+00:00
```

And to build a [`PointInTime`](points-in-time.md) back from a `string`:

```php
use Innmind\TimeContinuum\{
Clock,
Format,
PointInTime,
};
use Innmind\Immutable\Attempt;

$time = '2024-11-24T12:34:25+00:00';

$clock = Clock::live();
$at = $clock->at($time, Format::iso8601()); // instance of Attempt<PointInTime>
$point = $at->match(
static fn(PointInTime $point) => $point,
static fn() => null,
);
```

The `at` method returns an [`Attempt` monad](https://innmind.org/Immutable/structures/attempt/) that may contain a `PointInTime`. This is in case the `#!php $time` variable contains a value that doesn't correspond to the specified format (here `ISO8601`).

This means that the `#!php $point` variable here is an instance of `PointInTime` because the `#!php $time` value is valid. If it's invalid then `#!php $point` is `#!php null`.

## Logger

This clock will create a log everytime you call `#!php ->now()` or `#!php ->at()`.

To build this clock you need another clock (typically a live one) and a [PSR logger](https://packagist.org/packages/psr/log):

```php
use Innmind\TimeContinuum\Clock;
use Psr\Log\LoggerInterface;

$clock = Clock::logger(
Clock::live(),
/* any instance of LoggerInterface (1) */
);
```

1. Like [monolog](https://packagist.org/packages/monolog/monolog) for example.

You can then use `#!php $clock` like any other clock.

## Frozen

This clock is only useful when testing your program. It allows to specify the point in time at which your programs run.

This way you can test your program for special scenarii like a leap year, daylight saving time and so on...

```php
use Innmind\TimeContinuum\{
Clock,
Format,
};

$clock = Clock::live()
->at('2024-11-24T12:34:25+00:00', Format::iso8601())
->match(
Clock::frozen(...),
static fn(\Throwable $e) => throw $e
);
```

??? warning
Bear in mind that `#!php $clock->now()` will always return the same object. This means that if your program rely on calculating an [elapsed period](elapsed-period.md) it will always return `#!php 0`. If run in a loop you may end up with an inifinite one.
24 changes: 24 additions & 0 deletions docs/getting-started/elapsed-period.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Elapsed period

This is the number of microseconds between two [points in time](points-in-time.md).

```php
use Innmind\TimeContinuum\Clock;

$clock = Clock::live();
$start = $clock->now();
// do some stuff
$end = $clock->now();

$elapsed = $end->elapsedSince($start);
```

`$elapsed` is an instance of `#!php Innmind\TimeContinuum\ElapsedPeriod`.

This is especially useful when working with network I/O to check for timeouts.

!!! success ""
This example uses a monotonic clock internally to avoid the problem where the server clock re-synchronize and jump back in time. In this case `$end` is _technically_ before `$start` but the elapsed period is still a positive `int`.

??? info
Bear in mind that the monotonic clock only works on `PointInTime`s returned by `$clock->now()`. If `->elapsedSince()` is called on points returned by `$clock->at()` it will compare the number of microseconds since epoch.
Loading