Timezone handling in Ash

I'm using https://github.com/madeitGmbH/tz_datetime to store user entered local datetime as UTC datetime in the table, and convert it back to local time when reading. Does Ash have a built-in solution for making this type of timezone conversion easier?
GitHub
GitHub - madeitGmbH/tz_datetime: Opinonated handling of datetimes a...
Opinonated handling of datetimes and their original timezone with ecto - GitHub - madeitGmbH/tz_datetime: Opinonated handling of datetimes and their original timezone with ecto
4 Replies
ZachDaniel
ZachDaniel3y ago
I don’t think we have anything dedicated to that, but that library looks like a great implementation and that using Ash with it should go nicely. I think you could pair it nicely with 1. a calculation that depends on the three fields in question 2. A change that sets the fields in writes
Jason
JasonOP3y ago
Thank you! I will give it a try. Here is my naive attempt that failed with the error message at the bottom. The issue probably is that I'm treating Ash Changeset as if it's Ecto changeset. Can you give me some pointers as to how/if this can be tweaked to work?
change fn changeset, _ ->

if Ash.Changeset.get_argument(changeset, :signup_starts_at_input) do
changeset
|> TzDatetime.handle_datetime([
{:input_datetime, :signup_starts_at_input},
{:datetime, :signup_starts_at},
{:time_zone, :input_time_zone}
])
else
changeset
end
change fn changeset, _ ->

if Ash.Changeset.get_argument(changeset, :signup_starts_at_input) do
changeset
|> TzDatetime.handle_datetime([
{:input_datetime, :signup_starts_at_input},
{:datetime, :signup_starts_at},
{:time_zone, :input_time_zone}
])
else
changeset
end
key :changes not found in: #Ash.Changeset<action_type: :create, action: :create, attributes: %{sheet_status: 1, visibility: :public}, relationships: %{}, arguments: %{input_time_zone: "America/Los_Angeles", pub
key :changes not found in: #Ash.Changeset<action_type: :create, action: :create, attributes: %{sheet_status: 1, visibility: :public}, relationships: %{}, arguments: %{input_time_zone: "America/Los_Angeles", pub
lib/tz_datetime.ex
def handle_datetime(changeset, opts \\ []) do
fields = fields_from_opts(opts)
with false <- Keyword.has_key?(changeset.errors, fields.input_datetime),
false <- Keyword.has_key?(changeset.errors, fields.time_zone),
changed_fields = Map.keys(changeset.changes), <<<<<<<< This is where the error occurs
true <- fields.input_datetime in changed_fields || fields.time_zone in changed_fields do
do_handle_datetime(changeset, fields, opts)
else
_ -> changeset
end
lib/tz_datetime.ex
def handle_datetime(changeset, opts \\ []) do
fields = fields_from_opts(opts)
with false <- Keyword.has_key?(changeset.errors, fields.input_datetime),
false <- Keyword.has_key?(changeset.errors, fields.time_zone),
changed_fields = Map.keys(changeset.changes), <<<<<<<< This is where the error occurs
true <- fields.input_datetime in changed_fields || fields.time_zone in changed_fields do
do_handle_datetime(changeset, fields, opts)
else
_ -> changeset
end
ZachDaniel
ZachDaniel3y ago
Ash changesets are structured very differently from ecto changesets For example, changeset.errors is not a keyword list of field to errors, and .changes is not a key I don't know if we have a great way right off the bat for you to look for errors on a given field. I could write you a helper that would do it likely, for now but to start off I'd suggest something as simple as this:
if changeset.valid? and (Ash.Changeset.changing_attribute?(changeset, fields.input_datetime) || fields.time_zone) do
do_handle_datetime(changeset, fields, opts)
else
changeset
end
if changeset.valid? and (Ash.Changeset.changing_attribute?(changeset, fields.input_datetime) || fields.time_zone) do
do_handle_datetime(changeset, fields, opts)
else
changeset
end
Jason
JasonOP3y ago
Thank you!!

Did you find this page helpful?