namespace Nonemm.Core.Tests; public class SunTimesTests { private static readonly TimeSpan CloseEnough = TimeSpan.FromMinutes(3); private static void Near(string expected, DateTime actual) => Assert.True( (DateTime.Parse(expected, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AdjustToUniversal | System.Globalization.DateTimeStyles.AssumeUniversal) - actual).Duration() < CloseEnough, $"expected about {expected}, got {actual:yyyy-MM-dd HH:mm}Z"); [Fact] public void MidsummerInLondon() { (DateTime rise, DateTime set) = Assert.IsType<(DateTime, DateTime)>( SunTimes.For(51.48, -0.13, new DateTime(2026, 6, 21, 0, 0, 0, DateTimeKind.Utc))); Near("2026-06-21T03:43Z", rise); Near("2026-06-21T20:21Z", set); } [Fact] public void MidwinterInLondon() { (DateTime rise, DateTime set) = Assert.IsType<(DateTime, DateTime)>( SunTimes.For(51.48, -0.13, new DateTime(2026, 12, 21, 0, 0, 0, DateTimeKind.Utc))); Near("2026-12-21T08:04Z", rise); Near("2026-12-21T15:53Z", set); } [Fact] public void TheEquinoxIsAboutSixToSixEverywhereOnTheEquator() { (DateTime rise, DateTime set) = Assert.IsType<(DateTime, DateTime)>( SunTimes.For(0, 0, new DateTime(2026, 3, 20, 0, 0, 0, DateTimeKind.Utc))); Near("2026-03-20T06:04Z", rise); Near("2026-03-20T18:10Z", set); } [Fact] public void SouthOfTheEquatorTheSeasonsAreTheOtherWayRound() { (DateTime rise, DateTime set) = Assert.IsType<(DateTime, DateTime)>( SunTimes.For(-33.87, 151.21, new DateTime(2026, 6, 21, 0, 0, 0, DateTimeKind.Utc))); Near("2026-06-20T21:00Z", rise); Near("2026-06-21T06:54Z", set); } [Fact] public void InsideTheArcticCircleTheSunDoesNotSetInJune() => Assert.Null(SunTimes.For(78.22, 15.65, new DateTime(2026, 6, 21, 0, 0, 0, DateTimeKind.Utc))); }