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