Encode date time with micro second precision to json iso 8601 with millisecond precision

Hello,

I have an existing postgres database (10) and want to output some bytes as json:

  • spec of output json for date time data type is iso 8601, utc, millisecond precision: "2019-04-03T09:10:24.123Z"

  • schema to encode as json has 2 date time fields (opening_date, closing_date).

I use phoenix 1.4.3, ecto 3.1.0.
I use :utc_datetime_usec data type, and values I pulled from database do indeed have micro second precision, so I output : "2019-04-03T09:10:24.123456Z", which is not supported downstream.


I considered following options:

a) drop to millisecond precision in view function

DateTime.truncate(v, :millisecond)

cons: require to map each field of type date time.

b) use custom ecto type, that drops precision at load time

in schema

field(:opening_date, UTCDateTimeMs)
defmodule UTCDateTimeMs do
  @behaviour Ecto.Type

  def type(), do: :utc_datetime_usec

  def cast(term) do
    Ecto.Type.cast(:utc_datetime_usec, term)
  end

  def load(term) do
    case Ecto.Type.load(:utc_datetime_usec, term) do
      {:ok, d} -> {:ok, DateTime.truncate(d, :millisecond)}
      :error -> :error
    end
  end

  def dump(term) do
    Ecto.Type.dump(:utc_datetime_usec, term)
  end
end

Then I do not have to map each field of this type but it drops precision too early…

c) configure json jason encoder to encode date time
Tried to redefine?

defimpl Jason.Encoder, for: DateTime do
  def encode(value, _opts) do
    [?\", value |> DateTime.truncate(:millisecond) |> DateTime.to_iso8601(), ?\"]
  end
end

and I have 2 warnings:

warning: redefining module Jason.Encoder.DateTime (current version loaded from _build/dev/lib/jason/ebin/Elixir.Jason.Encoder.DateTime.beam)
  lib/lift/hack_jason.ex:2

Generated lift app
warning: this clause cannot match because a previous clause at line 1 always matches
  deps/jason/lib/encoder.ex:1

But my test is failing.
(And I do not like this approach redefining a module, it was scratch to see).

I’m currently using a) and ask for help on what a working c) would look like or any other option?
Cheers.

Hi and welcome to the forum!

IMHO I would stick with option a if there only those fields and/or you do need the microsecond precision for some calculations early than rendering.
If you have or will start having more date fields with the same condition, and don’t need the microsecond precision then migrate to a custom ecto type. It’s not advised to override Jason protocols or any protocols. That’s why you have view functions. Hope those help you

1 Like