Current section
Files
Jump to
Current section
Files
lib/every.ex
defmodule Every do
@moduledoc """
Every gives you ability to use `Process.send_after/3` with
intervals which can be rounded to every:
1. Minute,
2. N minutes,
3. Hour,
4. N Hours,
5. Day.
Every function accepts an optional `relative_to` parameter, which can be used
to fake the current moment in time. If it is not provided, the current time
will be used.
**Note:** All functions return the difference in milliseconds!
"""
@doc """
Calculates how many milliseconds left until the next minute starts.
## Examples
iex> now = Timex.parse!("2018-10-14T16:48:12.000Z", "{ISO:Extended}")
iex> Every.minute(now)
48_000
"""
def minute(relative_to \\ Timex.now()) do
(60 - relative_to.second) * 1000
end
@doc """
Calculates how many milliseconds left until the next interval (minutes) will be
reached.
## Examples
iex> now = Timex.parse!("2018-10-14T16:48:12.000Z", "{ISO:Extended}")
iex> Every.minutes(5, now) # 16:50 > 15:50:00 - 16:48:12
108_000
"""
def minutes(interval, relative_to \\ Timex.now())
def minutes(interval, relative_to) do
minutes_until_next_interval = next_interval(relative_to.minute, interval)
{microseconds, _precision} = relative_to.microsecond
relative_to
|> Timex.shift(seconds: -relative_to.second)
|> Timex.shift(microseconds: -microseconds)
|> Timex.shift(minutes: minutes_until_next_interval)
|> Timex.diff(relative_to, :milliseconds)
end
@doc """
Calculates how many seconds left until the next hour starts.
## Examples
iex> now = Timex.parse!("2018-10-14T16:48:12.000Z", "{ISO:Extended}")
iex> Every.hour(now)
708_000
"""
def hour(relative_to \\ Timex.now()) do
{microseconds, _precision} = relative_to.microsecond
relative_to
|> Timex.shift(seconds: -relative_to.second)
|> Timex.shift(microseconds: -microseconds)
|> Timex.shift(minutes: -relative_to.minute)
|> Timex.shift(hours: 1)
|> Timex.diff(relative_to, :milliseconds)
end
@doc """
Calculates how many milliseconds left until the next interval (hours) will be
reached.
## Examples
iex> now = Timex.parse!("2018-10-14T16:48:12.000Z", "{ISO:Extended}")
iex> Every.hours(2, now)
4_308_000
"""
def hours(interval, relative_to \\ Timex.now())
def hours(interval, relative_to) do
hours_until_next_interval = next_interval(relative_to.hour, interval)
{microseconds, _precision} = relative_to.microsecond
relative_to
|> Timex.shift(seconds: -relative_to.second)
|> Timex.shift(microseconds: -microseconds)
|> Timex.shift(minutes: -relative_to.minute)
|> Timex.shift(hours: hours_until_next_interval)
|> Timex.diff(relative_to, :milliseconds)
end
@doc """
Calculates how many milliseconds left until the next day starts.
## Examples
iex> now = Timex.parse!("2018-10-14T16:48:12.000Z", "{ISO:Extended}")
iex> Every.day(now) # Time remaining 7h 25m 48s
25_908_000
"""
def day(relative_to \\ Timex.now()) do
relative_to
|> Timex.shift(days: 1)
|> Timex.beginning_of_day()
|> Timex.diff(relative_to, :milliseconds)
end
defp next_interval(value, round_value) do
# Uses `rem` function to get remainder for value
# then calculates next step value, for example
# value=48, round_value=15
# then the result will look like
# 15 - (48%15) = 12
round_value - rem(value, round_value)
end
end