Table of Contents

Class DbnTime

Namespace
DatabentoDotNet.Dbn
Assembly
DatabentoDotNet.Dbn.dll

Converts between DBN's on-the-wire ulong nanosecond timestamps and NodaTime's Instant and LocalDate.

public static class DbnTime
Inheritance
DbnTime
Inherited Members

Examples

using DatabentoDotNet.Dbn;
using NodaTime;

// ts_recv for 2020-12-28T13:00:00.000000001Z. The trailing 1 is a nanosecond, which is what a
// DateTime tick — 100 of them — cannot represent and an Instant can.
ulong raw = 1609160400000000001;

Instant when = DbnTime.ToInstant(raw);              // 2020-12-28T13:00:00.000000001Z
LocalDate day = DbnTime.ToUtcDate(raw);             // 2020-12-28, the date a symbol map keys on
ulong roundTripped = DbnTime.ToUnixNanoseconds(when);   // exactly `raw` again

// The sentinel is not a time, and every conversion here says so rather than answering.
if (!DbnTime.TryToInstant(DbnConstants.UndefTimestamp, out Instant absent))
{
    Console.WriteLine("no timestamp");
}

Use the Try pair wherever an absent timestamp is an ordinary outcome — most optional record fields — and ToInstant(ulong) or ToUtcDate(ulong) where it is not, so a sentinel throws instead of becoming a plausible wrong answer:

if (record.TryGet(out ImbalanceMsg imbalance)
    && DbnTime.TryToInstant(imbalance.AuctionTime, out Instant auction))
{
    Console.WriteLine($"auction at {auction}");
}

Remarks

This is the boundary. Record struct fields and the codec keep raw ulong nanoseconds, because a record is reinterpreted in place over the read buffer and a field's type is its wire layout — Instant is 16 bytes and LocalDate is 4, where the wire has an 8-byte u64. Everything above the codec uses NodaTime. This type is the only crossing, and it is deliberately explicit: there is no implicit conversion to fall into.

Every conversion checks UndefTimestamp first, and that check is the whole reason this type exists. The sentinel is MaxValue, and the obvious conversion wraps it silently:

Duration.FromNanoseconds((long)DbnConstants.UndefTimestamp)   // -1 ns. No exception.

That resolves to an Instant one nanosecond before the UNIX epoch — 1969-12-31T23:59:59.999999999Z, a confidently wrong answer that nothing downstream would question. The sentinel does no better as a date: it floor-divides to a perfectly plausible day in 2554. So TryToInstant(ulong, out Instant) and TryToUtcDate(ulong, out LocalDate) report "no timestamp" by returning false, and ToInstant(ulong) and ToUtcDate(ulong) throw rather than answer.

Apart from the sentinel, every ulong converts exactly. The conversion splits into whole days plus a nanosecond-of-day remainder rather than going through a single long nanosecond count, so it never touches the year-2262 ceiling that long.MaxValue nanoseconds imposes. MaxValue minus one nanosecond is in 2554, well inside Instant's range.

Methods

IsUndefined(ulong)

Reports whether a raw timestamp is DBN's "no timestamp" sentinel, UndefTimestamp.

public static bool IsUndefined(ulong unixNanoseconds)

Parameters

unixNanoseconds ulong

The raw timestamp to test.

Returns

bool

true when the timestamp is undefined.

ToInstant(ulong)

Converts a raw DBN timestamp to an Instant.

public static Instant ToInstant(ulong unixNanoseconds)

Parameters

unixNanoseconds ulong

Nanoseconds since the UNIX epoch, as read from the wire.

Returns

Instant

The converted instant.

Exceptions

ArgumentOutOfRangeException

unixNanoseconds is UndefTimestamp, which is not a time. Use TryToInstant(ulong, out Instant) where an absent timestamp is expected.

ToUnixNanoseconds(Instant)

Converts an Instant back to the raw ulong nanoseconds DBN puts on the wire.

public static ulong ToUnixNanoseconds(Instant instant)

Parameters

instant Instant

The instant to convert.

Returns

ulong

Nanoseconds since the UNIX epoch.

Exceptions

ArgumentOutOfRangeException

instant is before the UNIX epoch, or so far after it that it does not fit in a ulong — or that it would land exactly on UndefTimestamp and read back as "no timestamp".

ToUnixNanosecondsAtMidnightUtc(LocalDate)

Converts a UTC calendar date to the raw ulong nanoseconds of its 00:00 UTC midnight.

public static ulong ToUnixNanosecondsAtMidnightUtc(LocalDate date)

Parameters

date LocalDate

The UTC date.

Returns

ulong

Nanoseconds since the UNIX epoch at 00:00 UTC on date.

Remarks

The inverse of ToUtcDate(ulong) only in the direction that loses nothing: every timestamp on a given day maps to that day, and the day maps back to its first nanosecond.

Exceptions

ArgumentOutOfRangeException

date is before 1970-01-01, or so far after it that its midnight does not fit in a ulong nanosecond count.

ToUtcDate(ulong)

Converts a raw DBN timestamp to the UTC calendar date it falls on.

public static LocalDate ToUtcDate(ulong unixNanoseconds)

Parameters

unixNanoseconds ulong

Nanoseconds since the UNIX epoch, as read from the wire.

Returns

LocalDate

The UTC date.

Exceptions

ArgumentOutOfRangeException

unixNanoseconds is UndefTimestamp. It would otherwise floor-divide to an entirely plausible day in 2554.

TryToInstant(ulong, out Instant)

Converts a raw DBN timestamp to an Instant, unless it is the undefined sentinel.

public static bool TryToInstant(ulong unixNanoseconds, out Instant instant)

Parameters

unixNanoseconds ulong

Nanoseconds since the UNIX epoch, as read from the wire.

instant Instant

Receives the converted instant, or default when unixNanoseconds is UndefTimestamp.

Returns

bool

false when the timestamp is undefined — the only value that does not convert. Every other ulong converts exactly.

TryToUtcDate(ulong, out LocalDate)

Converts a raw DBN timestamp to the UTC calendar date it falls on, unless it is the undefined sentinel.

public static bool TryToUtcDate(ulong unixNanoseconds, out LocalDate date)

Parameters

unixNanoseconds ulong

Nanoseconds since the UNIX epoch, as read from the wire.

date LocalDate

Receives the UTC date, or default when unixNanoseconds is UndefTimestamp.

Returns

bool

false when the timestamp is undefined.

Remarks

This is the date the symbol maps key on — see TryGetSymbol(LocalDate, uint, out string?).