Три типа покрывают модель времени Nova: Duration (знаковый интервал), Timestamp (момент от Unix-эпохи) и Monotonic (монотонные часы процесса). Все хранят наносекунды в одном поле i64. Методы-расширения для целых чисел и чисел с плавающей точкой позволяют писать 5.to_seconds(), 1.to_hours(), 500.to_millis() напрямую.

ro timeout = 30.to_seconds()
ro deadline = 1_700_000_000.to_unix_seconds() + timeout

ro d = 3661.to_seconds()  // 1h 1min 1s
assert(d.parts().hours == 1)

Типы

Duration

стабильно с 0.1
export type Duration { nanos i64 }

Знаковый временной интервал с наносекундной точностью. Диапазон: ±292 года (i64::MAX наносекунд). Поддерживает операторы арифметики, сравнения и форматирования.

Timestamp

стабильно с 0.1
export type Timestamp { nanos i64 }

Момент времени, хранимый как число наносекунд от Unix-эпохи (1970-01-01 UTC). Знаковый, поэтому поддерживает даты до 1970 года. Timestamp - Timestamp даёт Duration. Методам, которым нужны текущие настенные часы, требуется эффект Time.

Monotonic

стабильно с 0.6
export type Monotonic { nanos i64 }

Точка на монотонных часах процесса. Не подвержена коррекциям NTP / переходу на летнее время / ручной настройке часов. Используйте для дедлайнов таймеров, интервалов профилирования и бюджетов повторных попыток. Не может быть сериализована или сравнена между процессами.

Примеры

ro start = Monotonic.now()
// ... work ...
ro elapsed = Monotonic.now().elapsed_since(start)

Константы

const ZERO   Duration  = { nanos: 0 }             // zero duration
const SECOND Duration  = { nanos: 1_000_000_000 }  // 1 second
const MINUTE Duration  = { nanos: 60_000_000_000 } // 1 minute
const HOUR   Duration  = { nanos: 3_600_000_000_000 }
const EPOCH Timestamp = { nanos: 0 }  // 1970-01-01 00:00:00 UTC

Duration — конструкторы

fn[T Ints] T @to_nanos()   -> Duration  // 1 ns
fn[T Ints] T @to_micros()  -> Duration  // 1 μs = 1_000 ns
fn[T Ints] T @to_millis()  -> Duration  // 1 ms = 1_000_000 ns
fn[T Ints] T @to_seconds() -> Duration  // 1 s  = 1_000_000_000 ns
fn[T Ints] T @to_minutes() -> Duration  // 60 s
fn[T Ints] T @to_hours()   -> Duration  // 3600 s
fn[T Ints] T @to_days()    -> Duration  // 86400 s
fn[T Ints] T @to_weeks()   -> Duration  // 7 * 86400 s
fn f64 @to_seconds()       -> Duration  // e.g. 0.5 → 500ms

Duration — аксессоры

fn Duration @nanos()       -> i64  // raw nanoseconds
fn Duration @micros()      -> i64  // truncating
fn Duration @millis()      -> i64
fn Duration @seconds()     -> i64
fn Duration @minutes()     -> i64
fn Duration @hours()       -> i64
fn Duration @days()        -> i64
fn Duration @seconds_f64() -> f64  // fractional seconds (preserves sub-second)

Примеры

assert(2.to_seconds().millis() == 2000)
assert(1500.to_millis().seconds_f64() == 1.5)

Duration — арифметика

fn Duration @plus(other Duration)  -> Duration  // d1 + d2
fn Duration @minus(other Duration) -> Duration  // d1 - d2 (may be negative)
fn Duration @neg()                 -> Duration  // unary -
fn Duration @abs()                 -> Duration  // |d|
fn Duration @times(n i64)          -> Duration  // d * n
fn Duration @times(n f64)          -> Duration
fn Duration @div(n i64)            -> Duration  // d / n (truncating)
fn Duration @div(n f64)            -> Duration
fn Duration @ratio(other Duration) -> f64       // d1 / d2 dimensionless

Примеры

assert(1.to_hours() + 30.to_minutes() == 90.to_minutes())
assert(30.to_seconds().ratio(1.to_minutes()) == 0.5)

Duration — форматирование

fn Duration @to_str()       -> str  // auto-scale: "500ns" / "42ms" / "2.5s" / "5min" / "2h"
fn Duration @parts()        -> DurationParts

Примеры

ro d = 3661.to_seconds()  // 1h 1min 1s
ro p = d.parts()
assert(p.hours == 1 && p.minutes == 1 && p.seconds == 1)

assert(2.to_hours().to_str() == "2h")
assert(500.to_nanos().to_str() == "500ns")

Расширения целых чисел и чисел с плавающей точкой

Методы-расширения для int и f64 позволяют естественно записывать литералы длительности:

fn[T Ints] T @to_nanos()   -> Duration
fn[T Ints] T @to_micros()  -> Duration
fn[T Ints] T @to_millis()  -> Duration
fn[T Ints] T @to_seconds() -> Duration
fn[T Ints] T @to_minutes() -> Duration
fn[T Ints] T @to_hours()   -> Duration
fn[T Ints] T @to_days()    -> Duration
fn[T Ints] T @to_weeks()   -> Duration
fn f64 @to_seconds() -> Duration

Примеры

assert(30.to_seconds().seconds() == 30)
assert(500.to_nanos().nanos() == 500)
assert(0.5.to_seconds() == 500.to_millis())

Timestamp — конструкторы

fn[T Ints] T @to_unix_seconds() -> Timestamp
fn[T Ints] T @to_unix_millis()  -> Timestamp
fn[T Ints] T @to_unix_nanos()   -> Timestamp

Timestamp — арифметика

fn Timestamp @plus(d Duration)          -> Timestamp   // shift forward
fn Timestamp @minus(d Duration)         -> Timestamp   // shift back
fn Timestamp @minus(other Timestamp)    -> Duration    // elapsed (signed)

Примеры

ro start    = 1000.to_unix_seconds()
ro deadline = start + 30.to_seconds()
assert(deadline.unix_seconds() == 1030)
assert((deadline - start) == 30.to_seconds())

Timestamp — запросы через эффект Time

Эти методы требуют эффект Time из окружающей области видимости. В тестах внедрите детерминированный обработчик:

fn Timestamp @is_past()     Time -> bool
fn Timestamp @elapsed()     Time -> Duration  // positive if in the past
fn Timestamp @time_until()  Time -> Duration  // positive if in the future
fn deadline_in(d Duration)  Time -> Timestamp // now() + d

Примеры

with Time = th.fixed_ms(10_000) {
    ro deadline = 5.to_unix_seconds()
    assert(deadline.is_past())

    ro (result, elapsed) = measure(|| 42)
    assert(result == 42)
    assert(elapsed == Duration.ZERO)  // fixed clock doesn't advance
}