How do I specify time zone for datetime fields in action input?

I have a form input with “datetime-local” type, and it provides input for an action. Corresponding resource attribute has utc_datetime type. Is there a simple way to pass in the timezone info from the browser, so the date is automatically converted to user’s time zone (and back)?

It depends on your definition of simple and potentially some of the other details.

For instance, if you’ve got an action like this:

create :create do
  accept [:timestamp]
end

you could refactor it like this:

create :create do
  argument :timestamp, :utc_datetime_usec, allow_nil?: false
  argument :timezone, :string, allow_nil?: false

  change fn changeset, _ -> 
    timestamp = Ash.Changeset.get_attribute(changeset, :timestamp)
    timezone = Ash.Changeset.get_attribute(changeset, :timezone)
    converted_timestamp = convert_timestamp(timestamp, timezone)
    Ash.Changeset.force_change_attribute(changeset, :timestamp, converted_timestamp)
  end
end

I think I can get you part of the way. I dug this out of an old project:

In your HEEx code, convert an Ecto time value to the user’s local time via JS:

value="new Date('#{your_datetime}Z').toLocaleString()"

(EDIT: I typed that by hand, the formatting may be off by bit, but it gets the point across. I found I had to add the “Z” manually because Elixir doesn’t render the timezone by default, so adding the Z makes it a proper ISO timestamp that JS will recognize.)

I don’t have the code that would convert it back. But I think you would keep the actual data (in the form’s value field or whatever) as the UTC value, then render it in the browser with toLocaleString so the user gets the correct timezone.

1 Like

Yes, great to mention that, if at all possible, you should keep time zones as presentational only, and handle it in the view.

2 Likes

Thanks

1 Like

Yes, that is actually what I am aiming for. Just thought there is some non-obvious built-in way to achieve that

1 Like