1/**
2 * Service and helpers for reading time and sleeping inside Effect programs.
3 * The active `Clock` provides Unix time, monotonic time for measuring elapsed
4 * durations, and a `sleep` operation for delaying work. Because time is
5 * accessed through a service, tests can replace the clock with a controlled
6 * implementation.
7 *
8 * @since 2.0.0
9 */
10import type * as Context from "./Context.ts"
11import type * as Duration from "./Duration.ts"
12import type { Effect } from "./Effect.ts"
13import * as effect from "./internal/effect.ts"
14
15/**
16 * Represents a time-based clock which provides functionality related to time
17 * and scheduling.
18 *
19 * **When to use**
20 *
21 * Use to define or provide a clock service for current-time and sleep
22 * operations.
23 *
24 * **Example** (Reading current time)
25 *
26 * ```ts import.meta.vitest
27 * import { Clock, Effect } from "effect"
28 *
29 * const testClock: Clock.Clock = {
30 * currentTimeMillisUnsafe: () => 1_000,
31 * currentTimeMillis: Effect.succeed(1_000),
32 * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
33 * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
34 * currentTimeNanosUnsafe: () => 1_000_000_000n,
35 * currentTimeNanos: Effect.succeed(1_000_000_000n),
36 * sleep: () => Effect.void
37 * }
38 *
39 * const clockOperations = Effect.gen(function*() {
40 * const currentTime = yield* Clock.currentTimeMillis
41 * const currentTimeNanos = yield* Clock.currentTimeNanos
42 * return [currentTime, currentTimeNanos] as const
43 * })
44 *
45 * await Effect.runPromise(Effect.provideService(clockOperations, Clock.Clock, testClock)) // => [1_000, 1_000_000_000n]
46 * ```
47 *
48 * @category services
49 * @since 2.0.0
50 */
51export interface Clock {
52 /**
53 * Returns the current Unix time in milliseconds unsafely.
54 *
55 * **When to use**
56 *
57 * Use to read a wall-clock timestamp synchronously when you already have a
58 * `Clock` service and can accept non-effectful access.
59 *
60 * **Gotchas**
61 *
62 * The value can move backward or forward when the system wall clock is
63 * corrected, so it is not suitable for measuring elapsed time.
64 */
65 currentTimeMillisUnsafe(): number
66 /**
67 * Returns the current Unix time in milliseconds.
68 *
69 * **When to use**
70 *
71 * Use to read a wall-clock timestamp through this `Clock` service in
72 * `Effect`.
73 *
74 * **Gotchas**
75 *
76 * The value can move backward or forward when the system wall clock is
77 * corrected, so it is not suitable for measuring elapsed time.
78 */
79 readonly currentTimeMillis: Effect<number>
80 /**
81 * Returns the current Unix time in nanoseconds unsafely.
82 *
83 * **When to use**
84 *
85 * Use to read a wall-clock timestamp synchronously when you already have a
86 * `Clock` service and can accept non-effectful access.
87 *
88 * **Gotchas**
89 *
90 * The value can move backward or forward when the system wall clock is
91 * corrected, so it is not suitable for measuring elapsed time.
92 */
93 currentTimeNanosUnsafe(): bigint
94 /**
95 * Returns the current Unix time in nanoseconds.
96 *
97 * **When to use**
98 *
99 * Use to read a wall-clock timestamp through this `Clock` service in
100 * `Effect`.
101 *
102 * **Gotchas**
103 *
104 * The value can move backward or forward when the system wall clock is
105 * corrected, so it is not suitable for measuring elapsed time.
106 */
107 readonly currentTimeNanos: Effect<bigint>
108 /**
109 * Returns the current monotonic time in nanoseconds unsafely.
110 *
111 * **When to use**
112 *
113 * Use to measure elapsed time synchronously when you already have a `Clock`
114 * service and can accept non-effectful access.
115 *
116 * **Gotchas**
117 *
118 * The value has an arbitrary origin and is unsuitable for serialization. Use
119 * it only to subtract readings produced by the same clock. Whether it
120 * advances while the host is suspended depends on the runtime.
121 *
122 * @since 4.0.0
123 */
124 monotonicTimeNanosUnsafe(): bigint
125 /**
126 * Returns the current monotonic time in nanoseconds.
127 *
128 * **When to use**
129 *
130 * Use to measure elapsed time through this `Clock` service in `Effect`.
131 *
132 * **Gotchas**
133 *
134 * The value has an arbitrary origin and is unsuitable for serialization. Use
135 * it only to subtract readings produced by the same clock. Whether it
136 * advances while the host is suspended depends on the runtime.
137 *
138 * @since 4.0.0
139 */
140 readonly monotonicTimeNanos: Effect<bigint>
141 /**
142 * Asynchronously sleeps for the specified duration.
143 *
144 * **When to use**
145 *
146 * Use to delay an `Effect` workflow by a duration through this `Clock` service.
147 */
148 sleep(duration: Duration.Duration): Effect<void>
149}
150
151/**
152 * Context reference for the active time service in the environment.
153 *
154 * **When to use**
155 *
156 * Use when you need to access or provide the full time service, including sleep
157 * operations, rather than a single timestamp accessor.
158 *
159 * **Example** (Accessing the Clock service)
160 *
161 * ```ts import.meta.vitest
162 * import { Clock, Effect } from "effect"
163 *
164 * const testClock: Clock.Clock = {
165 * currentTimeMillisUnsafe: () => 1_000,
166 * currentTimeMillis: Effect.succeed(1_000),
167 * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
168 * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
169 * currentTimeNanosUnsafe: () => 1_000_000_000n,
170 * currentTimeNanos: Effect.succeed(1_000_000_000n),
171 * sleep: () => Effect.void
172 * }
173 *
174 * const program = Effect.gen(function*() {
175 * const clock = yield* Clock.Clock
176 * return clock.currentTimeMillisUnsafe()
177 * })
178 *
179 * await Effect.runPromise(Effect.provideService(program, Clock.Clock, testClock)) // => 1_000
180 * ```
181 *
182 * @see {@link clockWith} for using the current Clock service inside an effect
183 * @see {@link currentTimeMillis} for reading the current time in milliseconds
184 * @see {@link currentTimeNanos} for reading the current time in nanoseconds
185 *
186 * @category services
187 * @since 2.0.0
188 */
189export const Clock: Context.Reference<Clock> = effect.ClockRef
190
191/**
192 * Accesses the current Clock service and uses it to run the provided function.
193 *
194 * **When to use**
195 *
196 * Use when you need the full Clock service interface to perform multiple time
197 * operations or call unsafe variants within a single effect.
198 *
199 * **Example** (Accessing the current Clock service)
200 *
201 * ```ts import.meta.vitest
202 * import { Clock, Effect } from "effect"
203 *
204 * const testClock: Clock.Clock = {
205 * currentTimeMillisUnsafe: () => 1_000,
206 * currentTimeMillis: Effect.succeed(1_000),
207 * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
208 * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
209 * currentTimeNanosUnsafe: () => 1_000_000_000n,
210 * currentTimeNanos: Effect.succeed(1_000_000_000n),
211 * sleep: () => Effect.void
212 * }
213 *
214 * const program = Clock.clockWith((clock) => Effect.sync(() => clock.currentTimeMillisUnsafe()))
215 *
216 * await Effect.runPromise(Effect.provideService(program, Clock.Clock, testClock)) // => 1_000
217 * ```
218 *
219 * @see {@link Clock} for the service reference
220 * @see {@link currentTimeMillis} for convenience accessor that returns milliseconds
221 * @see {@link currentTimeNanos} for convenience accessor that returns nanoseconds
222 * @category accessors
223 * @since 2.0.0
224 */
225export const clockWith: <A, E, R>(f: (clock: Clock) => Effect<A, E, R>) => Effect<A, E, R> = effect.clockWith
226
227/**
228 * Returns an Effect that succeeds with the current Unix time in milliseconds.
229 *
230 * **When to use**
231 *
232 * Use to create wall-clock timestamps from the active `Clock` service with
233 * millisecond precision.
234 *
235 * **Gotchas**
236 *
237 * The value can move backward or forward when the system wall clock is
238 * corrected, so it is not suitable for measuring elapsed time.
239 *
240 * **Example** (Reading milliseconds)
241 *
242 * ```ts import.meta.vitest
243 * import { Clock, Effect } from "effect"
244 *
245 * const testClock: Clock.Clock = {
246 * currentTimeMillisUnsafe: () => 1_000,
247 * currentTimeMillis: Effect.succeed(1_000),
248 * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
249 * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
250 * currentTimeNanosUnsafe: () => 1_000_000_000n,
251 * currentTimeNanos: Effect.succeed(1_000_000_000n),
252 * sleep: () => Effect.void
253 * }
254 *
255 * await Effect.runPromise(Effect.provideService(Clock.currentTimeMillis, Clock.Clock, testClock)) // => 1_000
256 * ```
257 *
258 * @see {@link currentTimeNanos} for nanosecond precision
259 * @see {@link monotonicTimeNanos} for measuring elapsed time
260 * @see {@link clockWith} for accessing the full Clock service
261 *
262 * @category accessors
263 * @since 2.0.0
264 */
265export const currentTimeMillis: Effect<number> = effect.currentTimeMillis
266
267/**
268 * Returns an Effect that succeeds with the current Unix time in nanoseconds.
269 *
270 * **When to use**
271 *
272 * Use to create wall-clock timestamps from the active `Clock` service with
273 * nanosecond precision.
274 *
275 * **Gotchas**
276 *
277 * The value can move backward or forward when the system wall clock is
278 * corrected, so it is not suitable for measuring elapsed time.
279 * The live clock allows up to one second of drift from `Date.now()` before
280 * re-anchoring.
281 *
282 * **Example** (Reading nanoseconds)
283 *
284 * ```ts import.meta.vitest
285 * import { Clock, Effect } from "effect"
286 *
287 * const testClock: Clock.Clock = {
288 * currentTimeMillisUnsafe: () => 1_000,
289 * currentTimeMillis: Effect.succeed(1_000),
290 * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
291 * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
292 * currentTimeNanosUnsafe: () => 1_000_000_000n,
293 * currentTimeNanos: Effect.succeed(1_000_000_000n),
294 * sleep: () => Effect.void
295 * }
296 *
297 * await Effect.runPromise(Effect.provideService(Clock.currentTimeNanos, Clock.Clock, testClock)) // => 1_000_000_000n
298 * ```
299 *
300 * @see {@link monotonicTimeNanos} for measuring elapsed time
301 *
302 * @category accessors
303 * @since 2.0.0
304 */
305export const currentTimeNanos: Effect<bigint> = effect.currentTimeNanos
306
307/**
308 * Returns an Effect that succeeds with the current monotonic time in
309 * nanoseconds.
310 *
311 * **When to use**
312 *
313 * Use to measure elapsed time by subtracting two readings.
314 *
315 * **Gotchas**
316 *
317 * The value has an arbitrary origin and is unsuitable for serialization. Use
318 * it only to subtract readings produced by the same clock. Whether it advances
319 * while the host is suspended depends on the runtime.
320 *
321 * @see {@link currentTimeNanos} for Unix wall-clock timestamps
322 *
323 * @category accessors
324 * @since 4.0.0
325 */
326export const monotonicTimeNanos: Effect<bigint> = effect.monotonicTimeNanos