###前提・実現したいこと
Ecto + Timex を使って、PostgreSQL の timestamp with timezone を扱いたいんですが、Model で持っている日時とデータベースに保存される時間がずれてしまうので、理由と対処法を知りたいです。
もっと別の方法があるよ、とかでもいいです。
参考
- https://github.com/bitwalker/timex_ecto
- https://hexdocs.pm/timex_ecto/Timex.Ecto.DateTimeWithTimezone.html
↑を読むと、カスタム複合タイプ datetimetz つくって対処するといいよって書いてある。
###発生している問題・エラーメッセージ
インタラクションに従って、データベースに datetimetz 型をつくって、Elixir からはTimex.Ecto.DateTimeWithTimezone 型の変数を入れられるようにしました。
sql
1CREATE TYPE datetimetz AS ( 2 dt timestamptz, 3 tz varchar 4);
Timex.Ecto.DateTimeWithTimezone な変数の中身をダンプすると以下のようになっています。
elixir
1IO.inspect model.inserted_at 2# {{{2017, 6, 2}, {11, 41, 57, 93698}}, "Asia/Tokyo"}
データベースには以下のように登録されています。
sql
1("2017-06-02 20:41:57.093698+09",Asia/Tokyo)
9時間ずれている。。実際の時刻は上の方です(今日の午前11時に実行しました)。
###該当のソースコード
migrationファイル
elixir
1 def change do 2 create table(:messages) do 3 add :message, :text 4 add :inserted_at, :datetimetz 5 end 6 end
モデルクラス
elixir
1schema "messages" do 2 field :message, :string 3 field :inserted_at, Timex.Ecto.DateTimeWithTimezone 4end
インサート
elixir
1changeset = Message.changeset(%Message{}, %{message: message, inserted_at: Timex.now("Asia/Tokyo")}) 2Repo.insert(changeset)
###試したこと
すみません、何を試せばいいのかすら思いつかず。。
Ectoのコード読んだくらいです(でもよく分からなかった。。)
2017-06-04 13:00 追記
@mhashi さんのコメントにもあるように、インサートの際に UTC で入れないとダメなようです。
そもそも PostgreSQL の timestamp with timezone はタイムスタンプを UTC で持っており、それを、必要に応じて変換してから出力しているみたいなので、そこに JST の日時を入れてしまうと二重に +9 されてしまうようです。
たどり着いたコードとしては、
Ecto.Adapters.Postgres.Timestamp.encode/1
の中で
elixir
1:calendar.datetime_to_gregorian_seconds({{2017,6,4},{13,0,0}})
のようにして秒に変換しているのですが、当然ながらここではタイムゾーンは考慮されてないです。このタプルは、単純に Timex.Ecto.DateTimeWithTimezone の値 {{{2017,6,4},{13,0,0}}, "Asia/Tokyo"}
のタイムスタンプ部分を取ってきているにすぎません。
2017-06-04 13:00 追記ここまで
###補足情報(言語/FW/ツール等のバージョンなど)
Elixir 1.4
ecto 2.1
timex 3.1
timex_ecto 3.1
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/06/02 05:44
2017/06/02 06:59
退会済みユーザー
2017/06/02 08:01
2017/06/02 10:18
退会済みユーザー
2017/06/02 10:19