Phoenix/Ecto - converting ISO string into utc_date

2019-07-26 07:45发布

问题:

In my Phoenix app, I'm trying to insert an event record into the database that has fields for start_time and end_time - the datetime data will already be converted to ISO string format on the client and passed to the Phoenix API as JSON data, but this is causing me some trouble when I try to make an insert - the model is expecting those values to be :utc_datetime so I need to convert them - I read through the documentation, but I'm still not sure...

First off, here's the schema for the model:

@primary_key {:id, :string, []}
@derive {Phoenix.Param, key: :id}
schema "calendar_event" do
  field :start_time, :utc_datetime
  field :end_time, :utc_datetime
  field :description, :string

  timestamps()
end

JSON data from the client would look like:

{
    "start_time": "2017-09-28T18:31:32.223Z",
    "end_time": "2017-09-28T19:31:32.223Z",
    "description": "Test insert"
}

And if I were to (incorrectly) try to insert this data as-is, the statement would look like:

MyApp.Repo.insert(%MyApp.CalendarEvent{id: "calendar_event:test1", start_time: 
"2017-09-28T18:31:32.223Z", end_time: "2017-09-28T19:31:32.223Z", 
description: "Test insert"})

As expected, this throws an error that my datetime data does not match type :utc_datetime. Ok, that's cool, but my question is, with the data already in ISO string, how can I convert it to that Elixir/Ecto recognizes it as valid :utc_datetime?

回答1:

You want a DateTime struct for your :utc_datetime field, as you can see in the docs here: https://hexdocs.pm/ecto/Ecto.Schema.html#module-primitive-types

You can get a DateTime from an iso string like the one you had above like this:

iex> {:ok, dt, 0} = DateTime.from_iso8601("2017-09-28T18:31:32.223Z")
iex> dt
#DateTime<2017-09-28 18:31:32.223Z>

(The zero in the tuple is the UTC offset)

Note: Support for Elixir Calendar types was introduced in Ecto 2.1. DateTime.from_iso8601/1 was introduced in Elixir 1.4.