MsgpackDateTime (msgpack_datetime v0.1.0)

View Source

This module implements the msgpack_ext behaviour for (un)packing Elixir DateTimes as MessagePack ext -1 types. Use by adding {:ext, MsgpackDateTime} to :msgpack.unpack(_, options), and (un)wrap your DateTimes as {MsgpackDateTime, dt}.

Packing DateTimes directly cannot be implemented because :msgpack only considers erlang structs (so, tuples: {module, ...}) to be extendable and serialises Elixir structs (so, maps: %{__struct__: DateTime, ...}) as maps. Thus, the wrapping.

iex> dt = ~U[2025-12-10 12:53:25Z]
...> assert :msgpack.pack({MsgpackDateTime, dt}, [{:ext, MsgpackDateTime}])
...>        === <<214, 255, 105, 57, 109, 69>>
...> assert :msgpack.unpack("\x93\xC4\x06record\xD6\xFFi9mE\xCD\x01\xA4", [{:ext, MsgpackDateTime}])
...>        === {:ok, ["record", {MsgpackDateTime, dt}, 420]}

Elixir DateTimes have microsecond precision, but MessagePack provides nanosecond precision, so an unpack+pack won't round-trip if the packed timestamp had a non-zero nanosecond component.

Summary

Functions

pack_ext(arg, _)

@spec pack_ext(
  {MsgpackDateTime,
   %DateTime{
     calendar: term(),
     day: term(),
     hour: term(),
     microsecond: term(),
     minute: term(),
     month: term(),
     second: term(),
     std_offset: term(),
     time_zone: term(),
     utc_offset: term(),
     year: term(),
     zone_abbr: term()
   }},
  any()
) :: {:ok, {-1, binary()}}

unpack_ext(arg1, blob, _)

@spec unpack_ext(-1, binary(), any()) ::
  {:ok,
   {MsgpackDateTime,
    %DateTime{
      calendar: term(),
      day: term(),
      hour: term(),
      microsecond: term(),
      minute: term(),
      month: term(),
      second: term(),
      std_offset: term(),
      time_zone: term(),
      utc_offset: term(),
      year: term(),
      zone_abbr: term()
    }}}
  | {:error, any()}