Skip to content

File dp_isotime.h

FileList > inc > dp_isotime.h

Go to the source code of this file

ISO 8601 UTC timestamps in both spellings — filename-safe basic for names doppler writes,extended for the wire formats that mandate it.More...

  • #include <stdint.h>
  • #include <stdio.h>
  • #include <time.h>

Public Static Functions

Type Name
int64_t dp_isotime_days_from_civil_ (int64_t y, unsigned m, unsigned d)
Days since 1970-01-01 for a proleptic-Gregorian civil date.
int dp_isotime_digits_ (const char ** p, int n, int * out)
Reads n decimal digits, advancingp . 0 on success.
int dp_isotime_format (char * buf, size_t cap, int64_t sec, uint32_t nsec, unsigned frac)
int dp_isotime_format_as (char * buf, size_t cap, int64_t sec, uint32_t nsec, unsigned frac, int style)
int dp_isotime_now (char * buf, size_t cap, unsigned frac)
int dp_isotime_parse (const char * s, int64_t * sec, uint32_t * nsec)
Parses an ISO 8601 UTC timestamp into UNIX seconds + nanoseconds.

Macros

Type Name
define DP_ISOTIME_BASIC 0
define DP_ISOTIME_EXTENDED 1
define DP_ISOTIME_MAX 32
define DP_ISOTIME_MSEC 3u
define DP_ISOTIME_NSEC 9u
define DP_ISOTIME_SEC 0u
define DP_ISOTIME_USEC 6u

Detailed Description

Extended ISO 8601 (2026-08-05T04:15:30Z) is what a human reads, what doppler's CLI logs print, and what SigMF's core:datetime requires. It is also illegal in a filename on Windows and FAT, because of the colons, and awkward to quote in a shell. The basic form drops the separators: Both come out of dp_isotime_format_as, one calendar computation and one truncation rule rendered two ways, because the only thing that differs is whether strftime writes the separators. A second formatter would be a second place for the truncation rule below to be got wrong.

The basic format is not defined here. It is just-bashit's iso-8601-basic (src/just_bashit/datetime.sh), whose stated contract is "path and file-name-friendly characters only". doppler formats it in C rather than shelling out — a library shipped as a wheel cannot put its file naming behind a runtime bash + date/gdate lookup on PATH, and clock_gettime hands back the nanoseconds the sub-second field needs anyway. Code cannot be shared between a bash library and a C one, so the agreement is held by the golden vectors in native/tests/test_dp_isotime.c rather than asserted.

The fraction truncates; it never rounds. .999888777 at millisecond precision is .999, matching the shell helper. Rounding would carry .9996 to 1.000 and step the seconds field, emitting a timestamp one second in the future that disagrees with every name written beside it. The integer division below is what makes that structural rather than a convention someone has to remember.

Header-only, like dp_crc16.h, so no component grows a link-line dependency for a formatter.

Note:

CLOCK_REALTIME steps under NTP. These names are unique and human-readable, not a chronological sort key.

Public Static Functions Documentation

function dp_isotime_days_from_civil_

Days since 1970-01-01 for a proleptic-Gregorian civil date.

static inline int64_t dp_isotime_days_from_civil_ (
    int64_t y,
    unsigned m,
    unsigned d
) 

Howard Hinnant's days_from_civil, which is exact for every date and needs no timezone database. Written out rather than reached through timegm: that function is neither C nor POSIX, and the one thing this parser must never do is consult the ambient TZ.


function dp_isotime_digits_

Reads n decimal digits, advancingp . 0 on success.

static inline int dp_isotime_digits_ (
    const char ** p,
    int n,
    int * out
) 


function dp_isotime_format

static inline int dp_isotime_format (
    char * buf,
    size_t cap,
    int64_t sec,
    uint32_t nsec,
    unsigned frac
) 

Format one instant as a filename-safe basic-format UTC timestamp.

The default spelling: this is the one that goes in a name doppler writes. dp_isotime_format_as with DP_ISOTIME_EXTENDED is for the wire formats that mandate separators.

Parameters:

  • buf Destination; receives a NUL-terminated string.
  • cap Size of buf; DP_ISOTIME_MAX is always enough.
  • sec Seconds since the UNIX epoch (UTC).
  • nsec Nanoseconds within that second, [0, 999999999].
  • frac Fractional digits, as dp_isotime_format_as.

Returns:

As dp_isotime_format_as.


function dp_isotime_format_as

static inline int dp_isotime_format_as (
    char * buf,
    size_t cap,
    int64_t sec,
    uint32_t nsec,
    unsigned frac,
    int style
) 

Format one instant as a UTC timestamp in either separator style.

Parameters:

  • buf Destination; receives a NUL-terminated string.
  • cap Size of buf; DP_ISOTIME_MAX is always enough.
  • sec Seconds since the UNIX epoch (UTC).
  • nsec Nanoseconds within that second, [0, 999999999].
  • frac Fractional digits: 0, 3, 6 or 9 (the DP_ISOTIME_MSEC family). Any other value is rejected.
  • style DP_ISOTIME_BASIC or DP_ISOTIME_EXTENDED.

Returns:

Characters written (excluding the NUL), or -1 if frac is not one of the four, style is neither, nsec is out of range, buf is too small, or the instant is not representable as a UTC calendar time.


function dp_isotime_now

static inline int dp_isotime_now (
    char * buf,
    size_t cap,
    unsigned frac
) 

Format the current wall clock, the way a capture filename wants it.

Reads CLOCK_REALTIME directly: no PATH lookup, no subprocess, and the nanoseconds arrive already split from the seconds.

Parameters:

  • buf Destination; receives a NUL-terminated string.
  • cap Size of buf; DP_ISOTIME_MAX is always enough.
  • frac Fractional digits, as dp_isotime_format. Prefer DP_ISOTIME_MSEC or finer when the stamp is being used to keep filenames apart — two captures written in the same second collide at seconds resolution.

Returns:

As dp_isotime_format, or -1 if the clock read fails.


function dp_isotime_parse

Parses an ISO 8601 UTC timestamp into UNIX seconds + nanoseconds.

static inline int dp_isotime_parse (
    const char * s,
    int64_t * sec,
    uint32_t * nsec
) 

Accepts both spellings this file writes — extended (2026-08-05T04:15:30.123456Z) and basic (20260805T041530Z) — with an optional fraction of one to nine digits, and either Z or an explicit +hh:mm / -hhmm offset, which is applied.

A timestamp with NO zone is REFUSED. It is the one input where guessing costs hours rather than nothing: read as UTC, a local-time stamp dates a capture wrong and looks authoritative doing it. A caller that cannot parse a start time has ways to say so (the reader reports WFM_T0_NONE); a caller holding a wrong one does not.

Parameters:

  • s The timestamp.
  • sec Receives UNIX seconds (may be negative, before 1970).
  • nsec Receives the nanoseconds part, 0 when no fraction is given.

Returns:

0 on success, -1 on a NULL argument or any malformed field.

int64_t  sec;
uint32_t nsec;
dp_isotime_parse ("1970-01-01T00:00:01Z", &sec, &nsec);  // sec == 1

Macro Definition Documentation

define DP_ISOTIME_BASIC

#define DP_ISOTIME_BASIC `0`

Separator style: 20260805T041530Z, safe in a filename.


define DP_ISOTIME_EXTENDED

#define DP_ISOTIME_EXTENDED `1`

Separator style: 2026-08-05T04:15:30Z, what SigMF and humans want.


define DP_ISOTIME_MAX

#define DP_ISOTIME_MAX `32`

Bytes needed for the longest form (nanoseconds) plus the NUL.


define DP_ISOTIME_MSEC

#define DP_ISOTIME_MSEC `3u`

define DP_ISOTIME_NSEC

#define DP_ISOTIME_NSEC `9u`

define DP_ISOTIME_SEC

#define DP_ISOTIME_SEC `0u`

Fractional digits iso-8601-basic offers: none, -m, -u, -n.


define DP_ISOTIME_USEC

#define DP_ISOTIME_USEC `6u`


The documentation for this class was generated from the following file native/inc/dp_isotime.h