namespace ScadaLink.CentralUI.Components;
///
/// Converts <input type="datetime-local"> values — which are always
/// expressed in the user's browser-local time zone — into UTC
/// s for querying.
///
/// CLAUDE.md mandates UTC throughout the system, but a datetime-local
/// value carries no offset, so it must be converted to UTC, not relabelled
/// as UTC. Relabelling (the CentralUI-008 bug) shifts every query window by the
/// user's offset for any non-UTC browser.
///
///
public static class BrowserTime
{
///
/// Converts a browser-local to UTC using the
/// browser's Date.getTimezoneOffset() result.
///
///
/// The wall-clock value from a datetime-local input, or null.
///
///
/// The value of JavaScript new Date().getTimezoneOffset(): the number
/// of minutes that, added to local time, yields UTC. It is positive
/// for time zones behind UTC (e.g. +300 for UTC-5) and negative for zones
/// ahead (e.g. -120 for UTC+2).
///
/// The equivalent instant in UTC, or null when the input is null.
public static DateTimeOffset? LocalInputToUtc(DateTime? localValue, int browserUtcOffsetMinutes)
{
if (localValue is not { } local)
return null;
// getTimezoneOffset() is defined as (UTC - local) in minutes, so
// UTC = local + offset.
var utc = DateTime.SpecifyKind(local, DateTimeKind.Unspecified)
.AddMinutes(browserUtcOffsetMinutes);
return new DateTimeOffset(utc, TimeSpan.Zero);
}
}