Creating DateTime on a leap second and leap second list

Hello,

I am trying to work with DateTimes over leap seconds. I can’t create a %DateTime{} object on a leap second.

When using Tz I still get this issue:

My first attempt was to the ~U sigil:

iex> ~U[2016-12-30 23:59:60Z]
** (ArgumentError) cannot parse "2016-12-30 23:59:60Z" as UTC DateTime for Calendar.ISO, reason: :invalid_time
    (elixir 1.14.5) lib/kernel.ex:6260: Kernel.maybe_raise!/4
    (elixir 1.14.5) lib/kernel.ex:6239: Kernel.parse_with_calendar!/3
    (elixir 1.14.5) expanding macro: Kernel.sigil_U/2
    iex:5: (file)

Installing Tz and using it does not seem to help.

iex> DateTime.from_iso8601("2015-06-30T23:59:60Z", Tz.TimeZoneDatabase)
{:error, :invalid_time}

Trying to use ISO.Calendar directly does not work either

iex(19)> Calendar.ISO.datetime_to_string(2015, 12, 30, 23, 59, 60, {0, 0}, "Etc/UTC", "UTC", 0, 0, :basic)
** (FunctionClauseError) no function clause matching in Calendar.ISO.time_to_string/5    
    
    The following arguments were given to Calendar.ISO.time_to_string/5:
    
        # 1
        23
    
        # 2
        59
    
        # 3
        60
    
        # 4
        {0, 0}
    
        # 5
        :basic
    
    Attempted function clauses (showing 1 out of 1):
    
        def time_to_string(hour, minute, second, {ms_value, ms_precision} = microsecond, format) when is_integer(hour) and hour >= 0 and hour <= 23 and is_integer(minute) and minute >= 0 and minute <= 59 and is_integer(second) and second >= 0 and second <= 59 and is_integer(ms_value) and ms_value >= 0 and ms_value <= 999_999 and is_integer(ms_precision) and ms_precision >= 0 and ms_precision <= 6 and format === :basic or format === :extended
    
    (elixir 1.14.5) lib/calendar/iso.ex:1126: Calendar.ISO.time_to_string/5
    (elixir 1.14.5) lib/calendar/iso.ex:1306: Calendar.ISO.datetime_to_string/12
    iex:19: (file)

I belive this is the root of the issue, Calendar.ISO does not support leap second times. I’m not sure the Calendar is pluggable like the timezone is? Or if there is any third party, leap second supporting, Calendar implementation?

I was also trying to get a list of historic leap seconds (to convert from GPS time to a DateTime object) but I could not see an API in Tz to do this. So for now I have hardcoded a list of leapseconds in my application. Is there any built in way to get to this data in elixir or Tz?

Calendar.ISO or really all of elixir’s core datetime handling does indeed not support leap seconds. Calendars are a behaviour though, so in theory you could have another calendar, which handles leap seconds. Practically the calendar alone is likely not enough though and it would need adjustments and considerations in places outside of those calendar implementations as well.

Iirc the latest stance of the elixir team I saw on github discussions was that leap second support would require more input and thought.