Clocks
#######

.. highlight:: php

System time based
=================

.. _system_clock_class:

SystemClock
-----------

``Arokettu\Clock\SystemClock``

.. note::
    Can be installed separately as ``arokettu/system-clock``.
    See :ref:`system_clock_package`.

A basic system clock::

    <?php

    $clock = new \Arokettu\Clock\SystemClock();
    // optionally with a timezone
    $clock = new \Arokettu\Clock\SystemClock(new DateTimeZone('Europe/Tallinn'));

    $clock->now(); // whatever time is now

ShiftedClock
------------

``Arokettu\Clock\ShiftedClock``

A system clock with a constant time shift::

    <?php

    $shift = DateInterval::createFromDateString('1 week ago');
    $clock = new \Arokettu\Clock\ShiftedClock($shift);
    // optionally with a timezone
    $clock = new \Arokettu\Clock\ShiftedClock($shift, new DateTimeZone('Europe/Tallinn'));
    // shorter form
    $clock = \Arokettu\Clock\ShiftedClock::fromDateString('1 week ago', new DateTimeZone('Europe/Tallinn'));

    $clock->now(); // exactly a week ago

Abstract time based
===================

StaticClock
-----------

.. versionchanged:: 1.6/2.6 Float timestamps are accepted

``Arokettu\Clock\StaticClock``

Returns a specific time that can be changed manually::

    <?php

    $clock = new \Arokettu\Clock\StaticClock(); // 'now'
    // or a specific time
    $clock = new \Arokettu\Clock\StaticClock(new DateTimeImmutable('2007-01-01'));
    // or short
    $clock = \Arokettu\Clock\StaticClock::fromDateString('2007-01-01');
    // or timestamp
    $clock = \Arokettu\Clock\StaticClock::fromTimestamp(1167609600);

    $clock->now(); // happy new 2007

    $clock->set(new DateTimeImmutable('2015-10-21')); // back to the future

MutableClock
------------

.. versionchanged:: 1.6/2.6 Float timestamps are accepted

``Arokettu\Clock\MutableClock``

A clock that exposes a regular mutable DateTime that can be manipulated::

    <?php

    // initialize by 'now'
    $clock = new \Arokettu\Clock\MutableClock();
    // initialize by date time
    $clock = new \Arokettu\Clock\MutableClock(new DateTimeImmutable());
    // initialize by expression
    $clock = \Arokettu\Clock\MutableClock::fromDateString('yesterday');
    // initialize by timestamp
    $clock = \Arokettu\Clock\MutableClock::fromTimestamp(1_500_000_000);
    // attach to a DateTime instance
    $dateTime = new DateTime();
    $clock = (new \Arokettu\Clock\MutableClock())->setInstance($dateTime);

    // use the attached instance
    $dateTime->setDate(2022, 03, 03);
    $dateTime->setTime(12, 00, 00);

    $clock->now(); // 2022-03-03T12:00:00

    // or use the exposed property

    $clock->dateTime->modify('+1 day');

    $clock->now(); // 2022-03-03T12:00:00

TickingClock
------------

``Arokettu\Clock\TickingClock``

A clock that advances for a DateInterval value on every call::

    <?php

    $step = DateInterval::createFromDateString('+1 minute');
    // move forward by 1 minute from now
    $clock = new \Arokettu\Clock\TickingClock($step);
    // same thing in 1 step
    $clock = \Arokettu\Clock\TickingClock::fromDateString('+1 minute');

    // optionally with an initial time
    $time = new DateTime('2022-02-03 12:34');
    // move forward by 1 minute from 2022-02-03 12:34:00
    $clock = new \Arokettu\Clock\TickingClock($step, $time);
    // same thing in 1 step
    $clock = \Arokettu\Clock\TickingClock::fromDateString('+1 minute', '2022-02-03 12:34');

    $clock->now(); // 2022-02-03T12:34:00
    $clock->now(); // 2022-02-03T12:35:00

CallbackClock
-------------

``Arokettu\Clock\CallbackClock``

A clock that returns any time generated by a closure::

    <?php

    // simple callback
    $clock = new \Arokettu\Clock\CallbackClock(function () {
        return new DateTimeImmutable();
    });
    // generator also supported
    $clock = new \Arokettu\Clock\CallbackClock(function () {
        while (true) {
            yield new DateTimeImmutable();
        }
    });
    // a way to pass an iterable
    $values = [
        new DateTimeImmutable(),
        new DateTimeImmutable(),
        new DateTimeImmutable(),
    ];
    $clock = new \Arokettu\Clock\CallbackClock(fn () => yield from $values);

    $clock->now(); // whatever callback returns

.. note:: You can do a similar logic without any library by using an anonymous class:

::

    <?php

    $clock = new class implements \Psr\Clock\ClockInterface {
        public function now(): DateTimeImmutable
        {
            // your logic here
        }
    };

Wrappers
========

Rounding clock
--------------

.. versionadded:: 1.1/2.1

``Arokettu\Clock\RoundingClock``

A clock that can truncate another clock to a certain precision::

    <?php

    use Arokettu\Clock\RoundingClock;
    use Arokettu\Clock\StaticClock;

    $innerClock = new StaticClock(new DateTime('2012-03-04 5:06:07.899999'));

    // round to milliseconds
    $clock = new RoundingClock($innerClock, RoundingClock::ROUND_MILLISECONDS);
    // same as
    $clock = RoundingClock::toMilliseconds($innerClock);
    echo $clock->now()->format('c \\m\\s: u'), PHP_EOL; // 2012-03-04T05:06:07+00:00 ms: 899000

    // round to weeks
    $clock = new RoundingClock($innerClock, RoundingClock::ROUND_WEEKS);
    // same as
    $clock = RoundingClock::toWeeks($innerClock);
    echo $clock->now()->format('c'), PHP_EOL; // 2012-02-27T00:00:00+00:00, nearest Monday

Supported precisions:

* microseconds (``RoundingClock::ROUND_MICROSECONDS``)
* milliseconds (``RoundingClock::ROUND_MILLISECONDS``)
* seconds (``RoundingClock::ROUND_SECONDS``)
* minutes (``RoundingClock::ROUND_MINUTES``)
* hours (``RoundingClock::ROUND_HOURS``)
* days (``RoundingClock::ROUND_DAYS``)
* ISO weeks (``RoundingClock::ROUND_WEEKS``)
* months (``RoundingClock::ROUND_MONTHS``)
* calendar years (``RoundingClock::ROUND_YEARS``)
* ISO years (``RoundingClock::ROUND_ISO_YEARS``)

Offset Clock
------------

.. versionadded:: 1.5/2.5

``Arokettu\Clock\OffsetClock``

A wrapper clock with a constant time shift::

    <?php

    use Arokettu\Clock\OffsetClock;
    use Arokettu\Clock\StaticClock;

    $shift = DateInterval::createFromDateString('1 week ago');
    $clock = new OffsetClock(new StaticClock(), $shift);
    // or
    $clock = OffsetClock::fromDateString(new StaticClock(), '1 week ago');

    $clock->now(); // exactly a week ago

Replaceable Clock
-----------------

.. versionadded:: 1.7/2.7

``Arokettu\Clock\ReplaceableClock``

A wrapper that allows you to replace the inner clock.

    <?php

    use Arokettu\Clock\ReplaceableClock;
    use Arokettu\Clock\StaticClock;
    use Arokettu\Clock\SystemClock;

    $clock = new ReplaceableClock(new SystemClock());

    $clock->now(); // actual system time

    $clock->setInnerClock(new StaticClock());

    $clock->now(); // the time is now fixed
    $clock->now(); // the time is now fixed
    $clock->now(); // the time is now fixed
