In Phoenix I have this model
schema "events" do
field :start_time, Ecto.DateTime
field :end_time, Ecto.DateTime
belongs_to :calendar, Weozo.Calendar
timestamps
end
@required_fields ~w(calendar_id start_time end_time)
@optional_fields ~w()
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
and I have a JSON API controller generated by the scaffold (piped through :api) where the create function looks like this
def create(conn, %{"event" => event_params}) do
changeset = Event.changeset(%Event{}, event_params)
case Repo.insert(changeset) do
{:ok, event} ->
conn
|> put_status(:created)
|> put_resp_header("location", event_path(conn, :show, event))
|> render("show.json", event: event)
{:error, changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(Weozo.ChangesetView, "error.json", changeset: changeset)
end
end
This is just the default boiler plate. Now, I want to create an Event with a Javascript client, using jQuery I do this:
$.post('/api/events',
{"event": {"calendar_id": 1, "start_time": Date.now(), "end_time": Date.now()}}
).always(function(r){console.log(r.responseText)})
and it returns this
{"errors":{"start_time":["is invalid"],"end_time":["is invalid"]}}
So by default, Javascript posts the date as an integer (Epoch format). I've tried a bunch of variations in curl as well like this:
Just a normal date
curl -X POST http://localhost:4000/api/events \
-H "Content-Type: application/json" \
-d '{"event": {"calendar_id": 1, "start_time": "2015-10-29", "end_time": "2015-10-29"}}'
RFC 1123 formatted date
curl -X POST http://localhost:4000/api/events \
-H "Content-Type: application/json"
-d '{"event":{"calendar_id":"1","start_time":"Thu, 29 Oct 2015 20:11:54 GMT","end_time":"Thu, 29 Oct 2015 20:11:54 GMT"}}'
ISO 8601 formatted date
curl -X POST http://localhost:4000/api/events \
-H "Content-Type: application/json"
-d '{"event":{"calendar_id":"1","start_time":"2015-10-29T20:12:30+0000","end_time":"2015-10-29T20:12:30+0000"}}'
They all receive the same "is invalid" error message.
So Phoenix doesn't accept Epoch, RFC 1123 or ISO 8601. How should I format my date for Phoenix to accept it?
The changeset will cast the datetime fields using Ecto.DateTime.cast/1 from the docs:
• a binary in the "YYYY-MM-DD HH:MM:DD" format (may be separated by T and/or followed by "Z", as in 2014-04-17T14:00:00Z)
• a binary in the "YYYY-MM-DD HH:MM:DD.USEC" format (may be separated by T and/or followed by "Z", as in 2014-04-17T14:00:00.030Z)
Times should be in the ISO8601 format:
2015-10-29T20:12:30Z
You can generate such a string in JavaScript with:
new Date().toISOString()
Reading the ISO 8601 standard a bit closer, it says
YYYY-MM-DDTHH:mm:ss.sssZ
Z is the time zone offset specified as “Z” (for UTC) or either “+” or “-” followed by a time expression HH:mm
So it seems that my ISO 8601 formatting above was incorrect, the following curl works.
curl -X POST http://localhost:4000/api/events \
-H "Content-Type: application/json" \
-d '{"event": {"calendar_id": 1, "start_time": "2015-10-29T00:00:00Z", "end_time": "2015-10-29T00:00:00Z"}}'
But this one, that I feel should still work, doesn't:
curl -X POST http://localhost:4000/api/events \
-H "Content-Type: application/json" \
-d '{"event": {"calendar_id": 1, "start_time": "2015-10-29T00:00:00+01:00", "end_time": "2015-10-29T00:00:00+01:00"}}'
Regardless, the way to successfully create an event with Javascript would be to use the toJSON()
function or toISOString()
on a Date
.
$.post('/api/events',
{"event": {"calendar_id": 1, "start_time": (new Date()).toJSON(), "end_time": (new Date()).toJSON()}}
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With