defmodule WarframeWorldstateDataElixirTools.DateTimeTools do
@seconds_in_day 86_400
@days_in_week 7
@doc """
Returns a tuple with the start and end of the day from an input timestamp.
All timestamps are assumed to be UTC.
## Examples
iex> dt = ~U[2024-01-15 14:30:00Z]
iex> WarframeWorldstateDataElixirTools.DateTimeTools.daily_reset(dt)
{~U[2024-01-15 00:00:00Z], ~U[2024-01-15 23:59:59Z]}
"""
def daily_reset(now) when is_struct(now) do
start_of_day = %{now | hour: 0, minute: 0, second: 0, microsecond: {0, 0}}
end_of_day = DateTime.add(start_of_day, @seconds_in_day - 1, :second)
{start_of_day, end_of_day}
end
@doc """
Returns a tuple with the start of Monday and end of Sunday for the week
containing the input timestamp. All timestamps are assumed to be UTC.
## Examples
iex> dt = ~U[2024-01-17 14:30:00Z]
iex> WarframeWorldstateDataElixirTools.DateTimeTools.weekly_reset(dt)
{~U[2024-01-15 00:00:00Z], ~U[2024-01-21 23:59:59Z]}
iex> dt = ~U[2024-01-15 00:00:00Z]
iex> WarframeWorldstateDataElixirTools.DateTimeTools.weekly_reset(dt)
{~U[2024-01-15 00:00:00Z], ~U[2024-01-21 23:59:59Z]}
iex> dt = ~U[2024-01-21 23:59:59Z]
iex> WarframeWorldstateDataElixirTools.DateTimeTools.weekly_reset(dt)
{~U[2024-01-15 00:00:00Z], ~U[2024-01-21 23:59:59Z]}
"""
def weekly_reset(now) when is_struct(now) do
day_of_week = Date.day_of_week(now)
start_of_week =
now
|> DateTime.add(-(day_of_week - 1) * @seconds_in_day, :second)
|> then(&%{&1 | hour: 0, minute: 0, second: 0, microsecond: {0, 0}})
end_of_week =
DateTime.add(start_of_week, @days_in_week * @seconds_in_day - 1, :second)
{start_of_week, end_of_week}
end
@doc """
Returns milliseconds from now to `timestamp` (`timestamp - now`).
Positive = future, negative = past.
## Examples
iex> now = ~U[2024-01-15 12:00:00Z]
iex> ts = ~U[2024-01-15 12:00:05Z]
iex> WarframeWorldstateDataElixirTools.DateTimeTools.from_now(ts, fn -> now end)
5000
iex> now = ~U[2024-01-15 12:00:00Z]
iex> ts = ~U[2024-01-15 11:59:55Z]
iex> WarframeWorldstateDataElixirTools.DateTimeTools.from_now(ts, fn -> now end)
-5000
"""
def from_now(timestamp, now_fn \\ &DateTime.utc_now/0)
when is_struct(timestamp) do
DateTime.diff(timestamp, now_fn.(), :millisecond)
end
@doc """
Returns milliseconds from `timestamp` to now (`now - timestamp`).
Positive = past, negative = future.
## Examples
iex> now = ~U[2024-01-15 12:00:00Z]
iex> ts = ~U[2024-01-15 11:59:55Z]
iex> WarframeWorldstateDataElixirTools.DateTimeTools.to_now(ts, fn -> now end)
5000
iex> now = ~U[2024-01-15 12:00:00Z]
iex> ts = ~U[2024-01-15 12:00:05Z]
iex> WarframeWorldstateDataElixirTools.DateTimeTools.to_now(ts, fn -> now end)
-5000
"""
def to_now(timestamp, now_fn \\ &DateTime.utc_now/0)
when is_struct(timestamp) do
DateTime.diff(now_fn.(), timestamp, :millisecond)
end
end