Table of Contents

Struct DateRange

Namespace
DatabentoDotNet.Historical
Assembly
DatabentoDotNet.Historical.dll

A half-open UTC date interval: an inclusive Start date and an exclusive End date. Every Databento historical endpoint that queries by calendar date, rather than by exact instant, takes one of these.

public readonly record struct DateRange : IEquatable<DateRange>
Implements
Inherited Members

Examples

var day = new LocalDate(2024, 1, 2);

DateRange.OnDay(day);                                   // 2024-01-02 .. 2024-01-03
DateRange.Between(day, new LocalDate(2024, 2, 1));      // .. 2024-02-01, exclusive
DateRange.Including(day, new LocalDate(2024, 1, 31));   // the same range, named by its last day
DateRange.Spanning(day, Duration.FromDays(7));          // 2024-01-02 .. 2024-01-09

// Widened to the nanosecond instants the timeseries and metadata endpoints take.
DateTimeRange range = DateRange.OnDay(day).ToDateTimeRange();

// Rejected here rather than by an HTTP 422 that bills for the round trip: End must be strictly
// after Start.
DateRange.Between(day, day);   // throws ArgumentException

Remarks

Port of upstream's DateRange (databento-rs/src/historical.rs). Rust spells "which end is exclusive" with the range type itself — Range<Date> for half-open, RangeInclusive<Date> for inclusive — because a Rust range is a type. C# has no range literal to overload against, so the upstream From impls become named factories instead: OnDay(LocalDate), Between(LocalDate, LocalDate), Including(LocalDate, LocalDate), Spanning(LocalDate, Duration). Each name says, on its own, which end is exclusive — a half-open interval is exactly the kind of API a caller misreads silently, and nothing here reuses a bare constructor that would hide that choice.

An empty or inverted range is rejected at constructionEnd must be strictly after Start. Upstream sends whatever a caller built and lets the API answer with an error. This port fails locally instead, the same way this codebase's Symbols type already rejects a symbol carrying a character the wire format reserves: the offending pair is still in the caller's hand at the point it is rejected, rather than round-tripping to the server to learn the same thing from an HTTP error that bills for the request. See the M3 ROADMAP decision record for the full reasoning.

Properties

End

The exclusive UTC end date.

public LocalDate End { get; }

Property Value

LocalDate

EndIsoDate

This range's End, rendered the way the historical API's end_date parameter expects it: yyyy-MM-dd.

public string EndIsoDate { get; }

Property Value

string

Exceptions

InvalidOperationException

This is a default DateRange value.

Start

The inclusive UTC start date.

public LocalDate Start { get; }

Property Value

LocalDate

StartIsoDate

This range's Start, rendered the way the historical API's start_date parameter expects it: yyyy-MM-dd.

public string StartIsoDate { get; }

Property Value

string

Exceptions

InvalidOperationException

This is a default DateRange value.

Methods

Between(LocalDate, LocalDate)

A half-open range: start is included, end is not.

public static DateRange Between(LocalDate start, LocalDate end)

Parameters

start LocalDate

The inclusive start date.

end LocalDate

The exclusive end date.

Returns

DateRange

The range.

Exceptions

ArgumentException

end is not strictly after start.

Including(LocalDate, LocalDate)

A range where both start and lastDay are included.

public static DateRange Including(LocalDate start, LocalDate lastDay)

Parameters

start LocalDate

The inclusive start date.

lastDay LocalDate

The last day the range covers, inclusive.

Returns

DateRange

The range, whose exclusive End is the day after lastDay.

Exceptions

ArgumentException

lastDay is before start.

OnDay(LocalDate)

A range covering exactly one UTC calendar day.

public static DateRange OnDay(LocalDate date)

Parameters

date LocalDate

The day.

Returns

DateRange

A range from date to the following day.

Spanning(LocalDate, Duration)

A range starting at start and spanning duration, counting only whole days.

public static DateRange Spanning(LocalDate start, Duration duration)

Parameters

start LocalDate

The inclusive start date.

duration Duration

How long the range spans, truncated down to whole days.

Returns

DateRange

The range.

Remarks

A calendar date carries no time of day, so a duration shorter than 24 hours contributes no day to the range at all — this matches upstream's own Date + Duration, which adds duration.whole_days(). Upstream's own test for this construction (date_range_from_lt_day_duration) passes a one-second duration and asserts the resulting range is empty (start == end). This port does not carry that case forward: Validate(LocalDate, LocalDate, string) runs here exactly as it does in every other factory, so a duration under one day is rejected rather than silently producing a range that would query no data.

Exceptions

ArgumentException

duration spans fewer than one whole day.

ToDateTimeRange()

Widens this date range to a DateTimeRange, at UTC midnight on each end.

public DateTimeRange ToDateTimeRange()

Returns

DateTimeRange

A DateTimeRange whose Start and End are UTC midnight on Start and End respectively.

ToString()

A debugging-oriented description, printing Start and End directly rather than through StartIsoDate/EndIsoDate.

public override string ToString()

Returns

string

The description.

Remarks

A hand-written override, not the compiler-synthesized record ToString: that synthesized version prints every public property, including StartIsoDate and EndIsoDate — which would make a supposedly inert ToString() call throw InvalidOperationException for a default value, defeating the point of leaving it unguarded. Printing Start/End instead never throws, for any value including default.