Time-of-day and DST (testing) — System Clock stack
Deterministic DST tests under a virtual PrimeTestClock. The System Clock stack does not bundle a TZDB zone library, so the examples lean on environment probes for invalid/ambiguous calendar samples plus a stable virtual-clock advancement check.
/// <summary>
/// When the machine exposes a spring-forward gap example, documents that the BCL marks that
/// wall-clock value as invalid for <see cref="TimeZoneInfo.Local"/>.
/// </summary>
[Fact]
public void MachineProbe_InvalidExample_WhenPresent_IsInvalidLocalTime ()
{
TestEnvironmentDescriptor descriptor = TestEnvironmentDescriptor.FromLocalMachine();
if (descriptor.InvalidLocalWallClockExample is not DateTime invalid)
{
return;
}
TimeZoneInfo.Local.IsInvalidTime(invalid).Should().BeTrue();
}
/// <summary>
/// When the machine exposes a fall-back ambiguous example, documents that the BCL reports two
/// distinct UTC offsets for the same local wall-clock calendar value.
/// </summary>
[Fact]
public void MachineProbe_AmbiguousExample_WhenPresent_HasTwoOffsets ()
{
TestEnvironmentDescriptor descriptor = TestEnvironmentDescriptor.FromLocalMachine();
if (descriptor.AmbiguousLocalWallClockExample is not DateTime ambiguous)
{
return;
}
TimeZoneInfo.Local.IsAmbiguousTime(ambiguous).Should().BeTrue();
TimeSpan[] offsets = TimeZoneInfo.Local.GetAmbiguousTimeOffsets(ambiguous);
offsets.Should().HaveCount(2);
}
/// <summary>
/// Verifies advancing virtual UTC time across a long step does not throw for the default test clock,
/// providing a stable baseline on hosts without rich DST probe data.
/// </summary>
[Fact]
public void VirtualClock_AdvanceLargeStep_Completes ()
{
IPrimeTestClock clock = new PrimeTestClock(new DateTimeOffset(2025, 1, 1, 0, 0, 0, TimeSpan.Zero));
Action act = () => clock.Advance(TimeSpan.FromDays(400));
act.Should().NotThrow();
}
What to notice
TestEnvironmentDescriptor.FromLocalMachine()wraps the host'sTimeZoneInfo.Local. It returnsnullfor the invalid/ambiguous samples on hosts without DST data, so each test early-returns instead of asserting against a missing sample.- The third test demonstrates a stable baseline: advancing the virtual clock 400 days never throws, regardless of DST behavior of the host.
- For deterministic DST behavior independent of the host, prefer the PrimeTime / NodaTime stack, which can construct a
PrimeTestClockagainst a fixed TZDBDateTimeZone.
Related
- Time-of-day and DST (production) — wall-clock scheduling and environment probes in the example app.
- Test-clock control APIs —
Set*,Advance,RunFor,Start/Stopreference for both stacks. - API:
IPrimeTestClock