using System.Globalization;
namespace MeterVault.Core.Tests.Analysis;
/// Frozen instants and zones for the period tests — nothing here reads the wall clock.
internal static class AnalysisClock
{
public static readonly TimeZoneInfo Berlin = TimeZoneInfo.FindSystemTimeZoneById("Europe/Berlin");
public static readonly TimeZoneInfo NewYork = TimeZoneInfo.FindSystemTimeZoneById("America/New_York");
/// An unambiguous local wall-clock time in , as an instant.
public static DateTimeOffset At(TimeZoneInfo zone, int year, int month, int day, int hour = 0, int minute = 0)
{
var wall = new DateTime(year, month, day, hour, minute, 0, DateTimeKind.Unspecified);
Assert.False(zone.IsInvalidTime(wall), $"{wall:s} does not exist in {zone.Id}");
Assert.False(zone.IsAmbiguousTime(wall), $"{wall:s} is ambiguous in {zone.Id}; give the offset");
return new DateTimeOffset(wall, zone.GetUtcOffset(wall));
}
/// A local wall-clock time with an explicit offset — for the hour an autumn fold repeats.
public static DateTimeOffset At(int year, int month, int day, int hour, int minute, int offsetHours) =>
new(year, month, day, hour, minute, 0, TimeSpan.FromHours(offsetHours));
public static DateTimeOffset Utc(int year, int month, int day, int hour = 0, int minute = 0) =>
new(year, month, day, hour, minute, 0, TimeSpan.Zero);
public static DateOnly Day(int year, int month, int day) => new(year, month, day);
public static DateOnly Iso(string date) => DateOnly.ParseExact(date, "yyyy-MM-dd", CultureInfo.InvariantCulture);
public static DateTimeOffset IsoInstant(string instant) =>
DateTimeOffset.ParseExact(instant, "yyyy-MM-dd'T'HH:mm'Z'", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
/// The wall clock an instant shows in , for readable assertions.
public static string Wall(DateTimeOffset instant, TimeZoneInfo zone) =>
TimeZoneInfo.ConvertTime(instant, zone).ToString("yyyy-MM-dd HH:mm zzz", CultureInfo.InvariantCulture);
}