using zig, I need to generate a timestamp that format exactly or almost matches 2025-04-18T14:03:52.000Z
. How can I go about it? using the standard library only
It is possible to do this, but I would strongly suggest using a library like zig-time
, zig-datetime
or zig-tzif
instead.
Also please note that this is one of my first Zig programs, so it might not adhere to all conventions and best practices.
That said, here is how I would do it using the standard library only:
const std = @import("std");
const DateTime = struct {
year: u32,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
millisecond: u16,
};
fn isLeapYear(year: u32) bool {
return (@rem(year, 4) == 0 and @rem(year, 100) != 0) or (@rem(year, 400) == 0);
}
fn daysInMonth(month: u8, year: u32) u8 {
return switch (month) {
1 => 31,
2 => if (isLeapYear(year)) 29 else 28,
3 => 31,
4 => 30,
5 => 31,
6 => 30,
7 => 31,
8 => 31,
9 => 30,
10 => 31,
11 => 30,
12 => 31,
else => unreachable,
};
}
fn unixTimestampToUTC(timestamp: u64) DateTime {
const MILLIS_PER_SEC = 1000;
const SECS_PER_MIN = 60;
const SECS_PER_HOUR = SECS_PER_MIN * 60;
const SECS_PER_DAY = SECS_PER_HOUR * 24;
const millisecond: u16 = @intCast(@rem(timestamp, MILLIS_PER_SEC));
const seconds = @divTrunc(timestamp, MILLIS_PER_SEC);
// Compute the time of day.
const hour: u8 = @intCast(@divTrunc(@rem(seconds, SECS_PER_DAY), SECS_PER_HOUR));
const minute: u8 = @intCast(@divTrunc(@rem(seconds, SECS_PER_HOUR), SECS_PER_MIN));
const second: u8 = @intCast(@rem(seconds, SECS_PER_MIN));
// Compute the date.
var days = @divTrunc(seconds, SECS_PER_DAY);
var year: u32 = 1970;
while (true) {
const days_in_year: u16 = if (isLeapYear(year)) 366 else 365;
if (days >= days_in_year) {
days -= days_in_year;
year += 1;
} else break;
}
var month: u8 = 1;
while (true) {
const day_of_month = daysInMonth(month, year);
if (days >= day_of_month) {
days -= day_of_month;
month += 1;
} else break;
}
const day: u8 = @intCast(days + 1);
return DateTime{
.year = year,
.month = month,
.day = day,
.hour = hour,
.minute = minute,
.second = second,
.millisecond = millisecond,
};
}
pub fn main() !void {
const allocator = std.heap.page_allocator;
const stdout = std.io.getStdOut().writer();
// Timestamps before 01-01-1970 are not supported by this program.
const timestamp: u64 = @intCast(std.time.milliTimestamp());
const dt = unixTimestampToUTC(timestamp);
const iso8601 = try std.fmt.allocPrint(
allocator,
"{}-{:0>2}-{:0>2}T{:0>2}:{:0>2}:{:0>2}.{:0>3}Z",
.{ dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.millisecond },
);
defer allocator.free(iso8601);
try stdout.print("ISO 8601 UTC: {s}\n", .{iso8601});
}
Which gives you an output like:
ISO 8601 UTC: 2025-04-23T17:07:17.668Z
Currently this code comes with several caveats that all could be fixed, but I did not attempt this for the sake of brevity: