0

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

3
  • 1
    I am not able to find such functionality in docs. I searched in namespace time and tz. Commented Apr 18 at 8:40
  • I have searched alot too, my last resort was using claude, but it too wasn't able to crack it, Commented Apr 18 at 12:10
  • This zig-time library can provide this feature, if you don't want to add this dependency just explore how they do it. Commented Apr 19 at 12:06

1 Answer 1

1

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:

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.