Skip to content

Instantly share code, notes, and snippets.

@skolima
Created April 1, 2020 14:46
Show Gist options
  • Save skolima/655c9b7803ad274c44f40d5221066101 to your computer and use it in GitHub Desktop.
Save skolima/655c9b7803ad274c44f40d5221066101 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using NodaTime;
using NodaTime.Extensions;
using Xunit;
namespace DaylightSavingTimeTests
{
public class DstCalculationsTests
{
[Theory]
[MemberData(nameof(DstTestCases))]
public void ShouldCalculateTimeDifferenceAsExpected(
ZonedDateTime from,
ZonedDateTime until,
Duration expectedDifference,
string description)
{
Assert.Equal(expectedDifference, until - from, new DurationWithMillisecondPrecisionComparer(5));
}
public static TheoryData<ZonedDateTime, ZonedDateTime, Duration, string> DstTestCases()
{
var clock = SystemClock.Instance;
var zonedClock = clock.InTzdbSystemDefaultZone();
var utcDayBeforeGermanDst = Instant.FromDateTimeUtc(new DateTime(2020, 3, 28, 11, 30, 00, DateTimeKind.Utc));
var utcDayAfterGermanDst = Instant.FromDateTimeUtc(new DateTime(2020, 3, 29, 15, 17, 00, DateTimeKind.Utc));
var utcDayBeforePolishWinterTime = Instant.FromDateTimeUtc(new DateTime(2019, 10, 26, 13, 45, 55, DateTimeKind.Utc));
var timeZoneSource = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default;
return new TheoryData<ZonedDateTime, ZonedDateTime, Duration, string>
{
{zonedClock.GetCurrentZonedDateTime(), clock.GetCurrentInstant().InUtc(), Duration.FromHours(0), "UtcNow and Now"},
{zonedClock.GetCurrentZonedDateTime(), zonedClock.GetCurrentZonedDateTime().PlusHours(1), Duration.FromHours(1), "One hour ahead, local time"},
{zonedClock.GetCurrentZonedDateTime(), zonedClock.GetCurrentZonedDateTime().PlusHours(24), Duration.FromHours(24), "One day ahead, local time"},
{
new ZonedDateTime(utcDayBeforeGermanDst, timeZoneSource.ForId("Europe/Berlin")),
new ZonedDateTime(utcDayBeforeGermanDst.Plus(Duration.FromDays(1)), timeZoneSource.ForId("Europe/Berlin")),
Duration.FromHours(24),
"One day ahead, across DST start in Germany"
},
{
new ZonedDateTime(utcDayAfterGermanDst, timeZoneSource.ForId("Europe/Berlin")),
new ZonedDateTime(utcDayAfterGermanDst.Minus(Duration.FromDays(2)), timeZoneSource.ForId("Europe/Berlin")),
Duration.FromHours(-48),
"Two days back, across DST start in Germany"
},
{
new ZonedDateTime(utcDayBeforePolishWinterTime, timeZoneSource.ForId("Europe/Warsaw")),
new ZonedDateTime(utcDayBeforePolishWinterTime.Plus(Duration.FromDays(2)), timeZoneSource.ForId("Europe/Warsaw")),
Duration.FromHours(48),
"Two days ahead, across DST end in Poland"
},
};
}
}
public class DurationWithMillisecondPrecisionComparer : IEqualityComparer<Duration>
{
private readonly int _millisecondPrecision;
public DurationWithMillisecondPrecisionComparer(int millisecondPrecision)
{
this._millisecondPrecision = millisecondPrecision;
}
public bool Equals(Duration x, Duration y)
{
var diff = (x - y).TotalMilliseconds;
return Math.Abs(diff) < this._millisecondPrecision;
}
public int GetHashCode(Duration obj)
{
return obj.GetHashCode();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment