Osy#betaRun it on Osyrin: osyrin.com

Reference / Types

TimeSpan (durations)

TimeSpan — a duration; TimeSpan.FromHours(2), new TimeSpan(h, m, s), ts.TotalMinutes, ts.Hours

`TimeSpan` is the duration type — a length of time, as in C#. Build one with the `TimeSpan.FromX` factories or `new TimeSpan(…)`, read `.TotalHours`/`.TotalMinutes`/… (fractional) or `.Days`/`.Hours`/… (whole components), and store it on an entity like any scalar. Evaluated in memory.

preview2 examples compiled by CItypesdatetimetimespanduration

Summary#

TimeSpan is a duration — a length of time — exactly as in C#. It is a first-class scalar: you can declare a TimeSpan local, pass it to a function, and store it on an entity (persisted as an interval). Build one with the TimeSpan.FromX factories or the new TimeSpan(…) constructor; read its total or component parts through members.

Signature#

TimeSpan.FromDays(n) / FromHours(n) / FromMinutes(n) / FromSeconds(n) / FromMilliseconds(n)   // factories
new TimeSpan(hours, minutes, seconds)              // constructor (h/m/s)
new TimeSpan(days, hours, minutes, seconds)        // constructor (d/h/m/s)
ts.TotalDays / TotalHours / TotalMinutes / TotalSeconds / TotalMilliseconds   // fractional whole-span totals (double)
ts.Days / Hours / Minutes / Seconds                // whole component parts (int)
TimeSpan.FromTicks(n) / ts.Ticks                   // the duration as one integer, in 100ns ticks (long)

Description#

A factory takes a numeric count and returns the duration: TimeSpan.FromHours(2) is two hours. The constructor takes whole components — new TimeSpan(1, 30, 0) is one hour thirty minutes (h, m, s), and the four-argument form leads with days.

The .TotalX members give the whole span measured in that unit, as a fractional double — TimeSpan.FromMinutes(90).TotalHours is 1.5. The component members (.Days, .Hours, .Minutes, .Seconds) give the whole-number parts of the breakdown — for new TimeSpan(1, 2, 30, 0), .Days is 1 and .Hours is 2.

A TimeSpan entity property is stored and read back faithfully:

entity WorkItem {
  [Required, MaxLength(200)] string Title;
  TimeSpan Estimate;
}

TimeSpan DefaultEstimate() {
  return new TimeSpan(1, 30, 0);          // 1h30m — the (h, m, s) constructor
}

double EstimateInHours(WorkItem w) {
  return w.Estimate.TotalHours;           // 90 minutes → 1.5
}

TimeSpan Remaining(WorkItem w, TimeSpan spent) {
  return w.Estimate - spent;              // durations subtract, exactly as in C#
}

long EstimateTicks(WorkItem w) {
  return w.Estimate.Ticks;                // the whole duration as one integer — a `long`, always
}

TimeSpan SpanFromTicks(long ticks) {
  return TimeSpan.FromTicks(ticks);       // …and the exact way back
}

The tick — a duration as one exact integer#

A tick is 100 nanoseconds, the unit .NET measures time in, and it is how a duration becomes a single whole number you can store, compare or put on a wire. ts.Ticks reads one and TimeSpan.FromTicks(n) builds the duration back, with no loss in either direction:

long precise = TimeSpan.FromMinutes(90).Ticks;    // 54000000000
var same     = TimeSpan.FromTicks(precise);       // ninety minutes again

⚠ .Ticks answers a long, never an int — one hour is already 36 billion ticks, well past int's range, so the local or the field that holds one must say long.

It is the same unit an instant is read with: Date.Ticks(d) (see Reading a date — Year, Month, Day, Hour, Minute, Second, DayOfWeek, DayOfYear, Date) counts ticks since 0001-01-01, so the two agree — Date.Ticks(b) - Date.Ticks(a) and (b - a).Ticks are the same number.

Reach for ticks when you want exactness, an ordering key, or a compact interchange value. For anything a person reads, prefer .TotalMinutes and the component members: a tick count is precise and unreadable.

Arithmetic and comparison are C#-faithful:

  • dateTime2 - dateTime1 → a TimeSpan (how much time elapsed).
  • dateTime + timeSpan / dateTime - timeSpan → a shifted DateTime.
  • timeSpan1 + timeSpan2 / timeSpan1 - timeSpan2 → a TimeSpan; timeSpan * n scales one.
  • <, <=, >, >=, ==, != compare two TimeSpans (and two DateTimes).

The same operators work inside a query that runs in the database: Order.Where(o => o.ShippedAt - o.PlacedAt > TimeSpan.FromDays(2)) is answered there, by the instant. A DateTimeOffset mixes in exactly as C# mixes it — dateTime - dateTimeOffset is a TimeSpan too ([[types-datetimeoffset#mixing]]).

Examples#

Factories, components, and DateTime/TimeSpan arithmetic — the window/debounce shape:

double QuotaMinutes() {
  var quota = TimeSpan.FromHours(2);
  return quota.TotalMinutes;                       // 120.0
}

int LeadDays() {
  var span = new TimeSpan(1, 2, 30, 0);            // 1d 2h 30m
  return span.Days;                                // 1
}

TimeSpan Elapsed(DateTime start, DateTime end) {
  return end - start;                              // DateTime − DateTime → TimeSpan
}

bool LongEnough(DateTime start, DateTime end) {
  return (end - start) >= TimeSpan.FromHours(2);   // arithmetic + comparison
}

A TimeSpan is also a normal entity column:

entity WorkItem {
  string Title;
  TimeSpan Estimate;      // stored as an interval; read back as a TimeSpan
}

See also#

Related

namespace

Declares the namespace a file's types belong to, written once at the top of the file. It is optional — a file without…

Numeric types & literal suffixes

The platform numeric types are int, long, decimal, and double. Literals follow C# exactly, suffixes (L, m, d) included:…