morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
datetime.hpp File Reference

UTC timestamps for morph actions. More...

#include <charconv>
#include <chrono>
#include <compare>
#include <cstdint>
#include <format>
#include <functional>
#include <glaze/glaze.hpp>
#include <morph/attributes.hpp>
#include <morph/core/payload_shape_tag.hpp>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <utility>

Go to the source code of this file.

Classes

struct  morph::time::DateTime
 A UTC instant with millisecond precision. More...
class  morph::time::ScopedNowOverride
 RAII helper that fixes DateTime::now() to a constant instant (or a custom callable) for its lifetime and restores the previous override on destruction. More...
struct  morph::time::Timestamp
 An optionally-empty timestamp field. More...
struct  morph::model::PayloadShapeTag< morph::time::DateTime >
 Stable shape tag for DateTime. More...
struct  morph::model::PayloadShapeTag< morph::time::Timestamp >
 Stable shape tag for Timestamp. More...

Functions

std::pair< std::mutex, std::function< DateTime()> > & morph::time::detail::nowOverrideState ()
 Process-wide override for DateTime::now(), guarded by a mutex.
void morph::time::setNowOverride (std::function< DateTime()> clock)
 Installs clock as the process-wide override for DateTime::now() (and therefore Timestamp::now(), which delegates to it).
constexpr std::optional< std::chrono::milliseconds > morph::time::operator- (const Timestamp &lhs, const Timestamp &rhs) noexcept
 The signed duration between two engaged timestamps.

Detailed Description

UTC timestamps for morph actions.

Two types, mirroring the Rational/Quantity split:

  • morph::time::DateTime — the value: a UTC instant with millisecond precision over std::chrono::sys_time (adapted from LASTRADA Toolbox/Chrono.hpp). Cheap to copy, ordered, duration arithmetic.
  • morph::time::Timestamp — the field: an optionally-empty DateTime with the same one-kind-of-empty semantics as Quantity (a form draft starts blank; required-ness is derived by morph::forms).
Wire format
A DateTime travels as the ISO-8601 string "YYYY-MM-DDTHH:MM:SS[.mmm]Z" (UTC only; the fractional part and the trailing Z are optional on input, always written on output). Parsing is a strict, hand-rolled routine — no locale, no std::chrono::parse dependency — so behaviour is identical across libstdc++, libc++ (WASM), and MSVC. Unlike the Rational codec, which clamps hostile input into a valid value, a malformed timestamp has no meaningful clamp: the codec rejects it as a JSON read error.
Schema
A Timestamp field renders as {"type": ["string","null"], "format": "date-time"} — the standard JSON-Schema vocabulary form renderers key on (the demo clients render a date-time input for it).

Definition in file datetime.hpp.

Function Documentation

◆ nowOverrideState()

std::pair< std::mutex, std::function< DateTime()> > & morph::time::detail::nowOverrideState ( )
inlinenodiscard

Process-wide override for DateTime::now(), guarded by a mutex.

Function-local static backing DateTime::now()'s override seam.

Mirrors morph::journal::detail::defaultActionLogState() — the same "mutex-guarded function-local static" shape used for the action-log and logger override seams elsewhere in the codebase. An empty std::function (the default) means "no override installed"; DateTime::now() falls back to std::chrono::system_clock::now() in that case. Forward-declared here (before DateTime is a complete type – a function signature only needs DateTime to be declared, not defined) and defined out-of-line just after the DateTime struct, before DateTime::now()'s first caller needs it.

Defined out-of-line (after DateTime is a complete type) since the state is keyed on std::function<DateTime()>.

Returns
Reference to the process-wide (mutex, override callable) pair; the callable is empty when no override is installed.

Definition at line 291 of file datetime.hpp.

◆ setNowOverride()

void morph::time::setNowOverride ( std::function< DateTime()> clock)
inline

Installs clock as the process-wide override for DateTime::now() (and therefore Timestamp::now(), which delegates to it).

Every call to DateTime::now() — including inside a registry-constructed (remotely instantiated) model that has no constructor parameter to receive an injected clock — consults this override before falling back to std::chrono::system_clock::now(). This is the seam docs/spec/util/datetime.md describes for deterministic testing of time-dependent model behavior: a test fixes "now" once via ScopedNowOverride and every DateTime::now()/Timestamp::now() call for its lifetime — direct or from inside a model under test — observes the fixed instant. Thread-safe.

Warning
clock must not throw (DateTime::now() is noexcept and calls it directly — an exception escaping clock terminates the process) and must not call DateTime::now()/Timestamp::now(), setNowOverride, or construct a ScopedNowOverride itself: now() holds a non-recursive mutex while invoking clock, so any of those self-deadlocks.
Parameters
clockCallable returning the instant DateTime::now() should report, or an empty std::function to clear the override (restore real wall-clock time).

Definition at line 319 of file datetime.hpp.

◆ operator-()

std::optional< std::chrono::milliseconds > morph::time::operator- ( const Timestamp & lhs,
const Timestamp & rhs )
nodiscardconstexprnoexcept

The signed duration between two engaged timestamps.

Parameters
lhsMinuend.
rhsSubtrahend.
Returns
lhs - rhs as a chrono duration, or std::nullopt if either is empty.

Definition at line 416 of file datetime.hpp.