mudasobwa

mudasobwa

Creator of Cure

Adding days with a TZ is confusing

This question is more about semantics. Adding a :day to the DateTime instance changes the time value, which might be slightly confusing.

iex(1)> DateTime.new!(~D[2024-04-06], ~T[23:59:00], "Australia/Sydney")
...(1)>   |> IO.inspect()
...(1)>   |> DateTime.add(1, :day)
#DateTime<2024-04-06 23:59:00+11:00 AEDT Australia/Sydney>
#DateTime<2024-04-07 22:59:00+10:00 AEST Australia/Sydney>

Yes, adding the exact number of seconds (86_400) multiplied by the number of days results in this, but DateTime(dt, 5, :day) usually means the developer wants to get the very same hh:mm:ss time back.

Consider a ToDoApp (huh) example. If I am after producing a Stream of recurring events, I am surely to expect it won’t change the Time part alongside with a DST change.

I discovered this when people complained about Tempus.Slots.Stream.recurrent/3 is broken in an aforementioned way. I fixed it by reassuring Time part to stay intact in the produced stream elements, but it looks like a hack and I am positive, DateTime.add(…, …, :day) should not corrupt the Time anyway.

Thought?

Most Liked

LostKobrakai

LostKobrakai

This function relies on a contiguous representation of time, ignoring the wall time and timezone changes. For example, if you add one day when there are summer time/daylight saving time changes, it will also change the time forward or backward by one hour, so the elapsed time is precisely 24 hours.

This is called out in the docs as the intended behaviour.

If you want a continuous stream of datetimes at the same hour you can use a date and Date.add and turn those dates into datetimes with a time. Though you might run into invalid/duplicate datetimes this way if a date+time combination is in a DST change switch.

zachallaun

zachallaun

The docs for the new DateTime.shift/3 landing in 1.17 addresses this specifically and offers a suggestion using NaiveDateTime. It looks like this works:

iex(1)> Mix.install([:tz])
:ok
iex(2)> Calendar.put_time_zone_database(Tz.TimeZoneDatabase)
:ok
iex(3)> dt = DateTime.new!(~D[2024-04-06], ~T[23:59:00], "Australia/Sydney")
#DateTime<2024-04-06 23:59:00+11:00 AEDT Australia/Sydney>
iex(4)> dt |> DateTime.to_naive() |> NaiveDateTime.add(1, :day) |> DateTime.from_naive(dt.time_zone)
{:ok, #DateTime<2024-04-07 23:59:00+10:00 AEST Australia/Sydney>}

Edit to note that the above isn’t using anything in 1.17 and was copied from a 1.16 REPL.

LostKobrakai

LostKobrakai

DateTime.shift could make that decision, sure. But DateTime.add adds a certain (and fixed per amount/unit) amount of seconds to the supplied DateTime. That’s a different task. The issue is that it allows for :day with a constant of 86400 seconds when days are not always that long. That’s also the reason why :week, :month, :year weren’t added to DateTime.add, but handled into the new DateTime.shift.

Last Post!

LostKobrakai

LostKobrakai

Not modeling leapseconds doesn‘t leave you in a state where you miss a (naive) datetime or run into it twice though - which is what happens if you don‘t handle the dst change complexities.

Where Next?

Popular in Discussions Top

scouten
I’m looking for a host for the server part of a small (personal) side project that I’m working on. It’s currently written in Node.js and ...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31771 143
New
und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
New
AstonJ
If so I (and hopefully others!) might have some tips for you :slight_smile: But first, please say which area you’re finding most challen...
New
mikl
I wanted to capitalize a string, and tried using String.capitalize(). That generally works well, until you try to capitalize a word like...
New
owaisqayum
I have a sample string sentence = "Hello, world ... 123 *** ^%&amp;*())^% %%:&gt;" From this string, I want to only keep the integers, ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 44778 311
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement