Eyeon.Timestamp (eyeon v0.3.2)

Copy Markdown View Source

Precision-preserving Ion timestamp representation.

Ion timestamps carry precision and local offset semantics that native Elixir date/time types cannot represent. Two timestamps are Ion-equivalent only when they have the same precision, the same offset status, and the same component values. For example, 2001T and 2001-01T represent the same instant but have different precisions — they are NOT equivalent in Ion.

Fields

  • :year — always present
  • :month — nil for year precision
  • :day — nil for year/month precision
  • :hour — nil for date-only precision (always paired with minute)
  • :minute — nil for date-only precision
  • :second — nil for minute precision
  • :fraction — fractional seconds as a digit string (e.g. "123", "00300"), preserving trailing zeros for precision. nil if no fractional seconds.
  • :offset:unknown for -00:00, integer (minutes from UTC) for known offsets, nil when no time component is present
  • :precision — one of :year, :month, :day, :minute, :second, :fractional_second

Summary

Functions

Build a DateTime, NaiveDateTime, or Date from timestamp components.

Format a UTC offset in seconds as a zone abbreviation like "+05:30" or "-08:00".

Build a %Eyeon.Timestamp{} directly from parsed components.

Parse an Ion timestamp string into a %Eyeon.Timestamp{}.

Returns true if the given year is a leap year.

Maximum number of days in a given month, accounting for leap years.

Parse a fractional seconds string (like ".123456" or "123456") into a {microseconds, precision} tuple.

Convert to an Ion text representation string.

Convert to a native Elixir date/time type.

Convert to a UTC DateTime for timeline comparison.

Types

offset()

@type offset() :: :unknown | integer() | nil

precision()

@type precision() :: :year | :month | :day | :minute | :second | :fractional_second

t()

@type t() :: %Eyeon.Timestamp{
  day: pos_integer() | nil,
  fraction: String.t() | nil,
  hour: non_neg_integer() | nil,
  minute: non_neg_integer() | nil,
  month: pos_integer() | nil,
  offset: offset(),
  precision: precision(),
  second: non_neg_integer() | nil,
  year: pos_integer()
}

Functions

components_to_native(year, month, day, hour, minute, second, frac_str, offset)

@spec components_to_native(
  integer(),
  integer() | nil,
  integer() | nil,
  integer() | nil,
  integer() | nil,
  integer() | nil,
  String.t() | nil,
  integer()
) :: Date.t() | NaiveDateTime.t() | DateTime.t()

Build a DateTime, NaiveDateTime, or Date from timestamp components.

  • offset is in minutes, with -0x800 meaning unknown offset.
  • When hour/minute/day/month are nil, returns coarser types (Date).

format_zone_abbr(total_seconds)

@spec format_zone_abbr(integer()) :: String.t()

Format a UTC offset in seconds as a zone abbreviation like "+05:30" or "-08:00".

from_components(year, month, day, hour, minute, second, frac_str, offset)

@spec from_components(
  integer(),
  integer() | nil,
  integer() | nil,
  integer() | nil,
  integer() | nil,
  integer() | nil,
  String.t() | nil,
  integer()
) :: t()

Build a %Eyeon.Timestamp{} directly from parsed components.

Used by the binary decoder which already has components parsed. offset uses the binary encoding convention: -0x800 for unknown offset, minutes from UTC otherwise.

from_string(str)

@spec from_string(String.t()) :: t()

Parse an Ion timestamp string into a %Eyeon.Timestamp{}.

Accepts all Ion timestamp formats:

  • 2024T (year)
  • 2024-01T (year-month)
  • 2024-01-15 or 2024-01-15T (date)
  • 2024-01-15T12:30Z (minute with offset)
  • 2024-01-15T12:30:00Z (second with offset)
  • 2024-01-15T12:30:00.123Z (fractional second with offset)

leap_year?(year)

@spec leap_year?(integer()) :: boolean()

Returns true if the given year is a leap year.

max_days_in_month(year, month)

@spec max_days_in_month(integer(), integer()) :: integer()

Maximum number of days in a given month, accounting for leap years.

parse_frac_to_microsecond(frac_str)

@spec parse_frac_to_microsecond(nil | String.t()) ::
  {non_neg_integer(), non_neg_integer()}

Parse a fractional seconds string (like ".123456" or "123456") into a {microseconds, precision} tuple.

to_ion_string(ts)

@spec to_ion_string(t()) :: String.t()

Convert to an Ion text representation string.

to_native(ts)

@spec to_native(t()) :: Date.t() | NaiveDateTime.t() | DateTime.t()

Convert to a native Elixir date/time type.

Returns DateTime, NaiveDateTime, or Date depending on precision and offset.

to_utc(ts)

@spec to_utc(t()) :: DateTime.t()

Convert to a UTC DateTime for timeline comparison.

All timestamps are normalized to UTC. Unknown offsets are treated as UTC. Date-only timestamps are treated as midnight UTC.