
```vary
import time

let start = time.now()
time.sleep_ms(100)
let elapsed = time.now().diff(start)
print(elapsed.to_millis())  # milliseconds elapsed
```

## Instant

An `Instant` represents a point in time (milliseconds since epoch).

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `time.now()` | `Instant` | Current wall-clock time |
| `time.now_epoch_millis()` | `Int` | Current time as epoch milliseconds |
| `time.now_epoch_seconds()` | `Float` | Current time as epoch seconds |
| `instant_from_epoch_millis(ms)` | `Instant` | Create Instant from epoch ms |
| `instant_from_epoch_seconds(s)` | `Instant` | Create Instant from epoch seconds |

### Instant Methods

| **Method** | **Returns** | **Description** |
|--------|---------|-------------|
| `.epoch_millis()` | `Int` | Epoch milliseconds |
| `.epoch_seconds()` | `Float` | Epoch seconds |
| `.add(duration)` | `Instant` | Add a Duration |
| `.sub(duration)` | `Instant` | Subtract a Duration |
| `.diff(other)` | `Duration` | Duration between two instants |
| `.format_iso()` | `Str` | ISO 8601 format |

## Duration

A `Duration` represents a time span in milliseconds.

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `duration_ms(ms)` | `Duration` | From milliseconds |
| `duration_seconds(s)` | `Duration` | From seconds (Float) |
| `duration_minutes(m)` | `Duration` | From minutes |
| `duration_hours(h)` | `Duration` | From hours |

### Duration Methods

| **Method** | **Returns** | **Description** |
|--------|---------|-------------|
| `.to_millis()` | `Int` | Milliseconds |
| `.to_seconds()` | `Float` | Seconds |
| `.is_zero()` | `Bool` | True if zero |
| `.is_negative()` | `Bool` | True if negative |
| `.abs()` | `Duration` | Absolute value |

## Sleep

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `time.sleep(duration)` | `None` | Sleep for a Duration |
| `time.sleep_ms(ms)` | `None` | Sleep for milliseconds |
| `time.sleep_seconds(s)` | `None` | Sleep for seconds (Float) |

## Monotonic Time

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `monotonic_now_nanos()` | `Int` | Monotonic nanoseconds |
| `monotonic_now_millis()` | `Int` | Monotonic milliseconds |
| `measure(block)` | `TimedResult` | Time a block's execution |

## Calendar

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `time.current_year()` | `Int` | Current calendar year |
| `time.now_local()` | `ZonedDateTime` | Current time in system zone |

## Clock Abstraction

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `system_clock()` | `Clock` | Real system clock |
| `mock_clock(start)` | `Clock` | Deterministic mock clock |
| `set_clock(clock)` | `None` | Replace global clock |
| `reset_clock()` | `None` | Restore system clock |
| `with_clock(clock, block)` | `None` | Scoped clock override |

## Duration Arithmetic

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `add_duration(a, b)` | `Duration` | Sum of two durations |
| `sub_duration(a, b)` | `Duration` | Difference of two durations |
| `min_duration(a, b)` | `Duration` | Smaller of two durations |
| `max_duration(a, b)` | `Duration` | Larger of two durations |

## Instant Comparison

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `before(a, b)` | `Bool` | True if instant `a` is before `b` |
| `after(a, b)` | `Bool` | True if instant `a` is after `b` |
| `min_instant(a, b)` | `Instant` | Earlier of two instants |
| `max_instant(a, b)` | `Instant` | Later of two instants |

## ISO Formatting and Parsing

All parsing functions return `Result[T, TimeError]`. Use `import time` then `time.function_name()`.

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `format_iso_instant(instant)` | `Str` | Format an Instant as ISO 8601 UTC string |
| `parse_instant_iso(text)` | `Result[Instant, TimeError]` | Parse an ISO 8601 UTC string to Instant |
| `format_iso_date(d)` | `Str` | Format a LocalDate as ISO 8601 (YYYY-MM-DD) |
| `format_iso_time(t)` | `Str` | Format a LocalTime as ISO 8601 (HH:MM:SS.mmm) |
| `format_iso_datetime(dt)` | `Str` | Format a LocalDateTime as ISO 8601 |
| `parse_date_iso(text)` | `Result[LocalDate, TimeError]` | Parse an ISO 8601 date string |
| `parse_time_iso(text)` | `Result[LocalTime, TimeError]` | Parse an ISO 8601 time string |
| `parse_datetime_iso(text)` | `Result[LocalDateTime, TimeError]` | Parse an ISO 8601 datetime string |

## Calendar Types

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `date(year, month, day)` | `Result[LocalDate, TimeError]` | Construct a local date |
| `local_time(hour, minute, second, millisecond)` | `Result[LocalTime, TimeError]` | Construct a local time |
| `datetime(d, t)` | `LocalDateTime` | Combine a LocalDate and LocalTime |

### LocalDate Methods

| **Method** | **Returns** | **Description** |
|--------|---------|-------------|
| `.year()` | `Int` | Calendar year |
| `.month()` | `Int` | Month (1-12) |
| `.day()` | `Int` | Day of month (1-31) |

### LocalTime Methods

| **Method** | **Returns** | **Description** |
|--------|---------|-------------|
| `.hour()` | `Int` | Hour (0-23) |
| `.minute()` | `Int` | Minute (0-59) |
| `.second()` | `Int` | Second (0-59) |
| `.millisecond()` | `Int` | Millisecond (0-999) |

### LocalDateTime Methods

| **Method** | **Returns** | **Description** |
|--------|---------|-------------|
| `.date()` | `LocalDate` | The date component |
| `.time()` | `LocalTime` | The time component |

## Timezone

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `system_zone()` | `Str` | IANA name of the system timezone |
| `available_zones()` | `List[Str]` | All available IANA timezone names |
| `zone(name)` | `Result[Str, TimeError]` | Validate and return a timezone name |
| `now_in(tz)` | `Result[ZonedDateTime, TimeError]` | Current time in the given timezone |
| `convert_zone(dt, tz)` | `Result[ZonedDateTime, TimeError]` | Convert a ZonedDateTime to another timezone |
| `instant_in_zone(instant, tz)` | `Result[ZonedDateTime, TimeError]` | Convert an Instant to a ZonedDateTime in a timezone |

### ZonedDateTime Methods

| **Method** | **Returns** | **Description** |
|--------|---------|-------------|
| `.instant()` | `Instant` | The underlying UTC instant |
| `.zone()` | `Str` | IANA timezone name |
| `.year()` | `Int` | Local calendar year |
| `.month()` | `Int` | Local month (1-12) |
| `.day()` | `Int` | Local day of month (1-31) |
| `.hour()` | `Int` | Local hour (0-23) |
| `.minute()` | `Int` | Local minute (0-59) |
| `.second()` | `Int` | Local second (0-59) |

## Pattern Formatting

Patterns follow Java `DateTimeFormatter` conventions (e.g. `"yyyy-MM-dd HH:mm:ss"`).

| **Function** | **Returns** | **Description** |
|----------|---------|-------------|
| `format(instant, pattern, zone)` | `Result[Str, TimeError]` | Format an Instant using a pattern in a timezone |
| `format_local(dt, pattern)` | `Result[Str, TimeError]` | Format a LocalDateTime using a pattern |
| `parse_instant(text, pattern, zone)` | `Result[Instant, TimeError]` | Parse an Instant from text using a pattern and timezone |
| `parse_local_datetime(text, pattern)` | `Result[LocalDateTime, TimeError]` | Parse a LocalDateTime from text using a pattern |

## TimeError

A structured error returned by parsing, validation, and timezone functions.

| **Method** | **Returns** | **Description** |
|--------|---------|-------------|
| `.kind()` | `Str` | Error category (see below) |
| `.message()` | `Str` | Human-readable description |

Valid `.kind()` values:

| **Kind** | **When raised** |
|------|-------------|
| `"invalid_date"` | Year/month/day out of range or non-existent |
| `"invalid_time"` | Hour/minute/second/millisecond out of range |
| `"invalid_datetime"` | Combined date-time is invalid |
| `"invalid_zone"` | Timezone name not recognised |
| `"parse_error"` | Input text did not match the expected format |
| `"format_error"` | Pattern string is malformed |
| `"out_of_range"` | Value exceeds representable range |

Construct a TimeError directly with `time_error(kind, message)` → `TimeError`.
