DateTime
A datetime implementation with a time zone.
This datetime can be seen as an ephemeral snapshot of a datetime at a given time zone. For such purposes, it also includes both UTC and Standard offsets, as well as the zone abbreviation field used exclusively for formatting purposes.
Remember, comparisons in Elixir using ==
, >
, <
and friends are structural and based on the DateTime struct fields. For proper comparison between datetimes, use the compare/2
function.
The functions on this module work with the DateTime
struct as well as any struct that contains the same fields as the DateTime
struct. Such functions expect Calendar.datetime/0
in their typespecs (instead of t/0
).
Developers should avoid creating the DateTime struct directly and instead rely on the functions provided by this module as well as the ones in 3rd party calendar libraries.
Where are my functions?
You will notice this module only contains conversion functions as well as functions that work on UTC. This is because a proper DateTime implementation requires a TimeZone database which currently is not provided as part of Elixir.
Such may be addressed in upcoming versions, meanwhile, use 3rd party packages to provide DateTime building and similar functionality with time zone backing.
Summary
Types
Functions
- compare(datetime1, datetime2)
-
Compares two datetime structs
- convert(datetime, calendar)
-
Converts a given
datetime
from one calendar to another - convert!(datetime, calendar)
-
Converts a given
datetime
from one calendar to another - diff(datetime1, datetime2, unit \\ :second)
-
Subtracts
datetime2
fromdatetime1
- from_iso8601(string, calendar \\ Calendar.ISO)
-
Parses the extended “Date and time of day” format described by ISO 8601:2004
- from_naive(naive_datetime, time_zone)
-
Converts the given
NaiveDateTime
toDateTime
- from_naive!(naive_datetime, time_zone)
-
Converts the given
NaiveDateTime
toDateTime
- from_unix(integer, unit \\ :second, calendar \\ Calendar.ISO)
-
Converts the given Unix time to
DateTime
- from_unix!(integer, unit \\ :second, calendar \\ Calendar.ISO)
-
Converts the given Unix time to
DateTime
- to_date(datetime)
- to_iso8601(datetime, format \\ :extended)
-
Converts the given datetime to ISO 8601:2004 format
- to_naive(datetime)
-
Converts the given
datetime
into aNaiveDateTime
- to_string(datetime)
-
Converts the given
datetime
to a string according to its calendar - to_time(datetime)
- to_unix(datetime, unit \\ :second)
-
Converts the given
datetime
to Unix time - truncate(datetime, precision)
-
Returns the given datetime with the microsecond field truncated to the given precision (
:microsecond
,millisecond
or:second
) - utc_now(calendar \\ Calendar.ISO)
-
Returns the current datetime in UTC
Types
t()
t() :: %DateTime{ calendar: Calendar.calendar(), day: Calendar.day(), hour: Calendar.hour(), microsecond: Calendar.microsecond(), minute: Calendar.minute(), month: Calendar.month(), second: Calendar.second(), std_offset: Calendar.std_offset(), time_zone: Calendar.time_zone(), utc_offset: Calendar.utc_offset(), year: Calendar.year(), zone_abbr: Calendar.zone_abbr() }
Functions
compare(datetime1, datetime2)
compare(Calendar.datetime(), Calendar.datetime()) :: :lt | :eq | :gt
Compares two datetime structs.
Returns :gt
if the first datetime is later than the second and :lt
for vice versa. If the two datetimes are equal :eq
is returned.
Note that both UTC and Standard offsets will be taken into account when comparison is done.
Examples
iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"} iex> dt2 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"} iex> DateTime.compare(dt1, dt2) :gt
convert(datetime, calendar)
convert(Calendar.datetime(), Calendar.calendar()) :: {:ok, t()} | {:error, :incompatible_calendars}
Converts a given datetime
from one calendar to another.
If it is not possible to convert unambiguously between the calendars (see Calendar.compatible_calendars?/2
), an {:error, :incompatible_calendars}
tuple is returned.
Examples
Imagine someone implements Calendar.Holocene
, a calendar based on the Gregorian calendar that adds exactly 10,000 years to the current Gregorian year:
iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"} iex> DateTime.convert(dt1, Calendar.Holocene) {:ok, %DateTime{calendar: Calendar.Holocene, day: 29, hour: 23, microsecond: {0, 0}, minute: 0, month: 2, second: 7, std_offset: 0, time_zone: "America/Manaus", utc_offset: -14400, year: 12000, zone_abbr: "AMT"}}
convert!(datetime, calendar)
convert!(Calendar.datetime(), Calendar.calendar()) :: t() | no_return()
Converts a given datetime
from one calendar to another.
If it is not possible to convert unambiguously between the calendars (see Calendar.compatible_calendars?/2
), an ArgumentError is raised.
Examples
Imagine someone implements Calendar.Holocene
, a calendar based on the Gregorian calendar that adds exactly 10,000 years to the current Gregorian year:
iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"} iex> DateTime.convert!(dt1, Calendar.Holocene) %DateTime{calendar: Calendar.Holocene, day: 29, hour: 23, microsecond: {0, 0}, minute: 0, month: 2, second: 7, std_offset: 0, time_zone: "America/Manaus", utc_offset: -14400, year: 12000, zone_abbr: "AMT"}
diff(datetime1, datetime2, unit \\ :second)
Subtracts datetime2
from datetime1
.
The answer can be returned in any unit
available from System.time_unit/0
.
This function returns the difference in seconds where seconds are measured according to Calendar.ISO
.
Examples
iex> dt1 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"} iex> dt2 = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"} iex> DateTime.diff(dt1, dt2) 18000 iex> DateTime.diff(dt2, dt1) -18000
from_iso8601(string, calendar \\ Calendar.ISO)
from_iso8601(String.t(), Calendar.calendar()) :: {:ok, t(), Calendar.utc_offset()} | {:error, atom()}
Parses the extended “Date and time of day” format described by ISO 8601:2004.
Since ISO 8601 does not include the proper time zone, the given string will be converted to UTC and its offset in seconds will be returned as part of this function. Therefore offset information must be present in the string.
As specified in the standard, the separator “T” may be omitted if desired as there is no ambiguity within this function.
Time representations with reduced accuracy are not supported.
Note that while ISO 8601 allows datetimes to specify 24:00:00 as the zero hour of the next day, this notation is not supported by Elixir.
Examples
iex> {:ok, datetime, 0} = DateTime.from_iso8601("2015-01-23T23:50:07Z") iex> datetime #DateTime<2015-01-23 23:50:07Z> iex> {:ok, datetime, 9000} = DateTime.from_iso8601("2015-01-23T23:50:07.123+02:30") iex> datetime #DateTime<2015-01-23 21:20:07.123Z> iex> {:ok, datetime, 9000} = DateTime.from_iso8601("2015-01-23T23:50:07,123+02:30") iex> datetime #DateTime<2015-01-23 21:20:07.123Z> iex> DateTime.from_iso8601("2015-01-23P23:50:07") {:error, :invalid_format} iex> DateTime.from_iso8601("2015-01-23 23:50:07A") {:error, :invalid_format} iex> DateTime.from_iso8601("2015-01-23T23:50:07") {:error, :missing_offset} iex> DateTime.from_iso8601("2015-01-23 23:50:61") {:error, :invalid_time} iex> DateTime.from_iso8601("2015-01-32 23:50:07") {:error, :invalid_date} iex> DateTime.from_iso8601("2015-01-23T23:50:07.123-00:00") {:error, :invalid_format} iex> DateTime.from_iso8601("2015-01-23T23:50:07.123-00:60") {:error, :invalid_format}
from_naive(naive_datetime, time_zone)
from_naive(NaiveDateTime.t(), Calendar.time_zone()) :: {:ok, t()}
Converts the given NaiveDateTime
to DateTime
.
It expects a time zone to put the NaiveDateTime in. Currently it only supports “Etc/UTC” as time zone.
Examples
iex> {:ok, datetime} = DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC") iex> datetime #DateTime<2016-05-24 13:26:08.003Z>
from_naive!(naive_datetime, time_zone)
from_naive!(NaiveDateTime.t(), Calendar.time_zone()) :: t()
Converts the given NaiveDateTime
to DateTime
.
It expects a time zone to put the NaiveDateTime in. Currently it only supports “Etc/UTC” as time zone.
Examples
iex> DateTime.from_naive!(~N[2016-05-24 13:26:08.003], "Etc/UTC") #DateTime<2016-05-24 13:26:08.003Z>
from_unix(integer, unit \\ :second, calendar \\ Calendar.ISO)
from_unix(integer(), :native | System.time_unit(), Calendar.calendar()) :: {:ok, t()} | {:error, atom()}
Converts the given Unix time to DateTime
.
The integer can be given in different unit according to System.convert_time_unit/3
and it will be converted to microseconds internally.
Unix times are always in UTC and therefore the DateTime will be returned in UTC.
Examples
iex> {:ok, datetime} = DateTime.from_unix(1464096368) iex> datetime #DateTime<2016-05-24 13:26:08Z> iex> {:ok, datetime} = DateTime.from_unix(1432560368868569, :microsecond) iex> datetime #DateTime<2015-05-25 13:26:08.868569Z>
The unit can also be an integer as in System.time_unit/0
:
iex> {:ok, datetime} = DateTime.from_unix(143256036886856, 1024) iex> datetime #DateTime<6403-03-17 07:05:22.320Z>
Negative Unix times are supported, up to -62167219200 seconds, which is equivalent to “0000-01-01T00:00:00Z” or 0 Gregorian seconds.
from_unix!(integer, unit \\ :second, calendar \\ Calendar.ISO)
from_unix!(integer(), :native | System.time_unit(), Calendar.calendar()) :: t()
Converts the given Unix time to DateTime
.
The integer can be given in different unit according to System.convert_time_unit/3
and it will be converted to microseconds internally.
Unix times are always in UTC and therefore the DateTime will be returned in UTC.
Examples
# An easy way to get the Unix epoch is passing 0 to this function iex> DateTime.from_unix!(0) #DateTime<1970-01-01 00:00:00Z> iex> DateTime.from_unix!(1464096368) #DateTime<2016-05-24 13:26:08Z> iex> DateTime.from_unix!(1432560368868569, :microsecond) #DateTime<2015-05-25 13:26:08.868569Z>
to_date(datetime)
to_date(t()) :: Date.t()
Converts a DateTime
into a Date
.
Because Date
does not hold time nor time zone information, data will be lost during the conversion.
Examples
iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"} iex> DateTime.to_date(dt) ~D[2000-02-29]
to_iso8601(datetime, format \\ :extended)
to_iso8601(Calendar.datetime(), :extended | :basic) :: String.t()
Converts the given datetime to ISO 8601:2004 format.
By default, DateTime.to_iso8601/2
returns datetimes formatted in the “extended” format, for human readability. It also supports the “basic” format through passing the :basic
option.
Only supports converting datetimes which are in the ISO calendar, attempting to convert datetimes from other calendars will raise.
WARNING: the ISO 8601 datetime format does not contain the time zone nor its abbreviation, which means information is lost when converting to such format.
Examples
iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"} iex> DateTime.to_iso8601(dt) "2000-02-29T23:00:07+01:00" iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "UTC", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"} iex> DateTime.to_iso8601(dt) "2000-02-29T23:00:07Z" iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"} iex> DateTime.to_iso8601(dt, :extended) "2000-02-29T23:00:07-04:00" iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"} iex> DateTime.to_iso8601(dt, :basic) "20000229T230007-0400"
to_naive(datetime)
to_naive(t()) :: NaiveDateTime.t()
Converts the given datetime
into a NaiveDateTime
.
Because NaiveDateTime
does not hold time zone information, any time zone related data will be lost during the conversion.
Examples
iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 1}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"} iex> DateTime.to_naive(dt) ~N[2000-02-29 23:00:07.0]
to_string(datetime)
to_string(Calendar.datetime()) :: String.t()
Converts the given datetime
to a string according to its calendar.
Examples
iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"} iex> DateTime.to_string(dt) "2000-02-29 23:00:07+01:00 CET Europe/Warsaw" iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "UTC", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: 0, std_offset: 0, time_zone: "Etc/UTC"} iex> DateTime.to_string(dt) "2000-02-29 23:00:07Z" iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "AMT", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 0}, ...> utc_offset: -14400, std_offset: 0, time_zone: "America/Manaus"} iex> DateTime.to_string(dt) "2000-02-29 23:00:07-04:00 AMT America/Manaus"
to_time(datetime)
to_time(t()) :: Time.t()
Converts a DateTime
into Time
.
Because Time
does not hold date nor time zone information, data will be lost during the conversion.
Examples
iex> dt = %DateTime{year: 2000, month: 2, day: 29, zone_abbr: "CET", ...> hour: 23, minute: 0, second: 7, microsecond: {0, 1}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Warsaw"} iex> DateTime.to_time(dt) ~T[23:00:07.0]
to_unix(datetime, unit \\ :second)
to_unix(Calendar.datetime(), System.time_unit()) :: integer()
Converts the given datetime
to Unix time.
The datetime
is expected to be using the ISO calendar with a year greater than or equal to 0.
It will return the integer with the given unit, according to System.convert_time_unit/3
.
Examples
iex> 1464096368 |> DateTime.from_unix!() |> DateTime.to_unix() 1464096368 iex> dt = %DateTime{calendar: Calendar.ISO, day: 20, hour: 18, microsecond: {273806, 6}, ...> minute: 58, month: 11, second: 19, time_zone: "America/Montevideo", ...> utc_offset: -10800, std_offset: 3600, year: 2014, zone_abbr: "UYST"} iex> DateTime.to_unix(dt) 1416517099 iex> flamel = %DateTime{calendar: Calendar.ISO, day: 22, hour: 8, microsecond: {527771, 6}, ...> minute: 2, month: 3, second: 25, std_offset: 0, time_zone: "Etc/UTC", ...> utc_offset: 0, year: 1418, zone_abbr: "UTC"} iex> DateTime.to_unix(flamel) -17412508655
truncate(datetime, precision)
truncate(t(), :microsecond | :millisecond | :second) :: t()
Returns the given datetime with the microsecond field truncated to the given precision (:microsecond
, millisecond
or :second
).
Examples
iex> dt1 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: "CET", ...> hour: 11, minute: 45, second: 18, microsecond: {123456, 6}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Paris"} iex> DateTime.truncate(dt1, :microsecond) #DateTime<2017-11-07 11:45:18.123456+01:00 CET Europe/Paris> iex> dt2 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: "CET", ...> hour: 11, minute: 45, second: 18, microsecond: {123456, 6}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Paris"} iex> DateTime.truncate(dt2, :millisecond) #DateTime<2017-11-07 11:45:18.123+01:00 CET Europe/Paris> iex> dt3 = %DateTime{year: 2017, month: 11, day: 7, zone_abbr: "CET", ...> hour: 11, minute: 45, second: 18, microsecond: {123456, 6}, ...> utc_offset: 3600, std_offset: 0, time_zone: "Europe/Paris"} iex> DateTime.truncate(dt3, :second) #DateTime<2017-11-07 11:45:18+01:00 CET Europe/Paris>
utc_now(calendar \\ Calendar.ISO)
utc_now(Calendar.calendar()) :: t()
Returns the current datetime in UTC.
Examples
iex> datetime = DateTime.utc_now() iex> datetime.time_zone "Etc/UTC"
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.6.6/DateTime.html