aws/internal/codec/json_timestamp
JSON-side timestamp decoder. AWS protocol families disagree on
the wire shape of @timestamp fields:
- awsJson1_0 / awsJson1_1 default: epoch-seconds number (Int OR Float — services like KitchenSinkOperation send doubles)
- restJson1 / restXml default: ISO 8601 string
- Any protocol with
@timestampFormat("http-date"): HTTP-date string
We never know which the server will send for a given field —
fractional-second tests in particular surface Floats where the
schema declares an Int member. Returning option.None on decode
failure would mask data; instead we accept all three forms and
coerce to Int (epoch seconds).
Types
Higher-precision timestamp value with nanosecond resolution.
AWS services like CloudWatch, EventBridge, and metric APIs ship
Float epoch-seconds wire values that carry sub-second
precision; the existing Int decoder truncates them. Callers
who need the precision use Timestamp end-to-end:
import aws/internal/codec/json_timestamp.{type Timestamp, Timestamp}
let t = Timestamp(seconds: 1700000000, nanoseconds: 123_000_000)
// ⇒ 2023-11-14T22:13:20.123 UTC
nanoseconds is bounded to [0, 999_999_999] by convention;
callers normalising from a Float wire value get this for free
(see decoder_precise).
pub type Timestamp {
Timestamp(seconds: Int, nanoseconds: Int)
}
Constructors
-
Timestamp(seconds: Int, nanoseconds: Int)
Values
pub fn decoder() -> decode.Decoder(Int)
Decode Int | Float | String into epoch seconds. Falls back to 0
when none of the forms match, which matches gleam/dynamic’s
default decode.failure payload style and lets the caller surface
the decode failure via the standard Decoder machinery rather than
crashing on bad data.
pub fn decoder_precise() -> decode.Decoder(Timestamp)
Decode an AWS timestamp wire value into a Timestamp that
preserves sub-second precision when present.
Int→Timestamp(seconds: n, nanoseconds: 0)Float→ fractional seconds extracted via floor + scaling to nanoseconds. Negative timestamps (pre-1970) handled by normalising the fractional remainder sonanosecondsis always in[0, 999_999_999].String→ ISO 8601 / HTTP-date, parsed with second-level precision today (fractional ISO timestamps would need an FFI extension; tracked separately).
pub fn encode_epoch_seconds(t: Timestamp) -> json.Json
Encode a Timestamp as a JSON epoch-seconds number. When
nanoseconds == 0 we emit a JSON Int (1700000000) so the
wire bytes match the existing json.int path the codegen
uses for the Int API — flipping a member to precise must
not perturb the wire form for callers who never set
nanoseconds. When nanoseconds > 0 we emit a JSON Float
(1700000000.5) so the fractional component reaches the
server intact.
pub fn epoch_seconds_text(t: Timestamp) -> String
Render a Timestamp as a plain epoch-seconds integer string
("1700000000"). Used by URI / query / header / XML emitters
when @timestampFormat("epoch-seconds") is in force — the
wire form is the integer-as-decimal-digits, no fractional
component.
pub fn format_http_date(seconds: Int) -> String
Tue, 29 Apr 2014 18:30:38 GMT. Used by
@timestampFormat("http-date") body fields and headers.
pub fn format_http_date_precise(t: Timestamp) -> String
Format a Timestamp as HTTP-date
(Tue, 29 Apr 2014 18:30:38 GMT). Same nanosecond caveat as
format_iso8601_precise — HTTP-date is whole-second precision
by definition.
pub fn format_iso8601(seconds: Int) -> String
2024-01-02T03:04:05Z. Inverse of parse_iso8601_ffi.
pub fn format_iso8601_precise(t: Timestamp) -> String
Format a Timestamp as ISO 8601 (2024-01-02T03:04:05Z).
Wire-equivalent to format_iso8601(t.seconds) — sub-second
precision is dropped because the underlying FFI doesn’t
emit fractional seconds yet. Promoted to a distinct entry
point so the codegen can call this from Timestamp-typed
code paths without a redundant timestamp_to_int step.
pub fn int_to_timestamp(seconds: Int) -> Timestamp
Promote an Int epoch seconds value to a Timestamp with
zero nanoseconds. Symmetric with timestamp_to_int.
pub fn parse_http_date(s: String) -> Result(Timestamp, Nil)
Parse an HTTP-date timestamp string (“Tue, 29 Apr 2014 18:30:38 GMT”)
into a Timestamp. The default @timestampFormat for
@httpHeader bindings per Smithy core — used by Last-Modified,
Expires, Date, etc.
pub fn parse_iso8601(s: String) -> Result(Timestamp, Nil)
Parse an ISO 8601 timestamp string (“2024-01-02T03:04:05Z”) into a
Timestamp at second precision. nanoseconds is always 0 until
the FFI gains fractional-second support. Used by the header
extractor for members carrying @timestampFormat("date-time").
pub fn timestamp_to_int(t: Timestamp) -> Int
Convert Timestamp back to integer epoch seconds, dropping the
nanosecond component. Symmetric with int_to_timestamp and
useful when callers want to bridge to the existing Int API.