Packages

Momento is an Elixir port of Moment.js for the purpose of parsing, validating, manipulating, and formatting dates.

Current section

Files

Jump to
momento lib date.ex
Raw

lib/date.ex

defmodule Momento.Date do
import Momento.Guards
@moduledoc """
This module holds all the various `date/0`, 'date/1' and `date!/1` methods.
"""
@doc """
Get a `DateTime` struct representng now.
## Examples
iex> Momento.date
%DateTime{calendar: Calendar.ISO, day: 1, hour: 22, microsecond: {732692, 6},
minute: 56, month: 7, second: 5, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}
"""
@spec date() :: DateTime.t
def date, do: DateTime.from_unix!(:erlang.system_time(:nano_seconds), :nanoseconds)
@doc """
Spits back the given `DateTime` struct, for convenience.
## Examples
iex> Momento.date |> Momento.date
%DateTime{calendar: Calendar.ISO, day: 1, hour: 22, microsecond: {259334, 6},
minute: 56, month: 7, second: 46, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}
"""
@spec date(DateTime.t) :: DateTime.t
def date(%DateTime{} = arg), do: arg
@doc """
Get a `DateTime` struct by parsing a given string. Currently, only ISO8601 and ISO date strings are supported.
## Examples
iex> Momento.date("2016-04-20T15:05:13.991Z")
%DateTime{calendar: Calendar.ISO, day: 20, hour: 15, microsecond: {991000, 6},
minute: 5, month: 4, second: 13, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}
iex> Momento.date("2016-04-20")
%DateTime{calendar: Calendar.ISO, day: 20, hour: 0, microsecond: {0, 6},
minute: 0, month: 4, second: 0, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}
"""
@spec date(String.t) :: DateTime.t
# TODO: Add timezone support
# TODO: Add more formats to parse
def date(arg) when is_bitstring(arg) do
cond do
# ISO8601 - "2016-04-20T15:05:13.991Z"
Regex.match?(~r/^[0-9]{4}-[0-9]{2}-[0-9]{2}[tT\s][0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}[zZ]$/, arg) ->
[date, time] = String.split(arg, "T")
[year, month, day] = String.split(date, "-")
[hour, minute, seconds] = String.split(time, ":")
[second, milliseconds] = String.split(seconds, ".")
[millisecond, _] = String.split(milliseconds, "Z")
%DateTime{
year: String.to_integer(year),
month: String.to_integer(month),
day: String.to_integer(day),
hour: String.to_integer(hour),
minute: String.to_integer(minute),
second: String.to_integer(second),
microsecond: {String.to_integer(millisecond) * 1000, 6},
std_offset: 0,
utc_offset: 0,
time_zone: "Etc/UTC",
zone_abbr: "UTC"
}
# ISO date - "2016-04-20"
Regex.match?(~r/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/, arg) ->
[year, month, day] = String.split(arg, "-")
%DateTime{
year: String.to_integer(year),
month: String.to_integer(month),
day: String.to_integer(day),
hour: 0,
minute: 0,
second: 0,
microsecond: {0, 6},
std_offset: 0,
utc_offset: 0,
time_zone: "Etc/UTC",
zone_abbr: "UTC"
}
true -> {:error, "Unknown date format."}
end
end
@doc """
Get a `DateTime` struct from a UNIX timestamp. You can provide `seconds`, `milliseconds`, `microseconds` and
`nanoseconds`.
## Examples
iex> Momento.date(1467413967)
{:ok,
%DateTime{calendar: Calendar.ISO, day: 1, hour: 22, microsecond: {0, 0},
minute: 59, month: 7, second: 27, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}}
...> Momento.date(1467414084898)
{:ok,
%DateTime{calendar: Calendar.ISO, day: 1, hour: 23, microsecond: {898000, 3},
minute: 1, month: 7, second: 24, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}}
...> Momento.date(1467414112393174)
{:ok,
%DateTime{calendar: Calendar.ISO, day: 1, hour: 23, microsecond: {393174, 6},
minute: 1, month: 7, second: 52, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}}
...> Momento.date(1467414144089210599)
{:ok,
%DateTime{calendar: Calendar.ISO, day: 1, hour: 23, microsecond: {89210, 6},
minute: 2, month: 7, second: 24, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}}
"""
# TODO: This is probably wrong
@spec date(integer) :: {:ok, DateTime.t}
def date(s) when is_integer(s) and s > 999999999999999999, do: DateTime.from_unix(s, :nanoseconds)
def date(s) when is_integer(s) and s > 999999999999999, do: DateTime.from_unix(s, :microseconds)
def date(s) when is_integer(s) and s > 999999999999, do: DateTime.from_unix(s, :milliseconds)
def date(s) when is_integer(s) and positive?(s), do: DateTime.from_unix(s, :seconds)
@doc """
Get a `DateTime` struct from a UNIX timestamp without the tuple. You can provide `seconds`, `milliseconds`,
`microseconds` and `nanoseconds`.
## Examples
iex> Momento.date!(1467413967)
%DateTime{calendar: Calendar.ISO, day: 1, hour: 22, microsecond: {0, 0},
minute: 59, month: 7, second: 27, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}
"""
@spec date(integer) :: DateTime.t
def date!(s), do: ({:ok, datetime} = date(s); datetime)
end