Would like to use DateTime
in Ecto schemas and migrations, instead of the default NaiveDateTime
, and also timestamptz
in PostgreSQL, instead of the default timestamp
(aka. timestamp without time zone
).
Introduction to PostgreSQL timestamp The timestamp datatype allows you to store both date and time. However, it does not have any time zone data. It means that when you change the timezone of your database server, the timestamp value stored in the database will not change automatically.
Timestamp vs Timestamptz – What's the Difference? The big difference between these two data types is that timestamptz includes a timezone offset while timestamp does not. So it is important to decide for the timestamp you are storing whether the timezone is important to keep or not.
The difference arises from what the system can reasonably know about the value: With a time zone as part of the value, the value can be rendered as a local time in the client. Without a time zone as part of the value, the obvious default time zone is UTC, so it is rendered for that time zone.
For timestamp with time zone , the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT ). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone.
timestamptz
and :utc_datetime
Note: Ecto.Migration.timestamps/1 (source) global configuration can always be overridden locally.
Using the :migration_timestamps
configuration option from the Ecto.Migration
docs:
# in ./config/dev.exs (for example)
config :app, App.Repo, migration_timestamps: [type: :timestamptz]
and one can use Ecto.Migration.timestamps/1
in migrations as usual:
# ./priv/repo/migrations/20190718195828_create_users.exs
create table(:users) do
add :username, :string, null: false
timestamps()
end
The Postgres
adapter will automatically switch
the Elixir representation to DateTime
from
NaiveDateTime
.
Use Ecto.Migration.timestamps/1's :type
option:
defmodule App.Repo.Migrations.CreateUsers do
use Ecto.Migration
def change do
create table(:users) do
add :username, :string, null: false
timestamps(type: :timestamptz)
end
end
end
:utc_datetime
The Ecto schemas also need to be modified to
use :utc_datetime
, otherwise they will expect
NaiveDateTime
by default. Slightly modifying the
example in the
Ecto.Schema
docs:
# Define a module to be used as base defmodule MyApp.Schema do defmacro __using__(_) do quote do use Ecto.Schema # In case one uses UUIDs @primary_key {:id, :binary_id, autogenerate: true} @foreign_key_type :binary_id # ------------------------------------ @timestamps_opts [type: :utc_datetime] end end end # Now use MyApp.Schema to define new schemas defmodule MyApp.Comment do use MyApp.Schema schema "comments" do belongs_to :post, MyApp.Post timestamps() end end
defmodule ANV.Accounts.User do
use Ecto.Schema
# -- EITHER --------------------------
@timestamps_opts [type: :utc_datetime]
schema "users" do
field :username, :string
# -- OR -----------------------
timestamps(type: :utc_datetime)
end
lau/tzdata
DateTime
in Elixir "only handles "Etc/UTC"
datetimes" but it can be configured with a custom
time zone database, which is what the tzdata
library is
Time zones in PostgreSQL, Elixir and Phoenix and How to set timestamps to UTC DateTimes in Ecto
A very handy table from the first article:
+----------------------+------------------+------------------------+------------------------------+-----------------------------------+
| Ecto 3 type | Elixir type | Supports microseconds? | Supports DateTime functions? | Supports NaiveDateTime functions? |
+----------------------+------------------+------------------------+------------------------------+-----------------------------------+
| :utc_datetime_usec | DateTime | YES | YES | YES |
| :utc_datetime | DateTime | NO | YES | YES |
| :naive_datetime_usec | NaiveDateTime | YES | NO | YES |
| :naive_datetime | NaiveDateTime | NO | NO | YES |
+----------------------+------------------+------------------------+------------------------------+-----------------------------------+
Discussions and advice specific to PostgreSQL
Don't use timestamp (without time zone) (PostgreSQL Wiki)
Difference between timestamps with/without time zone in PostgreSQL
Ignoring time zones altogether in Rails and PostgreSQL (accepted answer)
8.5. Date/Time Types (PostgreSQL manual)
9.9.3. AT TIME ZONE (PostgreSQL manual)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With