bitwalker / timex_ecto

An adapter for using Timex DateTimes with Ecto
MIT License
162 stars 68 forks source link

(ArgumentError) could not encode datetime / Timex.Ecto.DateTimeWithTimezone stripping timezone #49

Closed danielnc closed 8 years ago

danielnc commented 8 years ago

getting the following error

     ** (ArgumentError) could not encode datetime: {2016, 10, 11}

     This error happens when you are by-passing Ecto's Query API by
     using either Ecto.Adapters.SQL.query/4 or Ecto fragments. This
     makes Ecto unable to properly cast the type. For example:

         now = Ecto.DateTime.utc |> Calecto.DateTimeUTC.cast
         from u in User, where: fragment("(?).wall_time > ?", u.start_datetime, ^now)

     In the query above, Ecto is unable to know the variable "now" is
     being compared to a datetime due to the fragment and is therefore
     unable to cast it. You can fix this by explicitly telling Ecto
     which type must be used:

         fragment("(?).wall_time > ?",
           u.start_datetime,
           type(^now, :datetime))

     Or by implementing the Ecto.DataType protocol for the given value.

with the following model

defmodule PhoenixMessagingGateway.SmsMessage do
  use PhoenixMessagingGateway.Web, :model
  use Timex

  schema "sms_messages" do
    field :from_number, :string
    field :to_number, :string
    field :body, :string
    field :gateway_sid, :string
    field :gateway_status, :string
    field :gateway_error_code, :string
    field :gateway_error_message, :string
    field :scheduled_to, Timex.Ecto.DateTimeWithTimezone
    field :enqueued_at, Timex.Ecto.DateTimeWithTimezone
    field :sent_at, Timex.Ecto.DateTimeWithTimezone
    field :failed_at, Timex.Ecto.DateTimeWithTimezone
    field :phone_gateway, :string, default: "twilio"

    timestamps()
  end

  @allowed_fields ~w(from_number to_number body scheduled_to)a
  @required_fields @allowed_fields
  def create_changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @allowed_fields)
    |> maybe_set_scheduled_to
    |> validate_required(@required_fields)
    |> update_change(:from_number, &format_phone_number/1)
    |> update_change(:to_number, &format_phone_number/1)
    |> validate_format(:from_number, ~r/\A\d{10}\z/)
    |> validate_format(:to_number, ~r/\A\d{10}\z/)
  end

  defp format_phone_number(phone) do
    if phone != nil do
      String.replace(phone, ~r/\D/, "")
    end
  end

  defp maybe_set_scheduled_to(struct) do
    if get_change(struct, :scheduled_to) do
      struct
    else
      put_change(struct, :scheduled_to, Timezone.convert(Timex.now, "UTC"))
    end
  end
end

and my scheduled_to is a datetimetz following examples provided

Here are my versions

Dependency           Current  Latest  Requirement
cowboy               1.0.4    1.0.4   ~> 1.0
faker                0.7.0    0.7.0   ~> 0.5
gettext              0.11.0   0.11.0  ~> 0.11
ja_serializer        0.11.0   0.11.0  ~> 0.11.0
phoenix              1.2.1    1.2.1   ~> 1.2.1
phoenix_ecto         3.0.1    3.0.1   ~> 3.0
phoenix_html         2.7.0    2.7.0   ~> 2.6
phoenix_live_reload  1.0.5    1.0.5   ~> 1.0
phoenix_pubsub       1.0.1    1.0.1   ~> 1.0
postgrex             0.12.1   0.12.1  >= 0.0.0
timex                3.0.8    3.0.8   ~> 3.0
timex_ecto           3.0.4    3.0.4   ~> 3.0

Looking at the source code when I manually call Timex.Ecto.DateTimeWithTimezone on a datetime it strips my TZ info and this is the generated query

INSERT INTO "sms_messages" ("body","from_number","gateway_sid","gateway_status","phone_gateway","scheduled_to","to_number","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) RETURNING "id" ["Blow, blow, thou winter wind! Thou art not so unkind as man's ingratitude.", "6102083514", "4471965905", "queued", "test", {{2016, 10, 11}, {12, 49, 39, 387814}}, "4452583471", {{2016, 10, 11}, {12, 49, 39, 388079}}, {{2016, 10, 11}, {12, 49, 39, 388087}}]

Is this a bug or am I doing something completely off?

bitwalker commented 8 years ago

Could you give this a shot with 3.0.5?

danielnc commented 8 years ago

Works thanks for the fix @bitwalker