/** * Obtains a clock that returns instants from the specified clock truncated * to the nearest occurrence of the specified duration. * <p> * This clock will only tick as per the specified duration. Thus, if the duration * is half a second, the clock will return instants truncated to the half second. * <p> * The tick duration must be positive. If it has a part smaller than a whole * millisecond, then the whole duration must divide into one second without * leaving a remainder. All normal tick durations will match these criteria, * including any multiple of hours, minutes, seconds and milliseconds, and * sensible nanosecond durations, such as 20ns, 250,000ns and 500,000ns. * <p> * A duration of zero or one nanosecond would have no truncation effect. * Passing one of these will return the underlying clock. * <p> * Implementations may use a caching strategy for performance reasons. * As such, it is possible that the start of the requested duration observed * via this clock will be later than that observed directly via the underlying clock. * <p> * The returned implementation is immutable, thread-safe and {@code Serializable} * providing that the base clock is. * * @param Clock $baseClock the base clock to base the ticking clock on, not null * @param Duration $tickDuration the duration of each visible tick, not negative, not null * @return Clock clock that ticks in whole units of the duration, not null * @throws \InvalidArgumentException if the duration is negative, or has a * part smaller than a whole millisecond such that the whole duration is not * divisible into one second * @throws ArithmeticException if the duration is too large to be represented as nanos */ public static function tick(Clock $baseClock, Duration $tickDuration) { if ($tickDuration->isNegative()) { throw new \InvalidArgumentException("Tick duration must not be negative"); } $tickNanos = $tickDuration->toNanos(); if ($tickNanos % 1000000 == 0) { // ok, no fraction of millisecond } else { if (1000000000 % $tickNanos == 0) { // ok, divides into one second without remainder } else { throw new \InvalidArgumentException("Invalid tick duration"); } } if ($tickNanos <= 1) { return $baseClock; } return new TickClock($baseClock, $tickNanos); }