Skip to content

Shift and Expand on ranges (move by a delta, buffer both sides) #101

Closed

Description

@CaffeinatedCoder

Intervals.NET offers Shift and Expand through its domain packages (https://www.nuget.org/packages/Intervals.NET); Guava's ContiguousSet and Boost.ICL expose the arithmetic through the domain type. The library has no way to move a range or to grow it on both sides, so "the same slot one week later" and "the booking plus a 15-minute buffer on each side" are a deconstruct-and-rebuild per shape today.

Proposed API (per type, since T arithmetic is not generic):

  • Shift(delta) — DateRange.Shift(int days), DateTimeRange.Shift(TimeSpan), DateTimeOffsetRange.Shift(TimeSpan), TimeRange.Shift(TimeSpan), Int32Range.Shift(int), Int64Range.Shift(long), DecimalRange.Shift(decimal); NodaTime LocalDateRange.Shift(Period), InstantRange.Shift(Duration), YearMonthRange.Shift(int months). Bounds and inclusiveness move together; Empty and Infinite return themselves; an unbounded side stays unbounded.
  • Expand(amount) — grows both bounds outward by amount (a negative amount shrinks; a result that inverts is Empty, as CreateFinite already does).

Overflow at the extremes (int.MaxValue, DateOnly.MaxValue) throws rather than wrapping, like NextValueAfter returning null.

Translation: PostgreSQL has no range arithmetic, so the rebuilt constructor: int4range(lower(r) + @d, upper(r) + @d) for the discrete types (canonical [), so the flags are fixed), and for the continuous ones numrange(lower(r) + @d, upper(r) + @d, CASE … lower_inc/upper_inc … END) with the same flag handling CreateFinite uses (E08 requires constant flags today; this needs the CASE form or stays in-memory and says so).

Done when: Shift and Expand are in docs/ranges.md, held by claims, swept by the small-model oracle (Shift(d).Shift(-d) == this, Expand(a).Contains(this)), and either translated with a live test or listed under "runs in memory only" with the reason.

Found by the comparable-library survey (Intervals.NET), 2026-10-17.

Activity

  1. added
    enhancementNew feature or request
    area/rangesRange unions, variants and the shape engines
    package/nodatimeAffects CodoMetis.ValueRanges.NodaTime
    package/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQL
    package/coreAffects CodoMetis.ValueRanges
    on Oct 17, 2026
  2. added this to the 10.0.0 milestone on Oct 18, 2026
  3. CaffeinatedCoder commented on Oct 18, 2026

    @CaffeinatedCoder
    OwnerAuthor

    Decided in #185: Shift and Expand run in memory only. The CASE-on-flags rebuild was measured on PostgreSQL 18 and differs from memory four ways: 'empty' rebuilds as (,), time + interval wraps at midnight (TimeRange throws), timestamptz + interval '1 day' is 23 hours across a DST change in the session time zone, and 'infinity'::date + 1 stays infinity (DateOnly.MaxValue overflows). Listed under docs/efcore.md#what-runs-where with those reasons. LocalDateTimeRange gets the members too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/rangesRange unions, variants and the shape enginesenhancementNew feature or requestpackage/coreAffects CodoMetis.ValueRangespackage/efcoreAffects CodoMetis.ValueRanges.EFCore.PostgreSQLpackage/nodatimeAffects CodoMetis.ValueRanges.NodaTime

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions