Cast string from database as %Time{} in Ecto

So I have the following field in a database table that I connect to via Ecto:

checkin_time character varying(255)[] DEFAULT '{15:00,15:00,15:00,15:00,15:00,15:00,15:00}'::character varying[],

What I’m trying to do is have Ecto cast this as a list of %Time{} structs but it is not quite working:

field(:checkin_times, {:array, :time}, source: :checkin_time)

Results in:

** (ArgumentError) cannot load ["15:00", "15:00", "15:00", "15:00", "15:00", "15:00", "15:00"] as type {:array, :time} for field checkin_time in schema …

It does work when I define the ecto field as {:array, :string}. I was reading the source code and I also noticed that this works:

{:ok, [%Time{}]} = Ecto.Type.cast({:array, :time}, ["23:50"])

But this doesn’t:

{:ok, [%Time{}]} = Ecto.Type.load({:array, :time}, ["23:50"])

I guess the postgres DB type has to be Time as well. Is there an elegant way to work around this? I cannot easily change the database.

Right. Time expects to be stored as an actual Time in the database and not a string. For your case, you will have to create a custom type. Then you can set the time to be {:array, TimeString} and everything should work.

1 Like