What is the best way to get a specific time, tomorrow?
I have a list of times a job may be enqueued for: [~T[07:00:00.000], ~T[11:00:00.000], ~T[14:00:00.000]]
. If the time has past (ie. It’s 15:00:00), we want to enqueue the job to run tomorrow at 7:00:00. (To further complicate things this is in mountain time).
In order to do this, this is what I’ve come up with:
now = "America/Denver" |> Timex.now()
times = [~T[07:00:00.000], ~T[11:00:00.000], ~T[14:00:00.000]]
# find the closest time in the future/ or default to the first time in the day
[first | _] = times
run_at = Enum.find(times, fn x -> Time.compare(x, now) == :gt end) || first
if Time.diff(perform_time, now, :second) > 0 do
# ... this is the easy part
else
{run_at_sec, _} = Time.to_seconds_after_midnight(run_at)
#this is the part that feels overly complex but I don't know how to simplify it
tomorrow =
Timex.now()
|> Timex.shift(days: 1)
|> Timex.beginning_of_day()
|> DateTime.to_unix()
|> Kernel.+(run_at_sec)
|> DateTime.from_unix()
|> elem(1)
|> DateTime.to_naive()
|> Timex.to_datetime("America/Denver")
DateTime.diff(tomorrow, now, :seconds)
end
That pipeline feels insane but from my trial and error of this it’s the only thing I could find that works.
- Start with the beginning of the day, tomorrow.
- Convert to unix so we can add seconds
- Add seconds from the beginning of the day to the run time
- Convert back to datetime
- Make naive so we can apply a timezone before running the comparison
Is there a simple way/function that does this I’m missing?