Files
HellionChat/HellionChat/Ui/Components/ClockPair.cs
T
JonKazama-Hellion 3b5001e616 feat(chat): local and server time side by side, and a quieter header
Both clocks in the status bar, in the game's own LT/ST notation. Anyone agreeing
on a time across regions reads them off one line instead of doing the arithmetic
in their head.

Server time is not computed here and must not be. Framework.GetServerTime() hands
it over, so the plugin follows whatever Square Enix does with it -- a local UTC
conversion would be right today and quietly wrong the day that stops holding.
Umbra reads it the same way. The slot drops out on its own like every other one,
and it is empty while logged out, because then there is no server to read a clock
off.

The header gives up its clock in exchange. With both times in the status bar it
would have been the third copy of the same number on one screen, and the header's
job is to answer where you are, not what time it is.

Its title also moves down to the meta size. Tracked caps at body size read like a
headline, and the header is meant to answer a question rather than announce one.
That only works because the meta face now carries the full glyph range: it was
built with an ASCII-sized one on the assumption it would only ever draw clocks
and world names, and a single umlaut in a tab name would have broken it. All
three delegate handles rasterise the full set now -- the honest cost of the
change, and the reason the size distinction is worth having at all.

Two things fell out along the way. The detail no longer needs a flag saying "draw
me in the body face", because there is no glyph the meta face cannot reach. And a
culture-pinning test lost its subject when the clock left, so it asserted nothing
and is gone rather than repaired.
2026-08-19 17:29:20 +02:00

44 lines
1.5 KiB
C#

using System.Globalization;
namespace HellionChat.Ui.Components;
// TEST-MIRROR: Ui/ClockPairTests.cs
//
// Local time and server time side by side, in the notation the game itself uses:
// LT and ST. Anyone coordinating across regions reads both off one line instead
// of doing the arithmetic in their head.
//
// Server time is not computed here and must not be. The game hands it over
// through Framework.GetServerTime(), and taking it from there means the plugin
// follows whatever Square Enix does with it. A local UTC conversion would be
// right today and silently wrong the day that stops holding.
//
// Culture is pinned for the same reason the message timestamps pin it: a German
// machine renders PM as nachm. under its own culture, and the two clocks sit
// next to each other.
internal static class ClockPair
{
internal const string Separator = " · ";
internal static string Format(DateTimeOffset local, TimeSpan server, bool use24Hour)
{
var localText = FormatOne(local.Hour, local.Minute, use24Hour);
var serverText = FormatOne(server.Hours, server.Minutes, use24Hour);
return $"LT {localText}{Separator}ST {serverText}";
}
private static string FormatOne(int hour, int minute, bool use24Hour)
{
if (use24Hour)
return $"{hour:00}:{minute:00}";
var suffix = hour < 12 ? "AM" : "PM";
var shown = hour % 12;
if (shown == 0)
shown = 12;
return string.Create(CultureInfo.InvariantCulture, $"{shown}:{minute:00} {suffix}");
}
}