# Current time (DateTime.UtcNow, DurableClock.Now)

> Read the current instant. `DateTime.UtcNow`/`Today` (and the platform-idiomatic `DurableClock.Now`/…) return the current time from the platform's replay-safe clock — so durable functions resume deterministically and any time-reading logic is time-travel-testable. All are UTC; there is no separate DateTimeOffset type, and `DateTime.Now` names the same instant as `UtcNow`. To read that instant as somebody's wall clock, name their zone.

<!-- id: function-current-time · area: function · stability: stable · html: https://osysharp.com/reference/function/current-time/ -->

## Summary        {#summary}
**`DateTime.UtcNow`** and **`DateTime.Today`** read the current instant, anywhere. Pasted C# that reads "now" runs
unchanged.

Inside a **workflow or durable body**, reach for **`DurableClock.Now` / `.UtcNow` / `.Today`** instead. They read the
instant the ENGINE is processing at — the same one every clock armed on that pass derives from, and the one a pinned
test clock moves. That is the whole difference: `DateTime.UtcNow` in a workflow body answers whatever the machine
says right now, which is neither replay-stable nor testable.

There are three clocks in total, and each is legal exactly where it means something:

| you want | write | where |
|---|---|---|
| the engine's instant, replay-stable | `DurableClock.UtcNow` | a workflow or durable body |
| a one-shot reading of now | `DateTime.UtcNow` | anywhere |
| a value that KEEPS MOVING on screen | `DateTime.UtcNow` | anything that runs on a RENDER PASS — a `render` block, and any method render calls. See [below](#on-screen) |

Reach for the wrong one and the compiler says which to pick: `DurableClock` in a `render` block is refused (it would
freeze at first paint), and outside a durable execution it fails loudly rather than quietly reading wall time.

⚠ **The boundary is WHEN THE CODE RUNS, not which body it is written in.** Pulling a render expression out into a
well-named method does not move it off the render path — it still runs on every pass, so it still wants `DateTime.UtcNow`,
and a `DateTime.UtcNow` left behind there freezes the page exactly as it would have in the slot:

```osy syntax
bool IsDue(Plant p, DateTime now) => p.LastWateredAt.AddDays(p.EveryDays) <= now;  // the instant is passed IN
// ⛔ NOT `bool IsDue(Plant p) => … <= DateTime.UtcNow;` — a clock read INSIDE a helper does not advance, and the
//    compiler refuses it from a `live var`: "Reactivity is decided where the read is WRITTEN, not where the
//    function is called." Read it at the call site — `items.Where(p => IsDue(p, DateTime.UtcNow))`.
action Water(Plant p) { p.LastWateredAt = DateTime.UtcNow; }              // runs once per press → the one-shot read
```

`osy lint` follows the calls, so it flags the first form written with `DateTime.UtcNow` and stays silent on a method
only an action reaches.

⚠ **Every `Now` spelling answers the same instant** — `DateTime.Now`, `DateTime.UtcNow`, `DateTimeOffset.Now`,
`DateTimeOffset.UtcNow`. That is not an alias papering over a difference: this platform has no local-time `DateTime`
for them to differ by. To read the instant as somebody's wall clock, say whose:
`DateTime.UtcNow.InZone(Zone.Of("Europe/Stockholm"))`. See [Time zones — the Zone type and its operations](https://osysharp.com/reference/stdlib/zones/).

### On screen: the clock that keeps moving        {#on-screen}

A reactive context — a `live var` or a render slot — subscribes to the clock, so a value derived from it counts down
on screen with no refetch, no polling and no code beyond the expression:

```osy syntax
live var left = deadline - DateTime.UtcNow;        // ✓ advances
var openedAt  = DateTime.UtcNow;                   // ✓ reads once — the instant the page mounted
```

Every reader on a page ticks **together** — one clock per page, not one per row — so two countdowns never disagree
about what second it is. The cadence is one second; that is a display rate, not a precision claim. A page that never
reads the clock starts no timer and costs nothing.

⚠ **On screen it is a DISPLAY clock, never an authority.** It is the browser's wall clock, so a viewer whose machine
is skewed sees a skewed countdown:

- **Nothing may be decided on it.** Whether an SLA breached, whether an offer expired, whether a token is still
  valid — those are settled on the server against the server's clock and arrive as data. Render that answer.
- The honest division: the server decides **what is true**; the display clock animates **an interval whose endpoint
  is already known**.

## Signature      {#signature}
```osy syntax
DateTime.UtcNow                   // the current instant (UTC)
DateTime.Now                      // the same instant — everything here is UTC
DateTime.Today                    // the current date at midnight (UTC)
DurableClock.Now / .UtcNow / .Today   // inside a workflow/durable body: the ENGINE's instant
DateTimeOffset.Now / .UtcNow      // yields a DateTime (there is no DateTimeOffset type)
```

## Description    {#description}
The platform owns "now". Because a durable function can suspend and resume, a naive system clock would return a
different value on resume and corrupt replay — so every current-time read goes through the platform clock, which
returns the **same instant on replay**. The same mechanism makes time-reading logic **time-travel-testable**: a test
can fix the clock and assert behavior at a chosen moment.

The platform is **UTC-internal**, and that is what makes every `Now` spelling mean one thing. A `DateTime` here *is*
a UTC instant, not a wall-clock-plus-timezone reading, because a server has no single "local" zone to be correct
for — 9am in Frankfurt and 5pm in Tokyo are the same instant, and that instant is what the value holds. So `Now` and
`UtcNow` are not two readings the language collapses into one; there is only ever one reading, and both names say it.
`DateTimeOffset.Now`/`.UtcNow` yield a plain `DateTime` (there is no separate `DateTimeOffset` type), and
`DateTime.Today` is the current date at midnight.

**"Local time" is a question about a person, not about the platform** — which is why it is asked for rather than
assumed. Naming the zone is the whole answer, and it is one line:

```osy syntax
var instant = DateTime.UtcNow;                                  // the fact
var local   = instant.InZone(Zone.Of("Europe/Stockholm"));         // …read as somebody's wall clock
```

Stored and computed `DateTime`s stay UTC; the zone belongs at the display edge, where you know whose it is.

These are current-instant reads, so they run **in memory** (they are not deterministic SQL expressions).

**Parsing and formatting.** `DateTime.Parse(s)` turns a string into a `DateTime` (and `DateOnly.Parse` /
`TimeOnly.Parse` / `TimeSpan.Parse` for the others); each throws on an unparseable string. `value.ToString("fmt")`
formats a date/time/duration with a standard .NET/C# format string (the same engine as a `$"{d:fmt}"` interpolation
hole) — e.g. `d.ToString("yyyy-MM-dd")`. Both are in-memory.

## Examples       {#examples}
```osy title="stamp a row, then ask how old it is" test app=function-current-time
entity Ticket {
  [Required, MaxLength(200)] string Title;
  DateTime DueAt;
}

Ticket Open(string title) {
  return new Ticket { Title = title, DueAt = DateTime.UtcNow + TimeSpan.FromDays(7) };   // faithful C# — the platform clock
}

bool IsOverdue(Ticket t) {
  return DateTime.UtcNow > t.DueAt;
}

bool OpenedRecently(Ticket t) {
  // `CreatedAt` is provided for you — every entity is audited automatically, so you never declare it.
  return DateTime.UtcNow - t.CreatedAt < TimeSpan.FromHours(1);       // TimeSpan arithmetic — see [TimeSpan (durations)](https://osysharp.com/reference/types/timespan/)
}
```

## See also       {#see-also}
- [TimeSpan (durations)](https://osysharp.com/reference/types/timespan/) — durations, and `DateTime`/`TimeSpan` arithmetic
