oneshot
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
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
|
||||
Reference in New Issue
Block a user