如何让 Ecto 为“timestamps”宏解释/写入本地时间而不是 UTC

发布于 2025-01-21 03:41:53 字数 578 浏览 0 评论 0原文

这是关于集成遗留应用程序中的数据库。 旧版应用程序正在读取和写入时间戳(即主机本地时间的 created_atupdated_at)。

虽然我完全意识到应该高度避免这种行为,但这种行为是无法改变的。

因此,使用相同数据库的 Elixir 应用程序也必须配置为使用本地时间。

Ecto 提供时间戳< /code> macro但似乎我无法使其与本地时间戳一起使用。 虽然可以提供类型(即 :naive_datetime:utc_datetime),但这两种类型似乎都使用 utc_now() 函数。

此外,读取这些字段可能会造成困难,因为日期字段在数据库中被定义为没有时区的时间戳。 因此,数据库字段也应解释为本地时间而不是 UTC。

This is about integrating a database from a legacy app.
The legacy app is reading and writing timestamps (i.e. created_at, updated_at in local time of the host).

And while I'm fully aware that this should be highly avoided this behaviour cannot be changed.

Therefore the Elixir application that uses the same database must be configured to use local time as well.

Ecto provides the timestamps macro but it seems that I cannot make it work with local timestamps.
While it's possible to provide a type (i.e. :naive_datetime or :utc_datetime) both types seem to use the utc_now() function.

Also reading the fields might cause difficulties, since the date fields are defined as timestamp without time zone in the database.
Hence the database fields also should be interpreted as local time and not as UTC.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

后知后觉 2025-01-28 03:41:53

PER @AlekSeimatiushkin,您应该能够使用:autogenerate为此,例如:

defmodule MyThing do

  use Ecto.Schema

  schema "things" do
    field(:something, :string, null: false)
    # ...
    timestamps(autogenerate: {MyThing, :local_time, []})
  end

  def local_time do
    DateTime.now!("Europe/Vienna") |> DateTime.to_naive()
  end

  # ...
end

如果依赖宏对您的用例过于限制,则可以手动将值写入字段(有些语言称这些突变,虚拟字段或计算字段)。类似:


defmodule MyThing do

  use Ecto.Schema

  import Ecto.Changeset

  schema "things" do
    field(:something, :string, null: false)
    field(:my_timestamp_col, :map) # <-- or integer, or ???
    # ...
  end

  def changeset(thing, attrs) do
    thing
    |> cast(
         attrs,
         [
           :something,
           # ...
         ]
       )
    # validate, constraints, etc.
    |> calc_local_time()
  end



  defp calc_local_time(changeset) do
    case changeset do
      %Ecto.Changeset{
        valid?: true,
        changes: thing
      } ->
        put_change(thing, :my_timestamp_col, local_time())
      _ ->
        changeset
    end
  end

  def local_time do
    # add custom date/time calcs here
    DateTime.now!("Europe/Vienna") |> DateTime.to_naive()
  end
end

希望您能找到利用上述模式的解决方案。

Per @AlekseiMatiushkin, you should be able to use the :autogenerate for this, something like:

defmodule MyThing do

  use Ecto.Schema

  schema "things" do
    field(:something, :string, null: false)
    # ...
    timestamps(autogenerate: {MyThing, :local_time, []})
  end

  def local_time do
    DateTime.now!("Europe/Vienna") |> DateTime.to_naive()
  end

  # ...
end

If relying on the macro is too constrained for your use-case, you can manually write values to the fields (some languages call these mutations, virtual fields, or calculated fields). Something like:


defmodule MyThing do

  use Ecto.Schema

  import Ecto.Changeset

  schema "things" do
    field(:something, :string, null: false)
    field(:my_timestamp_col, :map) # <-- or integer, or ???
    # ...
  end

  def changeset(thing, attrs) do
    thing
    |> cast(
         attrs,
         [
           :something,
           # ...
         ]
       )
    # validate, constraints, etc.
    |> calc_local_time()
  end



  defp calc_local_time(changeset) do
    case changeset do
      %Ecto.Changeset{
        valid?: true,
        changes: thing
      } ->
        put_change(thing, :my_timestamp_col, local_time())
      _ ->
        changeset
    end
  end

  def local_time do
    # add custom date/time calcs here
    DateTime.now!("Europe/Vienna") |> DateTime.to_naive()
  end
end

Hopefully you can find a solution leveraging the above patterns.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文