# Building and reading a TimeSpan

> How to build a duration and read it back. Construct one with new TimeSpan(...) or a TimeSpan.FromX factory (including TimeSpan.FromMilliseconds); then read either the WHOLE span in one unit — TimeSpan.TotalHours and friends, fractional — or the individual component in each slot — TimeSpan.Hours and friends, whole. The two are easy to confuse. On a negative span every component is negative.

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

## Summary        {#summary}
A `TimeSpan` is a duration ([TimeSpan (durations)](https://osysharp.com/reference/types/timespan/)). You **build** one with `new TimeSpan(...)` — the call the
runtime knows as `TimeSpan.New` — or a `TimeSpan.FromX` factory (`TimeSpan.FromDays`, `FromHours`,
`FromMinutes`, `FromSeconds`, `TimeSpan.FromMilliseconds`). You **read** it two ways that are easy to mix up:
the **totals** (`TimeSpan.TotalDays`, `TotalHours`, `TotalMinutes`, `TotalSeconds`, `TotalMilliseconds`) give
the whole span expressed in one unit, and the **parts** (`TimeSpan.Days`, `Hours`, `Minutes`, `Seconds`) give
the individual component in each slot.

## Signature      {#signature}
```osy syntax
new TimeSpan(<int> hours, <int> minutes, <int> seconds)              -> TimeSpan
new TimeSpan(<int> days, <int> hours, <int> minutes, <int> seconds)  -> TimeSpan
TimeSpan.FromMilliseconds(<number> n) -> TimeSpan     // (and FromDays/FromHours/FromMinutes/FromSeconds)

ts.TotalDays / TotalHours / TotalMinutes / TotalSeconds / TotalMilliseconds  -> double   // the WHOLE span, one unit
ts.Days / Hours / Minutes / Seconds  -> int                                              // the component PARTS
```

## Description    {#description}

### Building a span   {#building}
`new TimeSpan(h, m, s)` and `new TimeSpan(d, h, m, s)` build a span from whole components. The `TimeSpan.FromX`
factories build one from a single, possibly fractional, quantity: `TimeSpan.FromMilliseconds(1500)` is one and
a half seconds, and `TimeSpan.FromDays(1.5)` is a day and a half. (The factories are covered alongside the type
in [TimeSpan (durations)](https://osysharp.com/reference/types/timespan/); `TimeSpan.FromMilliseconds` completes the set here.)

### Totals vs parts — the distinction that trips people up   {#totals-vs-parts}
For the span **1 day, 2 hours, 3 minutes, 4 seconds**:

| Total (whole span, one unit — a `double`) | | Part (the component in that slot — an `int`) | |
|---|---|---|---|
| `TimeSpan.TotalDays` | `1.085462962962963` | `TimeSpan.Days` | `1` |
| `TimeSpan.TotalHours` | `26.051111111111112` | `TimeSpan.Hours` | `2` |
| `TimeSpan.TotalMinutes` | `1563.0666666666666` | `TimeSpan.Minutes` | `3` |
| `TimeSpan.TotalSeconds` | `93784` | `TimeSpan.Seconds` | `4` |
| `TimeSpan.TotalMilliseconds` | `93784000` | | |

`TotalHours` is the **entire** span measured in hours (`26.05…`); `Hours` is just the **hours slot** (`2`).
Totals are fractional (`double`); parts are whole (`int`).

### A negative span has negative components   {#negative}
Subtract a later time from an earlier one and the span is negative. Then **every** component is negative or
zero — `TimeSpan.FromHours(-2)` has `Hours` of `-2` and `Minutes` of `0` (not `60`), and `TotalHours` of `-2`.
Do not assume a component is non-negative.

Every one of these is a pure function of the value, so it runs **in the browser** with no round trip
([execution side](https://osysharp.com/reference/function/execution-side/)).

## Examples       {#examples}
```osy title="how long until a deadline, in whole minutes" test app=timespan
// The WHOLE span in minutes — TotalMinutes, not Minutes (which would drop the hours).
int MinutesUntil(DateTime deadline) {
  var left = deadline - DateTime.UtcNow;
  return Convert.ToInt(left.TotalMinutes);
}
```

```osy title="parts vs totals, and a negative span — pinned" run app=timespan
[Test]
void TimeSpan_parts_and_totals() {
  var span = new TimeSpan(1, 2, 3, 4);         // 1d 2h 3m 4s

  // component PARTS — the piece in each slot, as ints
  Assert.Equal(1, span.Days);
  Assert.Equal(2, span.Hours);                 // the hours SLOT — not the whole span in hours
  Assert.Equal(3, span.Minutes);
  Assert.Equal(4, span.Seconds);

  // a factory, read back through a part
  Assert.Equal(1, TimeSpan.FromMilliseconds(1500).Seconds);   // 1.5s → the seconds slot is 1

  // a NEGATIVE span: every component is negative or zero, never wrapped positive
  var neg = TimeSpan.FromHours(-2);
  Assert.Equal(-2, neg.Hours);
  Assert.Equal(0, neg.Minutes);
}
```

## See also       {#see-also}
- [TimeSpan (durations)](https://osysharp.com/reference/types/timespan/) — the duration type, its `FromX` factories, and storing it on an entity
- [TimeSpan, DateOnly, TimeOnly](https://osysharp.com/reference/types/duration-and-parts/) — `TimeSpan` with `DateOnly` / `TimeOnly`, and `DateTime` arithmetic
- [DateTime](https://osysharp.com/reference/types/datetime/) — subtracting two `DateTime`s to get a `TimeSpan`
