Why does Phoenix use naive datetime for timestamps by default?

I found various topics discussing the differences and similarities between :naive_datetime and :utc_datetime, namely:

In addition, I looked through Ecto.Schema — Ecto v3.11.1, where it says:

All of those types [naive_datetime, naive_datetime_usec, utc_datetime, utc_datetime_usec] 
are represented by the same timestamp/datetime in the underlying data storage, 
the difference are in their precision and how the data is loaded into Elixir.

I’m guessing the difference in precision is related to the _usec datetime types.

But I’m still wondering - why does Phoenix use :naive_datetime by default for timestamps? From all these discussions I either get the impression that it does not matter or that it’s slightly better to use :utc_datetime. However, in this topic I’m not trying to start a conversation comparing the two like as much as understand the default choice for Phoenix.

Edit: Added link to the Ecto documentation, too.

3 Likes

You already linked to this

The reason why Ecto’s timestamps() are naive by default is backwards compatibility.

In what way doesn’t that address your question?

It is my impression that the core team by convention treats time data without a timezone as UTC.

Confusion typically arises with people coming from other backgrounds who may have been working with a different convention - assuming that timezone free data is recorded with reference to local server time or local client time - which may be immediately convenient in the local context but creates problems in a long term historical or global context.

2 Likes

Thank you for the reply! I did read the comment you quoted at least a few times but it seems I did not pay enough attention to this sentence.

In light of this I would then ask - what is different with :utc_datetime for backwards compatibility if both naive and utc datetime are ultimately the same in the database? Is it that it was always :naive_datetime and if it’s changed to :utc_datetime people would have to change the module they use in every place they load datetimes? If that’s the case, what was the reason to use :naive_datetime in the first place? If I’m not mistaken, both DateTime, which is used for :utc_datetime, and NaiveDateTime were added to Elixir in version 1.3.

In my view the difference is semantics.

  • :utc_datetime is very clear that UTC is it’s frame of reference
  • :naive_datetime retains ambiguity as to what the frame of reference is. It’s up to the application context to imply and/or supply the frame of reference.
    • In the absence of any other evidence UTC is the only sensible choice.
    • In the application context of being used as a Phoenix timestamp it is known to be UTC.

So just because it’s :naive_datetime doesn’t automatically imply it’s not UTC.


4 Likes

Keep in mind that tools for timezone manipulation only landed in core at version 1.8. Before that third party tools were needed to do any timezone calculations. In a library you don’t want to use defaults, which more or less require users into needing to use other libraries. Even in 1.8 the actual tz database is still required to be supplied by the developer or a third party library.

Also while those structs were introduced in 1.3 ecto came with its own set of datetime structs before that, which ecto probably tried to be as backwards compatible to as possible.

2 Likes

Thank you both for the replies once more, and, I must say, for your contributions to other topics too.

I noticed this comment by Michał Muskała, which also seems helpful for my question - Deprecation warning says to use :naive_datetime but I'd like to use :utc_datetime

Just to clarify. The warning says to use :naive_datetime since that’s the type 
with exactly the same behaviour as the old Ecto.DateTime. 
The :utc_datetime has slightly different semantics.
3 Likes