# clock

`software.visionary:clock:2026.10.13` · https://codeberg.org/javanese/clock

Clock: the time as a seam, monotonic clocks, and Hybrid Logical Clocks

Clocks a test can drive: <code>Clockwork</code> reads the time and runs work later, the monotonic clocks never step back, and the Hybrid Logical Clock orders events across processes.

## Rationale

**Why.** Code that reads the wall clock directly cannot be tested without it, and cannot order events by it: the wall clock steps back when NTP corrects it or someone sets it.

**Problem.** A timed <code>sleep</code>, <code>poll</code> or <code>wait</code> races the real clock, so its test is flaky under load. Across processes, no two clocks agree closely enough to order events by their readings alone.

**Solution.** Take time as a type. <code>Clockwork</code> is an <code>InstantSource</code> that also runs work after a delay, so a test hands in a clock it advances itself. A monotonic clock is a <code>software.visionary.counter.Increasing</code> that never steps back. A Hybrid Logical Clock, after Kulkarni et al. (2014), stamps each event to follow every stamp it issued or received before, while staying close to physical time.

## Key Concepts

### Clockwork

**Role.** Reads the time, as an <code>InstantSource</code>, and runs <code>then</code> on a thread of its own once <code>delay</code> has passed by this clockwork: <code>after(delay, then)</code>. A zero delay is as soon as possible.

**Pattern.** Strategy

### WallClock

**Role.** The system's <code>Clockwork</code>, <code>WallClock.INSTANCE</code>: <code>instant()</code> is the wall clock, and each piece of work that comes due runs on a virtual thread of its own, so a slow one never delays another.

**Pattern.** Singleton

### MonotonicWallClockFactory

**Role.** Supplies clocks that track the wall but never step back: each <code>next()</code> is the later of the wall's reading and every time the clock already issued.

### MonotonicClockFactory

**Role.** Supplies clocks that never step back because they read the wall once: each is anchored to one wall reading and advanced by a monotonic nanosecond source, such as <code>System::nanoTime</code>.

### HybridLogicalClock

**Role.** Stamps a local event with <code>next()</code> and a message's arrival with <code>receive(peer)</code>. Each stamp follows every stamp the clock issued or received before.

### HybridTimestamp

**Role.** A physical time and a logical counter. Stamps order by physical time, then by counter.

### HybridLogicalClockFactory

**Role.** Supplies Hybrid Logical Clocks over a physical clock, which may step back, and a strictly increasing counter for stamps that share a physical time.

## How It Works

**Guarantees.** No public parameter takes null and no public method returns it, declared with contrax's <code>@PreCondition(IsNotNull.class)</code> and <code>@PostCondition(IsNotNull.class)</code>. A monotonic clock's <code>next()</code> is never earlier than the one before. A Hybrid Logical Clock's stamp is later than every stamp it issued or received before.

## Lane

**Purpose.** Reading time, waiting on it, and ordering events through types a test drives by hand.

**Alternative.** <code>java.time.Clock</code>, when nothing waits on time. Vector clocks, when concurrent events must be detected rather than ordered.

## Usage

Running work at a time

```java
clockwork.after(Duration.between(clockwork.instant(), due), this::wake);
```

A wall-accurate time that never steps back

```java
Increasing<Instant> clock = new MonotonicWallClockFactory<>(Instant::now).get();
Instant now = clock.next();
```

Stamping messages between processes, given successors: a counter that starts after the value given, or at its first value given none

```java
HybridLogicalClock<Instant, Long> clock = new HybridLogicalClockFactory<Instant, Long>(Instant::now, successors).get();
HybridTimestamp<Instant, Long> sent = clock.next();
HybridTimestamp<Instant, Long> arrived = clock.receive(peer);
```

## Dependencies

- `software.visionary:counter:2026.10.13` at Compile
- `software.visionary:junit-closure:2026.09.17` at Testing

## Caveats

- A clock from <code>MonotonicClockFactory</code> drifts from the wall over long spans, since it reads the wall only once.
- A Hybrid Logical Clock is only as close to real time as its peers: a stamp received from a peer whose clock runs ahead carries every later stamp ahead with it.
- <code>WallClock</code>'s threads never keep a program running: work still waiting for its delay when the program exits never runs, and work already running is cut off.

