博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Elixir Ecto: 解决UTC时间戳和本地时间8小时时差的问题
阅读量:6624 次
发布时间:2019-06-25

本文共 4633 字,大约阅读时间需要 15 分钟。

Ecto 默认使用的是UTC时间, 它要比中国区的本地时间晚 8 小时.

2016-07-21 更新: 模块已经添加到 , 添加 {:ecto_timestamps, "~> 1.0"} 依赖到mix.exs即可, 详细信息参考项目

注意, :autogenerate 需要 Ecto 2.0的支持. 所以要使用这个自定义选项, 需要升级到 Ecto 2.0

说明了这个问题.

经过查找资料, 我们在 中找到了 timestamps 宏的选项 :autogenerate, 它的格式为一个三元组, 分别是模块, 函数, 参数

{Module, :function, []}

Ecto 的 timestamps 的时间戳是自动生成的, 同时Ecto 也给我们提供了自定义的方法, 我们参考上面的Ecto源码实现本地时间的插入

首先编写一个新的Localtime模块, 把UTC时间修改为本地时间, 定义如下, 只是替换了两个函数, 分别是:

  • :erlang.localtime替换:erlang.universaltime

  • :calendar.now_to_local_time 替换 :calendar.now_to_datetime

defmodule Test.Localtime do  def autogenerate(precision \\ :sec)  def autogenerate(:sec) do    {date, {h, m, s}} = :erlang.localtime    erl_load({date, {h, m, s, 0}})  end  def autogenerate(:usec) do    timestamp = {_, _, usec} = :os.timestamp    {date, {h, m, s}} = :calendar.now_to_local_time(timestamp)    erl_load({date, {h, m, s, usec}})  end  def erl_load({
{year, month, day}, {hour, min, sec, usec}}) do %Ecto.DateTime{ year: year, month: month, day: day, hour: hour, min: min, sec: sec, usec: usec } endend

在模型的模块属性中声明 @timestamps_opts 时间戳选项:

@timestamps_opts [  autogenerate: {Test.Localtime, :autogenerate, [:sec]}]

然后我们用一个例子来证实

模型的公共模块

require Loggerdefmodule Test.Model do  defmacro __using__(_opts) do    quote do      import Ecto.Query      use Ecto.Schema      alias Ecto.Changeset      alias Test.Repo      # 这里为了演示时差的问题, 先注释掉      # @timestamps_opts [autogenerate: {Test.Localtime, :autogenerate, [:sec]}]    end  endend

创建一个角色模型

defmodule Test.Model.Role do  @moduledoc """  角色表  """  use Test.Model  schema "role" do    field :name, :string # 角色名称    timestamps  endend

创建移植脚本

➜  mix ecto.gen.migration create_role_table -r Test.Repo* creating priv/repo/migrations* creating priv/repo/migrations/20160713121457_create_role_table.exs

内容如下

defmodule Test.Repo.Migrations.CreateRoleTable do  use Ecto.Migration  def up do    create table(:role) do      add :name, :string # 角色名称      timestamps    end  end  def down do    drop table(:role)  endend

创建表

➜ ✗ mix ecto.migrateCompiling 14 files (.ex)20:47:24.510 [info]  == Running Test.Repo.Migrations.CreateRoleTable.up/0 forward20:47:24.511 [info]  create table role20:47:24.534 [info]  == Migrated in 0.0s

角色模型修改为如下, 增加了测试函数:

defmodule Test.Model.Role do  @moduledoc """  角色表  """  use Test.Model  schema "role" do    field :name, :string # 角色名称    timestamps  end  def insert(map) do    Map.merge(%__MODULE__{}, map) |> Repo.insert  end  def test_insert do    row = %{      name: "技术总监"    }    insert(row)  endend

启动IEx测试, 现在的时间是2016-07-13 21:02:49, 插入的时间为2016-07-13 13:02:49, 晚了8个小时

(输出手工格式化, 以便阅读)

iex> Test.Model.Role.test_insertQUERY OK db=6.9ms decode=1.0ms queue=0.9msINSERT INTO "role" ("name","inserted_at","updated_at") VALUES ($1,$2,$3)     RETURNING "id" ["技术总监", {
{2016, 7, 13}, {13, 2, 49, 0}}, {
{2016, 7, 13}, {13, 2, 49, 0}}]{:ok, %Test.Model.Role{ __meta__: #Ecto.Schema.Metadata<:loaded, "role">, id: 6, inserted_at: #Ecto.DateTime<2016-07-13 13:02:49>, name: "技术总监", updated_at: #Ecto.DateTime<2016-07-13 13:02:49>}}

数据库中插入的数据为

select * from role;+------+----------+---------------------+---------------------+|   id | name     | inserted_at         | updated_at          ||------+----------+---------------------+---------------------||    6 | 技术总监 | 2016-07-13 13:02:49 | 2016-07-13 13:02:49 |+------+----------+---------------------+---------------------+

取消上面 Test.Model 模块的属性声明的注释, 并重新编译, 进入IEx

require Loggerdefmodule Test.Model do  defmacro __using__(_opts) do    quote do      import Ecto.Query      use Ecto.Schema      alias Ecto.Changeset      alias Test.Repo      # 这里为了演示时差的问题, 先注释掉      @timestamps_opts [autogenerate: {Test.Localtime, :autogenerate, [:sec]}]    end  endend

再次执行

iex(18)> Test.Model.Role.test_insert    QUERY OK db=8.5ms decode=1.0ms queue=1.1msINSERT INTO "role" ("name","inserted_at","updated_at") VALUES ($1,$2,$3)     RETURNING "id" ["技术总监", {
{2016, 7, 13}, {21, 4, 58, 0}}, {
{2016, 7, 13}, {21, 4, 58, 0}}]{:ok, %Test.Model.Role{ __meta__: #Ecto.Schema.Metadata<:loaded, "role">, id: 7, inserted_at: #Ecto.DateTime<2016-07-13 21:04:58>, name: "技术总监", updated_at: #Ecto.DateTime<2016-07-13 21:04:58>}}

数据为

select * from role;+------+----------+---------------------+---------------------+|   id | name     | inserted_at         | updated_at          ||------+----------+---------------------+---------------------||    6 | 技术总监 | 2016-07-13 13:02:49 | 2016-07-13 13:02:49 ||    7 | 技术总监 | 2016-07-13 21:04:58 | 2016-07-13 21:04:58 |+------+----------+---------------------+---------------------+

转载地址:http://botpo.baihongyu.com/

你可能感兴趣的文章
多文档
查看>>
输入5个学生的信息(包括学号,姓名,英语成绩,计算机语言成绩和数据库成绩), 统计各学生的总分,然后将学生信息和统计结果存入test.txt文件中...
查看>>
BZOJ2337 [HNOI2011]XOR和路径
查看>>
C# 该行已经属于另一个表 ...
查看>>
android 避免线程的重复创建(HandlerThread、线程池)
查看>>
手游-放开那三国socket协议分析
查看>>
SQL Lazy Spool Eager Spool
查看>>
type的解释
查看>>
Windows Phone 8 开发环境搭建
查看>>
2017:IDC市场规模将持续增长 增速放缓
查看>>
从自动驾驶到学习机器学习:解读2017科技发展的15大趋势
查看>>
SinoBBD探索"一体化"大数据创新发展
查看>>
互联网金融带来新机遇 数据合规性不容忽视
查看>>
智能家庭本周锋闻:专注跨界100年
查看>>
在Linux中永久并安全删除文件和目录的方法
查看>>
全民直播时代 内容监管还得靠技术
查看>>
10款Web开发最佳的Python框架
查看>>
c++ 类的对象与指针
查看>>
【算法】数据结构
查看>>
Boolean operations between triangle meshes
查看>>