Table of Contents

Persistence and schedule-zone conversions — System Clock, testing

These tests compare IPrimeTime schedule-zone projections against TimeZoneInfo.ConvertTime and verify DateOnly / TimeOnly recombination matches the wall DateTime from ToScheduleDateTimeOffset.

For the conceptual background, see Persistence and time conversions.

/// <summary>
/// Verifies schedule-zone <see cref="DateTimeOffset"/> projection matches
/// <see cref="TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo)"/> for the clock zone.
/// </summary>
[Fact]
public void PersistedUtc_ToScheduleZone_MatchesTimeZoneInfoConvertTime ()
{
    DateTimeOffset persistedUtc = new(2025, 7, 4, 15, 30, 0, TimeSpan.Zero);
    IPrimeTestClock clock = new PrimeTestClock(persistedUtc);
    IPrimeTime time = clock;

    DateTimeOffset projected = time.ToScheduleDateTimeOffset(persistedUtc);
    DateTimeOffset expected = TimeZoneInfo.ConvertTime(persistedUtc, clock.LocalScheduleTimeZone);
    projected.Should().Be(expected);
}

/// <summary>
/// Verifies <see cref="DateOnly"/> and <see cref="TimeOnly"/> extracted from a persisted instant
/// recombine to the schedule-local wall clock.
/// </summary>
[Fact]
public void PersistedUtc_ToScheduleDateAndTime_RecombinesToWallDateTime ()
{
    DateTimeOffset persistedUtc = new(2025, 7, 4, 15, 30, 0, TimeSpan.Zero);
    IPrimeTestClock clock = new PrimeTestClock(persistedUtc);
    IPrimeTime time = clock;

    DateTimeOffset inZone = time.ToScheduleDateTimeOffset(persistedUtc);
    DateOnly date = time.ToScheduleDateOnly(persistedUtc);
    TimeOnly timeOfDay = time.ToScheduleTimeOnly(persistedUtc);
    DateTime wall = date.ToDateTime(timeOfDay);
    wall.Should().Be(inZone.DateTime);
}

What to notice

  • ToScheduleDateTimeOffset(persistedUtc) matches TimeZoneInfo.ConvertTime(persistedUtc, clock.LocalScheduleTimeZone).
  • DateOnly + TimeOnly round-trip to the same local wall DateTime as the zoned offset’s DateTime property.