DateTime
Description
A broken-down calendar instant. Plain value type – copy and discard freely; there is no Init/Deinit.
year : Proleptic Gregorian year (e.g. 2026). month : 1..12. day : 1..31. hour : 0..23. minute : 0..59. second : 0..60 (60 only across a leap second). weekday : 0=Sunday .. 6=Saturday. nanosecond : 0..999999999. utc_offset_seconds : Offset of this rendering from UTC, east-positive (0 for a UTC instant; +19800 for IST).
Usage example (Cross-references)
Usage examples (Cross-references)
- In
DateTime.h:47:
u32 nanosecond;
i32 utc_offset_seconds;
} DateTime;
///
- In
DateTime.h:63:
/// TAGS: Std, DateTime, Convert
///
DateTime DateTimeFromUnixNs(u64 unix_ns, i32 utc_offset_seconds);
///
- In
DateTime.h:78:
/// TAGS: Std, DateTime, Convert
///
u64 DateTimeToUnixNs(DateTime dt);
///
- In
DateTime.h:90:
/// TAGS: Std, DateTime, Compare
///
i32 DateTimeCompare(DateTime a, DateTime b);
///
- In
DateTime.h:100:
/// TAGS: Std, DateTime, Compare
///
i64 DateTimeDiffNs(DateTime a, DateTime b);
///
- In
DateTime.h:111:
/// TAGS: Std, DateTime, Arithmetic
///
DateTime DateTimeAddNs(DateTime dt, i64 delta_ns);
///
- In
DateTime.h:142:
/// TAGS: Std, DateTime, Calendar
///
u16 DateTimeYearDay(DateTime dt);
#endif // MISRA_STD_DATETIME_H
- In
Io.h:17:
#include <Misra/Std/Container.h>
#include <Misra/Std/Container/Buf.h>
#include <Misra/Std/DateTime.h>
#include <Misra/Std/Zstr.h>
#include <Misra/Std/File.h>- In
Io.h:302:
Str: TO_TYPE_SPECIFIC_IO(Str, &(x)), \
Buf: TO_TYPE_SPECIFIC_IO(Buf, &(x)), \
DateTime: TO_TYPE_SPECIFIC_IO(DateTime, &(x)), \
IOFMT_FLOAT_CASE_(x, &(x)) IOFMT_INT_CASE_(x, &(x)) IOFMT_BITVEC_CASE_(x, &(x)) IOFMT_USER_CASE_(x, &(x)) \
Zstr: TO_TYPE_SPECIFIC_IO(Zstr, &(x)), \
- In
Io.h:328:
Str: TO_TYPE_SPECIFIC_IO(Str, (void *)&(x)), \
Buf: TO_TYPE_SPECIFIC_IO(Buf, (void *)&(x)), \
DateTime: TO_TYPE_SPECIFIC_IO(DateTime, (void *)&(x)), \
IOFMT_FLOAT_CASE_(x, (void *)&(x)) IOFMT_INT_CASE_(x, (void *)&(x)) IOFMT_BITVEC_CASE_(x, (void *)&(x)) \
IOFMT_USER_CASE_(x, (void *)&(x)) Zstr: TO_TYPE_SPECIFIC_IO(Zstr, (void *)&(x)), \
- In
Io.h:738:
bool _write_Str(Str *o, FmtInfo *fmt_info, Str *s);
bool _write_Buf(Str *o, FmtInfo *fmt_info, Buf *b);
bool _write_DateTime(Str *o, FmtInfo *fmt_info, DateTime *dt);
bool _write_u8(Str *o, FmtInfo *fmt_info, u8 *v);
bool _write_u16(Str *o, FmtInfo *fmt_info, u16 *v);- In
Io.h:763:
Zstr _read_Str(Zstr i, FmtInfo *fmt_info, Str *s);
Zstr _read_Buf(Zstr i, FmtInfo *fmt_info, Buf *b);
Zstr _read_DateTime(Zstr i, FmtInfo *fmt_info, DateTime *dt);
Zstr _read_u8(Zstr i, FmtInfo *fmt_info, u8 *v);
Zstr _read_u16(Zstr i, FmtInfo *fmt_info, u16 *v);- In
Clock.h:20:
#define MISRA_SYS_CLOCK_H
#include <Misra/Std/DateTime.h>
#include <Misra/Types.h>- In
Clock.h:104:
/// TAGS: Sys, Clock, Time, Calendar, Utc
///
DateTime ClockUtc(void);
///
- In
Clock.h:120:
/// TAGS: Sys, Clock, Time, Calendar, Local, Timezone
///
DateTime ClockLocal(void);
#endif // MISRA_SYS_CLOCK_H
- In
Io.c:1665:
// fraction is exactly the nanosecond count, so it parses back as a plain
// integer. Writer and reader share the layout, so a value round-trips.
bool _write_DateTime(Str *o, FmtInfo *fmt_info, DateTime *dt) {
(void)fmt_info;
if (!o || !dt) {- In
Io.c:1698:
}
Zstr _read_DateTime(Zstr i, FmtInfo *fmt_info, DateTime *dt) {
(void)fmt_info;
if (!i || !dt) {- In
Io.c:1737:
}
DateTime tmp;
tmp.year = year;
tmp.month = (u8)mon;- In
DateTime.c:10:
/// tables and no branches.
#include <Misra/Std/DateTime.h>
#define NS_PER_SEC 1000000000ll- In
DateTime.c:39:
}
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);- In
DateTime.c:60:
wd += 7;
DateTime dt;
dt.year = year;
dt.month = (u8)month;- In
DateTime.c:73:
}
u64 DateTimeToUnixNs(DateTime dt) {
i64 days = days_from_civil(dt.year, dt.month, dt.day);
i64 local_sec = days * SECS_PER_DAY + (i64)dt.hour * 3600 + (i64)dt.minute * 60 + (i64)dt.second;- In
DateTime.c:80:
}
i32 DateTimeCompare(DateTime a, DateTime b) {
u64 ua = DateTimeToUnixNs(a);
u64 ub = DateTimeToUnixNs(b);- In
DateTime.c:90:
}
i64 DateTimeDiffNs(DateTime a, DateTime b) {
return (i64)DateTimeToUnixNs(a) - (i64)DateTimeToUnixNs(b);
}- In
DateTime.c:94:
}
DateTime DateTimeAddNs(DateTime dt, i64 delta_ns) {
u64 base = DateTimeToUnixNs(dt);
return DateTimeFromUnixNs((u64)((i64)base + delta_ns), dt.utc_offset_seconds);- In
DateTime.c:112:
}
u16 DateTimeYearDay(DateTime dt) {
i64 today = days_from_civil(dt.year, dt.month, dt.day);
i64 jan1 = days_from_civil(dt.year, 1, 1);- In
Clock.c:104:
}
DateTime ClockUtc(void) {
return DateTimeFromUnixNs(ClockRealNs(), 0);
}- In
Clock.c:108:
}
DateTime ClockLocal(void) {
u64 ns = ClockRealNs();
#if FEATURE_FILE- In
Io.Write.c:913:
u64 base = 1609459200ull * 1000000000ull; // 2021-01-01T00:00:00Z
DateTime utc = DateTimeFromUnixNs(base, 0);
StrClear(&s);
StrAppendFmt(&s, "{}", utc);- In
Io.Write.c:918:
ok = ok && ZstrCompare(StrBegin(&s), "2021-01-01T00:00:00Z") == 0;
DateTime ist = DateTimeFromUnixNs(base, 19800); // +05:30
StrClear(&s);
StrAppendFmt(&s, "{}", ist);- In
Io.Write.c:923:
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);- In
Io.Write.c:928:
ok = ok && ZstrCompare(StrBegin(&s), "2020-12-31T14:30:00-09:30") == 0;
DateTime frac = DateTimeFromUnixNs(base + 123456789ull, 0);
StrClear(&s);
StrAppendFmt(&s, "{}", frac);- In
Io.Read.c:1993:
{
Zstr in = "2021-01-01T00:00:00Z";
DateTime d = {0};
StrReadFmt(in, "{}", d);
ok = ok && d.year == 2021 && d.month == 1 && d.day == 1 && d.hour == 0 && d.minute == 0 && d.second == 0 &&- In
Io.Read.c:2000:
{
Zstr in = "2021-01-01T05:30:00+05:30";
DateTime d = {0};
StrReadFmt(in, "{}", d);
ok = ok && d.year == 2021 && d.hour == 5 && d.minute == 30 && d.utc_offset_seconds == 19800;- In
Io.Read.c:2006:
{
Zstr in = "2020-12-31T14:30:00-09:30";
DateTime d = {0};
StrReadFmt(in, "{}", d);
ok = ok && d.year == 2020 && d.month == 12 && d.day == 31 && d.hour == 14 && d.minute == 30 &&- In
Io.Read.c:2013:
{
Zstr in = "2021-01-01T00:00:00.123456789Z";
DateTime d = {0};
StrReadFmt(in, "{}", d);
ok = ok && d.nanosecond == 123456789 && d.utc_offset_seconds == 0;- In
DateTime.c:3:
#include <Misra.h>
#include <Misra/Std/Allocator/Default.h>
#include <Misra/Std/DateTime.h>
#include <Misra/Std/Io.h>- In
DateTime.c:19:
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;- In
DateTime.c:29:
static bool test_to_unix_known(void) {
DateTime epoch = {.year = 1970, .month = 1, .day = 1};
DateTime day1 = {.year = 1970, .month = 1, .day = 2};
return DateTimeToUnixNs(epoch) == 0 && DateTimeToUnixNs(day1) == 86400ull * NS_PER_SEC;- In
DateTime.c:30:
static bool test_to_unix_known(void) {
DateTime epoch = {.year = 1970, .month = 1, .day = 1};
DateTime day1 = {.year = 1970, .month = 1, .day = 2};
return DateTimeToUnixNs(epoch) == 0 && DateTimeToUnixNs(day1) == 86400ull * NS_PER_SEC;
}- In
DateTime.c:35:
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.
- In
DateTime.c:36:
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);- In
DateTime.c:38:
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;
}- In
DateTime.c:43:
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;- In
DateTime.c:44:
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;
}- In
DateTime.c:49:
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 &&- In
DateTime.c:50:
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 &&
DateTimeDiffNs(b, a) == 86400ll * (i64)NS_PER_SEC;- In
DateTime.c:68:
static bool test_year_day(void) {
DateTime jan1 = {.year = 2024, .month = 1, .day = 1};
DateTime mar1 = {.year = 2024, .month = 3, .day = 1}; // leap: 31+29+1
DateTime dec31l = {.year = 2024, .month = 12, .day = 31};- In
DateTime.c:69:
static bool test_year_day(void) {
DateTime jan1 = {.year = 2024, .month = 1, .day = 1};
DateTime mar1 = {.year = 2024, .month = 3, .day = 1}; // leap: 31+29+1
DateTime dec31l = {.year = 2024, .month = 12, .day = 31};
DateTime dec31 = {.year = 2023, .month = 12, .day = 31};- In
DateTime.c:70:
DateTime jan1 = {.year = 2024, .month = 1, .day = 1};
DateTime mar1 = {.year = 2024, .month = 3, .day = 1}; // leap: 31+29+1
DateTime dec31l = {.year = 2024, .month = 12, .day = 31};
DateTime dec31 = {.year = 2023, .month = 12, .day = 31};
return DateTimeYearDay(jan1) == 1 && DateTimeYearDay(mar1) == 61 && DateTimeYearDay(dec31l) == 366 &&- In
DateTime.c:71:
DateTime mar1 = {.year = 2024, .month = 3, .day = 1}; // leap: 31+29+1
DateTime dec31l = {.year = 2024, .month = 12, .day = 31};
DateTime dec31 = {.year = 2023, .month = 12, .day = 31};
return DateTimeYearDay(jan1) == 1 && DateTimeYearDay(mar1) == 61 && DateTimeYearDay(dec31l) == 366 &&
DateTimeYearDay(dec31) == 365;- In
DateTime.c:83:
for (u32 yi = 0; yi < sizeof(years) / sizeof(years[0]); ++yi) {
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 ||- In
DateTime.c:84:
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) {- In
DateTime.c:95:
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;- In
DateTime.c:96:
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;
}- In
DateTime.c:115:
static bool test_year_boundaries_sweep(void) {
for (i32 y = 1970; y <= 2550; ++y) {
DateTime jan1 = {.year = y, .month = 1, .day = 1};
DateTime dec31 = {.year = y, .month = 12, .day = 31};
DateTime rj = DateTimeFromUnixNs(DateTimeToUnixNs(jan1), 0);- In
DateTime.c:116:
for (i32 y = 1970; y <= 2550; ++y) {
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);- In
DateTime.c:117:
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) {- In
DateTime.c:118:
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;- In
DateTime.c:128:
// Exact century / 400-cycle leap boundaries (the era's last day,
// doe==146096, and the leap Feb 29s) pin the remaining correction term.
DateTime exact[] = {
{.year = 2000, .month = 2, .day = 29},
{.year = 2100, .month = 2, .day = 28},- In
DateTime.c:135:
};
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;- In
DateTime.c:147:
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;- In
DateTime.c:158:
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;- In
DateTime.c:169:
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;- In
DateTime.c:181:
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);
DateTime a = DateTimeFromUnixNs(T_2021 * NS_PER_SEC + 123456789ull, MST);
StrAppendFmt(&s, "{}", a);- In
DateTime.c:184:
StrAppendFmt(&s, "{}", a);
DateTime b = {0};
Zstr p = StrBegin(&s);
StrReadFmt(p, "{}", b);- In
DateTime.c:198:
static bool test_iso_read_direct(void) {
Zstr in = "2026-06-26T17:34:11-07:00";
DateTime d = {0};
StrReadFmt(in, "{}", d);
return d.year == 2026 && d.month == 6 && d.day == 26 && d.hour == 17 && d.minute == 34 && d.second == 11 &&- In
DateTime.c:224:
test_iso_read_direct,
};
return run_test_suite(tests, sizeof(tests) / sizeof(tests[0]), NULL, 0, "DateTime");
}- In
Clock.c:26:
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;- In
Clock.c:32:
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 */;- In
Clock.c:38:
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;- In
Clock.c:44:
static bool test_subsecond_preserved(void) {
DateTime d = DateTimeFromUnixNs(T_2021 * NS_PER_SEC + 123456789ull, 0);
return d.second == 0 && d.nanosecond == 123456789;
}- In
Clock.c:49:
static bool test_clock_utc_is_utc(void) {
DateTime d = ClockUtc();
return d.utc_offset_seconds == 0 && d.year >= 2024 && d.month >= 1 && d.month <= 12;
}- In
Clock.c:56:
// timezone resolves (it falls back to UTC, offset 0).
static bool test_clock_local_sane(void) {
DateTime d = ClockLocal();
return d.year >= 2024 && d.month >= 1 && d.month <= 12 && d.day >= 1 && d.day <= 31 && d.hour <= 23 &&
d.minute <= 59;
Last updated on