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 amount() :: integer() | String.t()
@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()
@type error_type() :: {:error, atom()} | {:error, {atom(), atom()}}
@type parse_type() ::
  %{amount: amount(), unit: unit()} | {amount(), unit()} | amount()
@type unit() :: atom() | String.t()

Functions

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
Link to this function

diff(difference_type_1, difference_type2, unit \\ nil)

View Source
@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.

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
Link to this function

subtract(value_1, value_2)

View Source

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]
Link to this function

to_integer(period, convert_unit \\ nil)

View Source
@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}}
Link to this function

to_string(period, convert_unit \\ nil)

View Source
@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}}