View Source Periods (Periods v0.1.1)
Periods increments of time.
Periods are designed to represent fractions of time from milliseconds to decades in order to help make working with various time based structs easier.
Periods can be converted, added, and subtracted.
By default the base value is a second
you can choose a different base for your
application by setting the :default_value
in you Application config.
The only limitation are months. Due to the inconsistency of a period of a month from 28-31 days conversion and mathematical operations are limited.
Summary
Functions
Add a Period to a Period, Time, Date, DateTime, or NaiveDateTime.
Returns a list of all the current values Periods supports
Convert a Period from one unit to another unit.
Converts and returns a %Period{} or raise error.
Returns the value set by your Application environment or the default :second
Get the difference of Time, Date, DateTime, NaiveDateTime in a Period.
Create a new Period through a variety of input types.
Creates a new Period.
Creates a new Period or raises an error.
Subtract a Period from a Time, Date, DateTime, or NaiveDateTime.
Output a Period as an Integer with optional conversion unit.
Output a Period as a String with optional conversion unit.
Types
@type computation_type() :: Periods.Period.t() | Time.t() | Date.t() | DateTime.t() | NaiveDateTime.t()
@type difference_type() :: Time.t() | Date.t() | DateTime.t() | NaiveDateTime.t()
Functions
@spec add(computation_type(), computation_type()) :: computation_type() | error_type()
Add a Period to a Period, Time, Date, DateTime, or NaiveDateTime.
Note: Months
have limited additive properties
When performing addition of periods all values will be converted to the lowest unit value. For example if you add a Period of days to a Period of seconds then the result will be seconds.
When adding a period to an Elixir date/time struct the return will be the Elixir date/time struct.
Note: Since there is conversion involved you may loose fractional values such as adding 1 millisecond to a Date.
Examples
iex> Periods.add(%Period{amount: 10, unit: :day}, %Period{amount: 1000, unit: :second})
%Period(amount: 865000, unit: :second)
iex> DateTime.utc_now() |> Periods.add(%Period{amount: 1000, unit: :second})
~U[2023-07-09 14:14:50.896089Z]
iex> Time.utc_now() |> Periods.add(%Period{amount: 1000, unit: :second})
~T[14:17:04.932992]
iex> today = Date.utc_today()
~D[2023-07-09]
iex> Periods.add(today, %Period{amount: 1, unit: :millisecond})
~D[2023-07-09]
@spec all_units() :: [atom()]
Returns a list of all the current values Periods supports
Examples
iex> Periods.all_units()
[:millisecond, :second, :minute, :hour, :day, :week, :month, :year, :decade]
@spec convert(Periods.Period.t(), atom() | String.t()) :: Periods.Period.t() | error_type()
Convert a Period from one unit to another unit.
Note: Months
have limited conversion properties
When converting from a lower unit such as milliseconds to a higher unit such as seconds, since all return values are integers, you will loose precision due to rounding. In some conversion scenarios you may get a 0 value.
Examples
iex> Periods.convert(%Period{amount: 10, unit: :day}, :second)
%Periods.Period{amount: 864000, unit: :second}
iex> Periods.convert(%Period{amount: 864000, unit: :second}, :day)
%Period{amount: 10, unit: :day}
iex> Periods.convert(%Period{amount: 10, unit: :year}, :month)
%Periods.Period{amount: 120, unit: :month}
iex> Periods.convert(%Period{amount: 10, unit: :second}, :week)
%Periods.Period{amount: 0, unit: :week}
iex> Periods.convert(%Period{amount: 1000, unit: :second}, :month)
{:error, {:cannot_convert_to_month, :month}}
@spec convert!(Periods.Period.t(), atom() | String.t()) :: Periods.Period.t() | Periods.Conversion.ConversionError
Converts and returns a %Period{} or raise error.
Same as convert/2
excepts raises a %ConversionError{}
when unsuccessful
Examples
iex> Periods.convert!(%Period{amount: 10, unit: :day}, :second)
%Periods.Period{amount: 864000, unit: :second}
iex> Periods.convert!(%Period{amount: 1000, unit: :second}, :month)
** (Periods.Conversion.ConversionError) unit: bad type
@spec default_unit() :: atom()
Returns the value set by your Application environment or the default :second
Examples
iex> Periods.default_unit()
:second
@spec diff(difference_type(), difference_type(), unit()) :: {:ok, Periods.Period.t()} | error_type()
Get the difference of Time, Date, DateTime, NaiveDateTime in a Period.
Optional add unit for conversion. Some units will loose precision because fractional units are not supported. For example converting milliseconds to days will round to integer day.
Default conversion units will be dependant upon the struct.
- Time defaults to
:second
- Date defaults to
:day
- DateTIme defaults to
:second
- NaiveDateTime defaults to
:second
When getting the difference between two DateTimes with different timezones diff/3
will convert both timezones to UTC then calculate the difference.
For DateTime currently using the Tz hex package to help adjust timezones.
In order to use Timezone conversion please add to your application config:
config :elixir, :time_zone_database, Tz.TimeZoneDatabase
Examples
iex> Periods.diff(~T[21:30:43], ~T[13:50:17])
{:ok, %Periods.Period{amount: 27626, unit: :second}}
iex> Periods.diff(~D[2000-03-15], ~D[2000-01-01])
{:ok, %Periods.Period{amount: 74, unit: :day}}
iex> Periods.diff(~D[2000-03-15], ~D[2000-01-01], :second)
{:ok, %Periods.Period{amount: 6393600, unit: :second}}
iex> Periods.diff(#DateTime<2023-05-21 18:23:45.023+09:00 JST Asia/Tokyo>, #DateTime<2023-04-13 13:50:07.003+07:00 +07 Asia/Bangkok>)
{:ok, %Periods.Period{amount: 3292418, unit: :second}}
@spec new(parse_type()) :: {:ok, Periods.Period.t()} | error_type()
Create a new Period through a variety of input types.
Examples
iex> Periods.new(%{amount: 100, unit: :second})
{:ok, %Periods.Period{amount: 100, unit: :second}}
iex> Periods.new(%{amount: "100", unit: "second"})
{:ok, %Periods.Period{amount: 100, unit: :second}}
iex> Periods.new({100, "second"})
{:ok, %Periods.Period{amount: 100, unit: :second}}
iex> Periods.new("100")
{:ok, %Periods.Period{amount: 100, unit: :second}}
@spec new(amount(), unit()) :: {:ok, Periods.Period.t()} | error_type()
Creates a new Period.
Examples
iex> Periods.new(100, :second)
{:ok, %Periods.Period{amount: 100, unit: :second}}
iex> Periods.new("100", "second")
{:ok, %Periods.Period{amount: 100, unit: :second}}
@spec new!(parse_type()) :: Periods.Period.t() | Periods.Parser.ParserError
Creates a new Period or raises an error.
Same as new/1
excepts raises a %ParserError{}
when unsuccessful
Examples
iex> Periods.new!({100, "second"})
%Periods.Period{amount: 100, unit: :second}
iex> Periods.new!(100, :fort_nights)
** (Periods.Conversion.ConversionError) unit: bad type
@spec subtract(computation_type(), computation_type()) :: computation_type() | error_type()
Subtract a Period from a Time, Date, DateTime, or NaiveDateTime.
Note: Months
have limited subtracting properties
When performing subtraction of periods all values will be converted to the lowest unit value. For example if you subtract a Period of days from a Period of seconds then the result will be seconds.
When subtracting a period from an Elixir date/time struct the return will be the Elixir date/time struct.
Note: Since there is conversion involved you may loose fractional values such as subtracting 1 millisecond from a Date.
Examples
iex> Periods.subtract(%Period{amount: 10, unit: :day}, %Period{amount: 1000, unit: :second})
%Periods.Period{amount: 863000, unit: :second}
iex> DateTime.utc_now() |> Periods.subtract(%Period{amount: 1000, unit: :second})
~U[2023-07-09 14:08:32.916532Z]
iex> Time.utc_now() |> Periods.subtract(%Period{amount: 1000, unit: :second})
~T[14:08:45.831176]
iex> today = Date.utc_today()
~D[2023-07-10]
iex> Periods.subtract(today, %Period{amount: 10000000000000, unit: :millisecond})
~D[1706-08-21]
iex> Periods.subtract(today, %Period{amount: 3, unit: :year})
~D[2020-07-10]
@spec to_integer(Periods.Period.t(), unit() | nil) :: integer() | error_type()
Output a Period as an Integer with optional conversion unit.
Examples
iex> Periods.to_integer(%Period{amount: 10, unit: :day}, :second)
864000
iex> Periods.to_integer(%Period{amount: 10, unit: :day})
10
iex> Periods.to_integer(%Period{amount: 1000, unit: :second}, :month)
{:error, {:cannot_convert_to_month, :second}}
@spec to_string(Periods.Period.t(), unit() | nil) :: String.t() | error_type()
Output a Period as a String with optional conversion unit.
Examples
iex> Periods.to_string(%Period{amount: 10, unit: :day}, :second)
"864000 seconds"
iex> Periods.to_string(%Period{amount: 10, unit: :day})
"10 days"
iex> Periods.to_string(%Period{amount: 1, unit: :day})
"1 day"
iex> Periods.to_string(%Period{amount: 1000, unit: :second}, :month)
{:error, {:cannot_convert_to_month, :second}}