Definition of the standard frog.time timing library for FROG v0.1
FROG - Free Open Graphical Language
- 1. Overview
- 2. Goals
- 3. Relation with Other Specifications
- 4. Role of
frog.time - 5. Naming and Namespace
- 6. Time Model
- 7. Scope for v0.1
- 8. Typing and Status Model
- 9. Capability and Effect Model
- 10. Wall-Clock Functions
- 11. Monotonic and Elapsed Functions
- 12. Duration and Arithmetic Functions
- 13. Formatting and Parsing Functions
- 14. Wait and Delay Boundaries
- 15. Profiling Hooks
- 16. Diagram and FIR Representation
- 17. Determinism, Debugging, and Replay
- 18. Relation with Signal, Waveform, and Chart Surfaces
- 19. Validation Rules
- 20. Out of Scope for v0.1
- 21. Summary
This document defines the standard frog.time library for FROG v0.1.
The frog.time library provides a compact timing surface for:
- reading wall-clock time,
- reading monotonic time for elapsed-time measurement,
- computing elapsed durations,
- performing duration arithmetic and unit conversion,
- formatting and parsing UTC timestamp text,
- declaring wait/delay boundaries as explicit scheduler-capability calls,
- emitting optional profiling marks without making profiling part of program semantics.
Time is intentionally explicit in FROG. A diagram that depends on a clock, a scheduler wait, or a profiling hook must call a published primitive. Runtimes, compilers, IDEs, and launchers MUST NOT hide timing behavior behind private scheduler convention.
- Separation - keep wall-clock timestamps, monotonic timestamps, durations, waits, and profiling hooks distinct.
- Portability - define stable primitive identities and scalar port contracts using the v0.1 type system.
- Scheduler honesty - expose waits and delays as runtime-hosted capabilities, not as hard real-time guarantees.
- Determinism awareness - make clock reads and waits visible to FIR, lowering, manifests, replay, and debugging profiles.
- Status discipline - use explicit local status outputs until the FROG-wide status corridor is standardized.
- Minimality - avoid timer handles, event-loop APIs, cron-like schedulers, and locale-heavy formatting in the first surface.
This document complements the following specifications:
- Expression/Diagram.md - defines how primitive calls are serialized as executable graph nodes.
- Expression/Type.md - defines the scalar types used by the time primitives.
- Libraries/Core.md - defines pure computation and explicit local memory;
frog.timedoes not replacefrog.core.delay. - Libraries/System.md - defines bounded host/system introspection and explicitly excludes time and scheduler control.
- Libraries/Signal.md - defines signal functions over numeric arrays without owning waveform timestamp metadata.
- IR/Library call model.md - defines how FIR records host-capability calls, effects, status models, and abstract requirements.
- IR/Lowering.md and IR/Backend contract.md - define downstream specialization and manifest/provider boundaries.
- Language/Execution control and observation boundaries.md - defines safe observation, pause, debug-stop, and terminal boundaries.
This document defines the frog.time primitive catalog only. It does not define a
runtime scheduler implementation, a real-time profile, an IDE event loop, an operating-system timer
API, a private profiling transport, or a universal status value.
The frog.time library provides explicit timing primitives used by executable diagram
nodes of kind primitive.
In serialized diagrams, calls to these primitives use namespace-qualified identifiers such as:
frog.time.now
frog.time.monotonic_now
frog.time.elapsed_since
frog.time.wait_duration
frog.time.format_iso8601_utc
The role of frog.time is to make timing dependencies visible in source, FIR,
lowering, backend contracts, manifests, debug tooling, and conformance discussion.
FROG library primitives use stable namespace-qualified identifiers:
frog.<library>.<primitive>For this document:
frogidentifies the language namespace,timeidentifies the standard timing library,- the final segment identifies the primitive name.
Primitive names in frog.time SHOULD use lowercase snake_case where multiple words are needed.
A wall-clock timestamp represents civil UTC time. It is suitable for logging, display, file-like metadata, and timestamped data values.
In v0.1, a wall-clock timestamp is carried as:
wall_time_ns: i64
The value is signed nanoseconds from the Unix epoch, 1970-01-01T00:00:00Z.
The timestamp is UTC. It does not carry a local time zone, locale, calendar system, or leap-second
table.
Wall-clock time is not monotonic. It can move forward, pause, or move backward according to host clock adjustment, network time correction, manual setting, virtualization, or replay policy. Programs MUST NOT use wall-clock timestamps to measure elapsed durations or drive periodic loops unless a stricter profile explicitly defines that behavior.
A monotonic timestamp represents an implementation-provided non-decreasing clock suitable for elapsed-time measurement inside one execution context.
In v0.1, a monotonic timestamp is carried as:
monotonic_time_ns: u64The origin is implementation-defined. It has no civil meaning and MUST NOT be serialized as a portable wall-clock timestamp. Monotonic timestamps are meaningful only when compared with other monotonic timestamps produced by the same active clock source and compatible execution context.
A duration represents signed elapsed time or signed timestamp offset.
In v0.1, a duration is carried as:
duration_ns: i64Negative durations are valid for arithmetic and comparison. Scheduler waits reject negative durations unless a future profile explicitly gives them a meaning.
FROG v0.1 does not standardize library-defined custom time types, records, structs, or units-of-measure types. The scalar carrier names above describe primitive port roles and value semantics, not new source-level type expressions.
FROG v0.1 standardizes the following frog.time primitives:
| Area | Primitive | Purpose |
|---|---|---|
| Wall-clock | frog.time.now |
Reads the current wall-clock UTC timestamp. |
| Monotonic | frog.time.monotonic_now |
Reads the current monotonic timestamp for elapsed-time measurement. |
| Elapsed | frog.time.elapsed_since |
Reads monotonic time and computes elapsed duration since a prior monotonic timestamp. |
| Elapsed | frog.time.elapsed_between |
Computes duration between two monotonic timestamps. |
| Duration | frog.time.duration_from_ms |
Converts milliseconds to nanosecond duration. |
| Duration | frog.time.duration_to_ms |
Converts nanosecond duration to milliseconds with explicit rounding. |
| Arithmetic | frog.time.add_duration |
Adds a duration to a wall-clock timestamp. |
| Arithmetic | frog.time.subtract_duration |
Subtracts a duration from a wall-clock timestamp. |
| Formatting | frog.time.format_iso8601_utc |
Formats a wall-clock timestamp as canonical UTC ISO 8601 text. |
| Parsing | frog.time.parse_iso8601_utc |
Parses supported ISO 8601 timestamp text into UTC nanoseconds. |
| Wait | frog.time.wait_duration |
Requests a scheduler wait for at least a duration. |
| Wait | frog.time.wait_until_monotonic |
Requests a scheduler wait until a target monotonic timestamp. |
| Periodic helper | frog.time.periodic_next_target |
Computes the next monotonic target for drift-aware periodic loops. |
| Profiling | frog.time.profile_mark |
Emits an optional source-attributed profiling mark. |
Timer-handle APIs, asynchronous callbacks, timed loops, wall-clock alarms, cron-like scheduling,
timer events, cancellation tokens, high-resolution benchmarking suites, locale-heavy formatting,
and real-time guarantees are not part of the v0.1 frog.time surface.
All frog.time primitives are typed according to Expression/Type.md.
In v0.1, this library uses only built-in scalar types:
i64for wall-clock nanoseconds and signed durations,u64for monotonic nanoseconds and non-negative counts where needed,u8for fractional digit counts,boolfor success, completion, and acceptance flags,stringfor formatted timestamps, rounding modes, labels, and local error codes.
Until FROG standardizes a uniform error/status corridor, primitives in this document that can fail use a local status tuple:
success: boolerror_code: string
This local tuple is not the final FROG-wide error/status contract. FIR should represent it as
status_model = "local_result_tuple".
Rules:
- if
success = true,error_codeMUST be the empty string, - if
success = false, every data output MUST still be present, well-typed, and set to its fallback value, - integer outputs fall back to
0, - string outputs fall back to the empty string,
- boolean data outputs fall back to
false.
Standard local error codes are:
unsupported- the implementation or active execution profile does not support the primitive,permission_denied- host policy denies the clock, scheduler, or profiling operation,host_policy_blocked- a sandbox, deployment profile, or capability boundary blocks the operation,clock_unavailable- the required clock source is unavailable,scheduler_unavailable- the required wait/scheduler service is unavailable,profiling_unavailable- the requested profiling hook is unavailable,invalid_input- an input such as a negative wait duration, invalid rounding mode, invalid fractional digit count, or malformed label is invalid,overflow- arithmetic or unit conversion exceeds the representable scalar range,parse_error- timestamp text cannot be parsed by the published grammar,format_error- timestamp text cannot be formatted under the requested options,interrupted- a scheduler wait was interrupted by cancellation, abort, teardown, or a profile-defined interruption,unknown_error- the host failed without a more specific standardized code.
The frog.time library contains both value-only transforms and runtime-hosted
host-capability calls.
| Primitive group | Call class | Effect posture | Capability token |
|---|---|---|---|
| Arithmetic and unit conversion | standard_library_value |
pure unless a status-bearing overflow path is taken |
none |
| Formatting and parsing | standard_library_value |
pure |
none |
| Wall-clock reads | host_capability |
host_capability_read |
frog.time.wall_clock.read |
| Monotonic reads and elapsed-since helpers | host_capability |
host_capability_read |
frog.time.monotonic_clock.read |
| Scheduler waits | host_capability |
runtime_orchestration |
frog.time.scheduler.wait |
| Profiling hooks | host_capability |
runtime_orchestration |
frog.time.profiling.mark |
The runtime_orchestration effect is valid here only because the source-level primitive is
explicit. A private runtime scheduler service that is not called through a public primitive remains
outside ordinary FIR program calls.
Reads the current wall-clock UTC timestamp.
- input ports: none
- output ports:
wall_time_ns,success,error_code
Types:
wall_time_ns: i64success: boolerror_code: string
Rules:
- the timestamp is UTC nanoseconds from the Unix epoch,
- the value may move backward or forward between calls,
- the value MUST NOT be used as evidence of elapsed duration without explicit profile support,
- if the wall-clock source is unavailable, the primitive returns
success = falseanderror_code = "clock_unavailable".
Reads the current monotonic timestamp for elapsed-time measurement.
- input ports: none
- output ports:
monotonic_time_ns,success,error_code
Types:
monotonic_time_ns: u64success: boolerror_code: string
The origin of monotonic_time_ns is implementation-defined and not portable across execution
contexts. Only differences between compatible monotonic timestamps are meaningful.
Reads the current monotonic timestamp and computes elapsed duration since a prior monotonic timestamp.
- input port:
start_monotonic_ns - output ports:
elapsed_ns,current_monotonic_ns,success,error_code
Types:
start_monotonic_ns: u64elapsed_ns: i64current_monotonic_ns: u64success: boolerror_code: string
This primitive depends on frog.time.monotonic_clock.read. It fails if the current
monotonic clock is unavailable, if the computed difference exceeds the i64 duration range,
or if the current monotonic value is less than start_monotonic_ns under the active clock source.
Computes the signed duration between two monotonic timestamps.
- input ports:
start_monotonic_ns,end_monotonic_ns - output ports:
elapsed_ns,success,error_code
Types:
start_monotonic_ns: u64end_monotonic_ns: u64elapsed_ns: i64success: boolerror_code: string
This is a value transform. It succeeds when end_monotonic_ns >= start_monotonic_ns and
the difference fits in i64. It does not prove that the two timestamps came from the same
clock source; validators and profiles MAY add stricter provenance checks later.
Converts milliseconds to signed nanoseconds.
- input port:
milliseconds - output ports:
duration_ns,success,error_code
Types:
milliseconds: i64duration_ns: i64success: boolerror_code: string
The primitive fails with overflow if multiplying by 1_000_000 exceeds the
i64 range.
Converts signed nanoseconds to milliseconds with explicit rounding.
- input ports:
duration_ns,rounding_mode - output ports:
milliseconds,success,error_code
Types:
duration_ns: i64rounding_mode: stringmilliseconds: i64success: boolerror_code: string
Valid rounding modes are truncate, floor, ceil, and
nearest. The nearest mode rounds half away from zero.
Adds a signed duration to a wall-clock timestamp.
- input ports:
wall_time_ns,duration_ns - output ports:
result_wall_time_ns,success,error_code
Types:
wall_time_ns: i64duration_ns: i64result_wall_time_ns: i64success: boolerror_code: string
The primitive fails with overflow if the result exceeds the i64 range.
Subtracts a signed duration from a wall-clock timestamp.
- input ports:
wall_time_ns,duration_ns - output ports:
result_wall_time_ns,success,error_code
The typing and overflow rules are the same as frog.time.add_duration.
Formats a wall-clock timestamp as canonical UTC ISO 8601 text.
- input ports:
wall_time_ns,fractional_digits - output ports:
text,success,error_code
Types:
wall_time_ns: i64fractional_digits: u8text: stringsuccess: boolerror_code: string
Rules:
fractional_digitsMUST be in the inclusive range0through9,- the result MUST use UTC and end with
Z, - the date separator is
-, the time separator is:, and the date-time separator isT, - locale-specific month names, calendars, localized digits, and time-zone names are out of scope.
Example output:
2026-05-20T13:45:12.123456789ZParses supported ISO 8601 timestamp text into UTC nanoseconds.
- input port:
text - output ports:
wall_time_ns,success,error_code
Types:
text: stringwall_time_ns: i64success: boolerror_code: string
The v0.1 parser accepts:
YYYY-MM-DDTHH:MM:SSZ,YYYY-MM-DDTHH:MM:SS.sssZwith one through nine fractional digits,- the same forms with numeric UTC offsets such as
+02:00or-05:30, converted to UTC.
Leap-second notation such as 23:59:60, named time zones, locale formats, week dates,
ordinal dates, relaxed separators, and ambiguous local times are not supported in v0.1.
Wait primitives are explicit scheduler-capability calls. They request that the active execution host delay continuation of the relevant execution activity. They do not promise exact wakeup time, hard real-time behavior, OS-level sleep mechanics, or one implementation strategy.
Implementations MUST NOT realize waits as hidden runtime folklore. FIR, lowering, backend contracts, manifests, launchers, or comparable downstream representations must preserve that the program uses a scheduler wait capability.
Requests a scheduler wait for at least the supplied duration.
- input port:
duration_ns - output ports:
completed,actual_elapsed_ns,success,error_code
Types:
duration_ns: i64completed: boolactual_elapsed_ns: i64success: boolerror_code: string
Rules:
- negative durations are invalid and MUST produce
success = falsewitherror_code = "invalid_input", - a zero duration MAY yield at a scheduler boundary but MUST NOT be treated as a hard synchronization barrier,
- when the wait completes normally,
completed = trueandsuccess = true, actual_elapsed_nsis measured with the active monotonic clock when available,- if the wait is interrupted, aborted, blocked by policy, or unsupported,
completed = falseandsuccess = false.
Requests a scheduler wait until a target monotonic timestamp.
- input port:
target_monotonic_ns - output ports:
completed,actual_monotonic_ns,lateness_ns,success,error_code
Types:
target_monotonic_ns: u64completed: boolactual_monotonic_ns: u64lateness_ns: i64success: boolerror_code: string
If the target is already in the past for the active monotonic clock, the primitive completes without
requesting a positive delay. lateness_ns is actual_monotonic_ns - target_monotonic_ns
when the difference fits in i64.
Computes the next target for a monotonic periodic loop without accumulating drift from the current wakeup time.
- input ports:
previous_target_monotonic_ns,period_ns - output ports:
next_target_monotonic_ns,success,error_code
Types:
previous_target_monotonic_ns: u64period_ns: i64next_target_monotonic_ns: u64success: boolerror_code: string
period_ns MUST be positive. The primitive fails with overflow if the next target
does not fit in u64.
A wait may cause an execution activity to yield to a host scheduler, but it must not authorize a runtime to expose impossible source-level intermediate states. Debugging, pausing, and observation remain constrained by the safe boundary rules in the language layer.
For hosts with front panels or IDE event loops, a wait SHOULD allow the host to remain responsive when the active profile supports that behavior. This is a host responsiveness expectation, not a source-level guarantee about event ordering, repaint timing, or UI toolkit mechanics.
Emits an optional source-attributed profiling mark.
- input port:
label - output ports:
accepted,success,error_code
Types:
label: stringaccepted: boolsuccess: boolerror_code: string
The profiling mark is diagnostic. It MUST NOT change the meaning of ordinary dataflow values except
through its explicit status outputs. When profiling is disabled or unavailable, the primitive may
return success = false with error_code = "profiling_unavailable".
Profiling spans, sampled profilers, performance counters, benchmark harnesses, and private trace formats are out of scope for v0.1.
Calls to frog.time primitives are serialized as primitive nodes in the
diagram.
Examples:
{
"id": "clock_1",
"kind": "primitive",
"type": "frog.time.monotonic_now"
}{
"id": "wait_1",
"kind": "primitive",
"type": "frog.time.wait_duration"
}The exact port existence, direction, typing, status posture, effect posture, and capability requirement of these nodes are resolved from this specification together with the type system, graph rules, language execution rules, and FIR library-call model.
For FIR representation:
- value-only transforms SHOULD use
call_class = "standard_library_value", - clock reads SHOULD use
call_class = "host_capability"andeffect = "host_capability_read", - wait and profiling calls SHOULD use
call_class = "host_capability"andeffect = "runtime_orchestration", - status-bearing calls SHOULD use
status_model = "local_result_tuple", - clock, wait, and profiling calls MUST preserve abstract capability tokens rather than private runtime service names.
Clock reads and waits are not pure deterministic value transforms. They observe or request behavior from the active execution host. This dependency must remain explicit.
Deterministic execution, replay, testing, and simulation profiles MAY provide injected clock and scheduler providers. Such providers must be declared by the active profile, backend contract, manifest, test harness, or comparable execution contract. A runtime MUST NOT silently replace clock reads with invented deterministic values while claiming ordinary host-clock behavior.
Debug pause time is profile-sensitive:
- ordinary host-clock profiles may let wall and monotonic clock observations advance while execution is paused,
- replay or simulation profiles may freeze or script clock observations,
- the selected policy must be visible as a profile or host capability claim when it affects source-visible timing results.
Safe observation, pause, debug-stop, and terminal boundaries still apply. A wait primitive may be a natural place for an implementation to yield, pause, or observe, but it does not permit exposure of partially committed source-level state.
frog.signal v0.1 operates on numeric arrays and does not own timestamp metadata.
Future frog.waveform timing fields should use frog.time semantics:
t0for absolute waveform start time should map towall_time_nswhen absolute UTC time is needed,dtfor uniform sample interval should map toduration_nswhen integer nanosecond precision is sufficient,- relative-time waveforms should use duration semantics rather than wall-clock timestamps,
- irregular samples should use explicit x/time arrays or a future waveform-specific representation.
Widget-level chart fields such as timebase.t0, timebase.dt,
timebase.unit, and timebase.sample_rate remain chart value and widget-class
surface until a waveform library publishes a concrete value model. They must not silently define
the source-level frog.time API.
Implementations that support frog.time MUST enforce the following rules:
- every
frog.timeprimitive reference MUST identify a valid standardized primitive name from this document, - all required input ports MUST exist and be type-compatible,
- all produced output ports MUST match the primitive definition,
- status-bearing primitives MUST expose
successanderror_codeoutputs exactly as defined here, - wall-clock and monotonic timestamp values MUST NOT be used interchangeably,
- wait primitives MUST preserve scheduler capability requirements in FIR, lowering, backend contracts, manifests, or comparable downstream representation,
- unsupported clock, wait, or profiling use MUST be rejected or reported as unsupported rather than guessed from private runtime behavior,
- no implementation may claim hard real-time timing, deterministic replay, or profiling support unless the active profile or host contract explicitly provides it.
The following are outside the strict scope of frog.time in v0.1:
- hard real-time guarantees, deterministic jitter bounds, priority scheduling, or deadline scheduling,
- timed loops or event structures as source-level structure families,
- timer handles, cancellation tokens, async callbacks, promises, futures, or event-loop APIs,
- wall-clock alarms, cron-like scheduling, calendar recurrence, business calendars, or time-zone databases,
- locale-specific formatting, named time zones, leap-second tables, non-Gregorian calendars, and natural-language parsing,
- benchmark frameworks, sampled profilers, performance counters, flame graphs, private trace formats, or IDE-specific profiling transports,
- hardware timer APIs, DAQ timing, audio clocks, GPU clocks, distributed clock synchronization, PTP/NTP control, or multi-machine time coherence,
- using waits as hidden UI event pumps, hidden synchronization primitives, or substitutes for explicit local memory and dataflow dependencies,
- a universal structured error object or FROG-wide error/status corridor.
The frog.time library defines the first standard FROG timing surface.
It provides:
- wall-clock UTC reads through
frog.time.now, - monotonic reads and elapsed-time helpers,
- nanosecond duration conversion and wall-clock arithmetic,
- ISO 8601 UTC formatting and parsing,
- scheduler wait boundaries with explicit capability requirements,
- optional profiling marks that remain diagnostic rather than semantic.
The surface is intentionally explicit, status-bearing where needed, capability-aware, and honest about scheduler limits. It does not turn one runtime scheduler, one operating-system clock API, or one profiling implementation into FROG language truth.
End of FROG Time Library Specification