Search code examples
elixirecto

Validate ISO8601 start_time is before ISO8601 end_time in elixir/ecto/timex


I'm working on json request using phoenix where I have start_time and end_time in ISO8601 format and I want to validate that end_time is > start_time, so given:

 {
    "start_time": "2016-07-07T01:00:00+02:00",
    "end_time": "2016-07-07T01:30:00+01:00"
 }

validation error should be returned for both fields saying that "start_time": "must be less then end_time" and "end_time": "must be greater than start_time".

What is preferred way to accomplish that using ecto changesets (+ timex)?


Solution

  • You can write your custom vadlidate_time_range function and use it inside pipeline in changeset function. Those validators need to take changeset structure as first argument and return changeset structure.

    Inside this function you need to check both dates. If they changed, they will be in changeset.changes. If not, you will need to extract them from model. You can get them like this:

    start_time = changeset.changes |> Dict.get(:start_time, nil)
    start_time = start_time || (changeset.model |> Dict.get(:start_time))
    {:ok, start_time} = Timex.parse start_time, "{ISO:Extended}"
    

    The same goes with end time, so you might want to extract those three operations into a function.

    Then you need to compare with Timex.Comparable.compare(start_time, end_time).

    case comparison_result do
      1 ->
        changeset
      _ ->
        changeset
        |> add_error(:start_time, "must be less then end_time")
        |> add_error(:end_time, "must be greater than start_time")
    end