将 naive_datetime 转换为 utc_datetime_usec

Ala*_*lan 4 elixir

我有一个具有以下架构的模型:

schema "my_things" do
    (...)
    field :shifted_inserted_at, :utc_datetime_usec
    timestamps()
  end
Run Code Online (Sandbox Code Playgroud)

timestamps()类型默认为:naive_datetime.

我需要改变我的inserted_at值并将其插入到shifted_inserted_at.

如何将 NaiveDatetime 转换为正确的格式?我尝试过这样的事情:

  shifted_inserted_at =
    my_thing.inserted_at
    |> DateTime.from_naive!("Etc/UTC")
    |> Timex.shift(days: 10)

  my_thing
  |> Ecto.Changeset.change(shifted_inserted_at: shifted_inserted_at)
  |> Repo.update()
Run Code Online (Sandbox Code Playgroud)

但我得到:

** (ArgumentError) :utc_datetime_usec expects microsecond precision, got: #DateTime<2019-05-30 14:40:08Z>
Run Code Online (Sandbox Code Playgroud)

Ale*_*kin 5

DateTimetype 有一个名为 的字段microsecond。它\xe2\x80\x99是一个表示值精度的元组。

\n\n\n\n
iex|1 \xe2\x96\xb6 DateTime.from_naive!(\n...|1 \xe2\x96\xb6   ~N[2016-05-24 13:26:08], "Etc/UTC").microsecond       \n#\xe2\x87\x92\xc2\xa0{0, 0}\niex|2 \xe2\x96\xb6 DateTime.from_naive!(\n...|2 \xe2\x96\xb6   ~N[2016-05-24 13:26:08.123456], "Etc/UTC").microsecond\n#\xe2\x87\x92\xc2\xa0{123456, 6}\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如人们所看到的,除非实际值确实有微秒,否则精度为零。

\n\n

假设数据库中返回的值my_thing.inserted_at 具有微秒精度,可以简单地:

\n\n
~N[2016-05-24 13:26:08.123456]\n|> DateTime.from_naive!("Etc/UTC")\n|> DateTime.add(10 * 24 * 60 * 60) # 10 \xc3\x97 seconds in a day\n#\xe2\x87\x92\xc2\xa0#DateTime<2016-06-03 13:26:08.123456Z>\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果该值没有微秒精度,

\n\n
iex|3 \xe2\x96\xb6 DateTime.from_naive!(~N[2016-05-24 13:26:08], "Etc/UTC")\n#        PRECISION \xe2\x87\x92 ZERO!    \xe2\x87\x93\xe2\x87\x93\xe2\x87\x93 \n#\xe2\x87\x92\xc2\xa0#DateTime<2016-05-24 13:26:08Z>\n
Run Code Online (Sandbox Code Playgroud)\n\n

人们可能总是手动设置它:

\n\n
with dt <- DateTime.from_naive!(~N[2016-05-24 13:26:08], "Etc/UTC"),\n  do: %DateTime{dt | microsecond: {elem(dt.microsecond, 0), 6}}\n#\xe2\x87\x92\xc2\xa0#DateTime<2016-05-24 13:26:08.000000Z>\n
Run Code Online (Sandbox Code Playgroud)\n\n

后者现在可能已插入数据库中。

\n


Mic*_*ich 5

我刚刚也看到了这篇文章,并找到了另一个对我有帮助的解决方案,所以我想我会分享。

如果您使用 Ecto,则可以使用Ecto.Type.cast/2如下所示:

with {:ok, naive_datetime} <- NaiveDateTime.utc_now(),
     {:ok, datetime} <- DateTime.from_naive(naive_datetime, "Etc/UTC"),
     {:ok, utc_datetime_usec) <- Ecto.Type.cast(:utc_datetime_usec, datetime),
     do: utc_datetime_usec
Run Code Online (Sandbox Code Playgroud)

这是一个有点人为的示例,但您可以根据需要替换任何数据。它只是为了说明如何使用 Ecto 投射数据。