53 lines
1.6 KiB
Elixir
53 lines
1.6 KiB
Elixir
defmodule Rsh26pool.JST do
|
|
@moduledoc """
|
|
Helpers for converting between UTC (how timestamps are stored) and
|
|
Japan Standard Time (JST, UTC+9) which is what the UI shows and accepts.
|
|
|
|
A full time zone database is not configured for this demo, and JST has no
|
|
daylight saving time, so a fixed +9h offset is sufficient and dependency free.
|
|
"""
|
|
|
|
@offset_seconds 9 * 3600
|
|
|
|
@doc """
|
|
Parses a `datetime-local` form value (e.g. `"2026-07-04T15:30"`), interpreting
|
|
it as wall-clock JST, and returns the corresponding UTC `DateTime`.
|
|
"""
|
|
@spec parse_local(String.t()) :: {:ok, DateTime.t()} | :error
|
|
def parse_local(value) when is_binary(value) do
|
|
with {:ok, naive} <- NaiveDateTime.from_iso8601(ensure_seconds(value)) do
|
|
utc =
|
|
naive
|
|
|> DateTime.from_naive!("Etc/UTC")
|
|
|> DateTime.add(-@offset_seconds, :second)
|
|
|> DateTime.truncate(:second)
|
|
|
|
{:ok, utc}
|
|
else
|
|
_ -> :error
|
|
end
|
|
end
|
|
|
|
def parse_local(_), do: :error
|
|
|
|
@doc "Converts a stored UTC `DateTime` to a JST `DateTime` for display."
|
|
@spec to_local(DateTime.t()) :: DateTime.t()
|
|
def to_local(%DateTime{} = dt), do: DateTime.add(dt, @offset_seconds, :second)
|
|
|
|
@doc "Formats a stored UTC `DateTime` as a human friendly JST string."
|
|
@spec format(DateTime.t() | nil) :: String.t()
|
|
def format(nil), do: ""
|
|
|
|
def format(%DateTime{} = dt) do
|
|
l = to_local(dt)
|
|
|
|
"~4..0B/~2..0B/~2..0B ~2..0B:~2..0B"
|
|
|> :io_lib.format([l.year, l.month, l.day, l.hour, l.minute])
|
|
|> to_string()
|
|
end
|
|
|
|
defp ensure_seconds(value) do
|
|
if Regex.match?(~r/T\d{2}:\d{2}$/, value), do: value <> ":00", else: value
|
|
end
|
|
end
|