Skip to content
DateTimeFromUnixNs

DateTimeFromUnixNs

Description

Break a UTC nanoseconds-since-epoch value down into a DateTime, rendered at the fixed offset utc_offset_seconds (east-positive). Pass 0 to render in UTC.

Parameters

Name Direction Description
unix_ns in Nanoseconds since the Unix epoch (UTC).
utc_offset_seconds in Offset to apply before breaking down; recorded verbatim in the result’s utc_offset_seconds.

Success

Returns the corresponding DateTime.

Failure

Cannot fail.

Usage example (Cross-references)

Usage examples (Cross-references)
        // Derive the weekday from the canonical conversion so a parsed value
        // carries a correct weekday regardless of the input text.
        tmp.weekday = DateTimeFromUnixNs(DateTimeToUnixNs(tmp), offset).weekday;
        *dt         = tmp;
        return p;
    }
    
    DateTime DateTimeFromUnixNs(u64 unix_ns, i32 utc_offset_seconds) {
        i64 total_sec = (i64)(unix_ns / (u64)NS_PER_SEC);
        u32 nanos     = (u32)(unix_ns % (u64)NS_PER_SEC);
    DateTime DateTimeAddNs(DateTime dt, i64 delta_ns) {
        u64 base = DateTimeToUnixNs(dt);
        return DateTimeFromUnixNs((u64)((i64)base + delta_ns), dt.utc_offset_seconds);
    }
    
    DateTime ClockUtc(void) {
        return DateTimeFromUnixNs(ClockRealNs(), 0);
    }
        DefaultAllocatorDeinit(&alloc);
        if (ok)
            return DateTimeFromUnixNs(ns, offset);
    #endif
        return DateTimeFromUnixNs(ns, 0);
            return DateTimeFromUnixNs(ns, offset);
    #endif
        return DateTimeFromUnixNs(ns, 0);
    }
        u64              base  = 1609459200ull * 1000000000ull; // 2021-01-01T00:00:00Z
    
        DateTime utc = DateTimeFromUnixNs(base, 0);
        StrClear(&s);
        StrAppendFmt(&s, "{}", utc);
        ok = ok && ZstrCompare(StrBegin(&s), "2021-01-01T00:00:00Z") == 0;
    
        DateTime ist = DateTimeFromUnixNs(base, 19800); // +05:30
        StrClear(&s);
        StrAppendFmt(&s, "{}", ist);
        ok = ok && ZstrCompare(StrBegin(&s), "2021-01-01T05:30:00+05:30") == 0;
    
        DateTime neg = DateTimeFromUnixNs(base, -34200); // -09:30
        StrClear(&s);
        StrAppendFmt(&s, "{}", neg);
        ok = ok && ZstrCompare(StrBegin(&s), "2020-12-31T14:30:00-09:30") == 0;
    
        DateTime frac = DateTimeFromUnixNs(base + 123456789ull, 0);
        StrClear(&s);
        StrAppendFmt(&s, "{}", frac);
        for (u32 s = 0; s < sizeof(samples) / sizeof(samples[0]); ++s) {
            for (u32 o = 0; o < sizeof(offsets) / sizeof(offsets[0]); ++o) {
                DateTime d = DateTimeFromUnixNs(samples[s], offsets[o]);
                if (DateTimeToUnixNs(d) != samples[s]) {
                    return false;
    
    static bool test_compare(void) {
        DateTime a = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0);
        DateTime b = DateTimeFromUnixNs((T_2021 + 1) * NS_PER_SEC, 0);
        // Same instant rendered in two zones compares equal.
    static bool test_compare(void) {
        DateTime a = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0);
        DateTime b = DateTimeFromUnixNs((T_2021 + 1) * NS_PER_SEC, 0);
        // Same instant rendered in two zones compares equal.
        DateTime c = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, IST);
        DateTime b = DateTimeFromUnixNs((T_2021 + 1) * NS_PER_SEC, 0);
        // Same instant rendered in two zones compares equal.
        DateTime c = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, IST);
        return DateTimeCompare(a, b) == -1 && DateTimeCompare(b, a) == 1 && DateTimeCompare(a, c) == 0;
    }
    
    static bool test_diff(void) {
        DateTime a = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0);
        DateTime b = DateTimeFromUnixNs((T_2021 + 90) * NS_PER_SEC, 0);
        return DateTimeDiffNs(b, a) == 90ll * (i64)NS_PER_SEC && DateTimeDiffNs(a, b) == -90ll * (i64)NS_PER_SEC;
    static bool test_diff(void) {
        DateTime a = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0);
        DateTime b = DateTimeFromUnixNs((T_2021 + 90) * NS_PER_SEC, 0);
        return DateTimeDiffNs(b, a) == 90ll * (i64)NS_PER_SEC && DateTimeDiffNs(a, b) == -90ll * (i64)NS_PER_SEC;
    }
    
    static bool test_add(void) {
        DateTime a = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, IST);
        DateTime b = DateTimeAddNs(a, 86400ll * (i64)NS_PER_SEC); // +1 day
        return b.day == 2 && b.month == 1 && b.year == 2021 && b.utc_offset_seconds == IST &&
            for (u32 m = 1; m <= 12; ++m) {
                DateTime d = {.year = years[yi], .month = (u8)m, .day = 15, .hour = 13, .minute = 7, .second = 5};
                DateTime r = DateTimeFromUnixNs(DateTimeToUnixNs(d), 0);
                if (r.year != years[yi] || r.month != (u8)m || r.day != 15 || r.hour != 13 || r.minute != 7 ||
                    r.second != 5) {
    static bool test_leap_day_roundtrip(void) {
        DateTime feb29 = {.year = 2024, .month = 2, .day = 29, .hour = 23, .minute = 59, .second = 59};
        DateTime r     = DateTimeFromUnixNs(DateTimeToUnixNs(feb29), 0);
        return r.year == 2024 && r.month == 2 && r.day == 29 && r.hour == 23 && r.minute == 59 && r.second == 59;
    }
        // 1970-01-01 Thu(4), 2021-01-01 Fri(5), 2000-01-01 Sat(6), 2024-02-29
        // Thu(4), 2023-01-01 Sun(0) (the wd==0 case pins the `wd < 0` guard).
        return DateTimeFromUnixNs(0, 0).weekday == 4 && DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0).weekday == 5 &&
               DateTimeFromUnixNs(946684800ull * NS_PER_SEC, 0).weekday == 6 &&
               DateTimeFromUnixNs(1709164800ull * NS_PER_SEC, 0).weekday == 4 &&
        // Thu(4), 2023-01-01 Sun(0) (the wd==0 case pins the `wd < 0` guard).
        return DateTimeFromUnixNs(0, 0).weekday == 4 && DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0).weekday == 5 &&
               DateTimeFromUnixNs(946684800ull * NS_PER_SEC, 0).weekday == 6 &&
               DateTimeFromUnixNs(1709164800ull * NS_PER_SEC, 0).weekday == 4 &&
               DateTimeFromUnixNs(1672531200ull * NS_PER_SEC, 0).weekday == 0;
        return DateTimeFromUnixNs(0, 0).weekday == 4 && DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0).weekday == 5 &&
               DateTimeFromUnixNs(946684800ull * NS_PER_SEC, 0).weekday == 6 &&
               DateTimeFromUnixNs(1709164800ull * NS_PER_SEC, 0).weekday == 4 &&
               DateTimeFromUnixNs(1672531200ull * NS_PER_SEC, 0).weekday == 0;
    }
               DateTimeFromUnixNs(946684800ull * NS_PER_SEC, 0).weekday == 6 &&
               DateTimeFromUnixNs(1709164800ull * NS_PER_SEC, 0).weekday == 4 &&
               DateTimeFromUnixNs(1672531200ull * NS_PER_SEC, 0).weekday == 0;
    }
            DateTime jan1  = {.year = y, .month = 1, .day = 1};
            DateTime dec31 = {.year = y, .month = 12, .day = 31};
            DateTime rj    = DateTimeFromUnixNs(DateTimeToUnixNs(jan1), 0);
            DateTime rd    = DateTimeFromUnixNs(DateTimeToUnixNs(dec31), 0);
            if (rj.year != y || rj.month != 1 || rj.day != 1) {
            DateTime dec31 = {.year = y, .month = 12, .day = 31};
            DateTime rj    = DateTimeFromUnixNs(DateTimeToUnixNs(jan1), 0);
            DateTime rd    = DateTimeFromUnixNs(DateTimeToUnixNs(dec31), 0);
            if (rj.year != y || rj.month != 1 || rj.day != 1) {
                return false;
        };
        for (u32 i = 0; i < sizeof(exact) / sizeof(exact[0]); ++i) {
            DateTime r = DateTimeFromUnixNs(DateTimeToUnixNs(exact[i]), 0);
            if (r.year != exact[i].year || r.month != exact[i].month || r.day != exact[i].day) {
                return false;
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              s     = StrInit(&alloc);
        DateTime         d     = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0);
        StrAppendFmt(&s, "{}", d);
        bool ok = ZstrCompare(StrBegin(&s), "2021-01-01T00:00:00Z") == 0;
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              s     = StrInit(&alloc);
        DateTime         d     = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, IST);
        StrAppendFmt(&s, "{}", d);
        bool ok = ZstrCompare(StrBegin(&s), "2021-01-01T05:30:00+05:30") == 0;
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              s     = StrInit(&alloc);
        DateTime         d     = DateTimeFromUnixNs(T_2021 * NS_PER_SEC + 123456789ull, 0);
        StrAppendFmt(&s, "{}", d);
        bool ok = ZstrCompare(StrBegin(&s), "2021-01-01T00:00:00.123456789Z") == 0;
        DefaultAllocator alloc = DefaultAllocatorInit();
        Str              s     = StrInit(&alloc);
        DateTime         a     = DateTimeFromUnixNs(T_2021 * NS_PER_SEC + 123456789ull, MST);
        StrAppendFmt(&s, "{}", a);
    
    static bool test_epoch_zero(void) {
        DateTime d = DateTimeFromUnixNs(0, 0);
        return d.year == 1970 && d.month == 1 && d.day == 1 && d.hour == 0 && d.minute == 0 && d.second == 0 &&
               d.weekday == 4 /* Thursday */ && d.nanosecond == 0 && d.utc_offset_seconds == 0;
    
    static bool test_known_utc_instant(void) {
        DateTime d = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, 0);
        return d.year == 2021 && d.month == 1 && d.day == 1 && d.hour == 0 && d.minute == 0 && d.second == 0 &&
               d.weekday == 5 /* Friday */;
    
    static bool test_offset_shifts_wall_fields(void) {
        DateTime d = DateTimeFromUnixNs(T_2021 * NS_PER_SEC, IST_OFFSET);
        return d.year == 2021 && d.month == 1 && d.day == 1 && d.hour == 5 && d.minute == 30 && d.second == 0 &&
               d.weekday == 5 && d.utc_offset_seconds == IST_OFFSET;
    
    static bool test_subsecond_preserved(void) {
        DateTime d = DateTimeFromUnixNs(T_2021 * NS_PER_SEC + 123456789ull, 0);
        return d.second == 0 && d.nanosecond == 123456789;
    }
Last updated on