Is there a need to add new data formats to represent dates and times? There are a bunch already: Date
, NaiveDateTime
, DateTime
structs in the ISO calendar. Additionally Erlang already has an integer representation of dates. E.g. {2017,1,8} |> :calendar.date_to_gregorian_days
and also functions for “gregorian seconds”.
If we want to add a behaviour for alternative calendar modules, could it simply require functions for conversions to and from ISO structs? E.g. %DateTime{calendar: Calendar.ISO}
, and the same for Date
and NaiveDateTime
.
ISO DateTime
structs already support leap seconds. Although there are reasons for not always taking leap seconds into account when doing conversions.
You can know about leap seconds up to ~6 months into the future. The Tzdata library provides this information. The Calendar library (calendar
on hex) uses the tzdata to make this list native Elixir 1.3+ DateTime structs. Example:
iex> Calendar.TimeZoneData.leap_seconds |> List.last
%DateTime{calendar: Calendar.ISO, day: 31, hour: 23, microsecond: 0,
minute: 59, month: 12, second: 60, std_offset: 0, time_zone: "Etc/UTC",
utc_offset: 0, year: 2016, zone_abbr: "UTC"}
This functionality is also used to validate DateTime structs where the second field has a value of 60.
Calendar.DateTime.from_erl({{2015, 12, 31}, {23, 59, 60}}, "Europe/London")
returns an error because there was no leap second at 2015 December 31st.
Calendar.DateTime.from_erl({{2015, 12, 31}, {23, 59, 60}}, "Europe/London")
{:error, :invalid_datetime}
But in 2016 there was, so this is allowed provided the newest tzdata is available:
Calendar.DateTime.from_erl({{2016, 12, 31}, {23, 59, 60}}, "Europe/London")
{:ok, %DateTime{calendar: Calendar.ISO, day: 31, hour: 23, microsecond: {0, 0}, minute: 59, month: 12, second: 60, std_offset: 0, time_zone: "Europe/London", utc_offset: 0, year: 2016, zone_abbr: "GMT"}}