The scheduled_at field of the post editor is a datetime-local input:
a wall clock with no zone. It is read and written in the EDITOR's timezone
— their profile value, else the site's time_zone setting, else UTC
(core's PhoenixKit.Utils.Date.get_user_timezone/1) — and stored as a UTC
instant.
Both directions go through core's per-instant helpers, so a named zone
(Europe/Warsaw) follows daylight saving on the date typed, and a legacy
fixed offset ("2") still works. This used to be an Integer.parse/1 of
the profile value that read an IANA id as 0 and ignored the site setting:
a post scheduled for 09:00 by a Tallinn editor went out at 09:00 UTC.
Summary
Functions
The editor's timezone value (an IANA id or a legacy offset): their own
when set, else the site's — core's get_user_timezone/1 rule, with a
blank value and a user map without the column both counting as "not set"
(core's newer releases read a blank the same way).
The input's value, read as the editor's wall clock, as a UTC instant.
{:ok, datetime}, or :error for anything unparseable.
A stored UTC instant as the input's value in the editor's zone.
Functions
The editor's timezone value (an IANA id or a legacy offset): their own
when set, else the site's — core's get_user_timezone/1 rule, with a
blank value and a user map without the column both counting as "not set"
(core's newer releases read a blank the same way).
@spec from_input(String.t() | nil, map() | nil) :: {:ok, DateTime.t()} | :error
The input's value, read as the editor's wall clock, as a UTC instant.
{:ok, datetime}, or :error for anything unparseable.
@spec to_input(DateTime.t() | NaiveDateTime.t() | nil, map() | nil) :: String.t() | nil
A stored UTC instant as the input's value in the editor's zone.