From 54251ea1165f18737671d75aa51c5060e6cc3229 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Tue, 13 Jun 2023 20:01:34 -0400 Subject: [PATCH] Add custom format functions to print as ISO-8601 datetime --- src/main.zig | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/timezone.zig | 28 ++++++++++++++++++++++++++++ src/year.zig | 17 +++++++++++++++++ 3 files changed, 90 insertions(+) diff --git a/src/main.zig b/src/main.zig index e524042..ffe0607 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,5 +1,6 @@ const std = @import("std"); const debug = std.debug; +const mem = std.mem; const testing = std.testing; pub const Year = @import("year.zig").Year; pub const Month = @import("month.zig").Month; @@ -181,6 +182,30 @@ pub const DateTime = struct { const b = other.toTimestamp(); return if (a > b) .gt else if (a < b) .lt else .eq; } + + pub fn format( + self: Self, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = fmt; + _ = options; + + try writer.print("{s}-{d:0>2}-{d:0>2}", .{ + self.year, @enumToInt(self.month), self.day, + }); + if (self.hour) |h| { + try writer.print("T{d:0>2}", .{h}); + if (self.minute) |m| { + try writer.print(":{d:0>2}", .{m}); + if (self.second) |s| { + try writer.print(":{d:0>2}", .{s}); + } + } + } + try writer.print("{s}", .{self.tz}); + } }; test "new year" { @@ -402,3 +427,23 @@ test "ordering gt" { try testing.expectEqual(a.compare(b), .gt); debug.print("Passed\n", .{}); } + +test "custom fmt" { + const dt = DateTime{ + .year = Year.new(2023), + .month = .june, + .day = 10, + .hour = 6, + .minute = 21, + .second = 22, + .tz = .utc, + }; + const dt_string = try std.fmt.allocPrint( + testing.allocator, + "{s}", + .{dt}, + ); + defer testing.allocator.free(dt_string); + try testing.expect(mem.eql(u8, dt_string, "2023-06-10T06:21:22Z")); + debug.print("Passed\n", .{}); +} diff --git a/src/timezone.zig b/src/timezone.zig index 939e47b..a83b4c8 100644 --- a/src/timezone.zig +++ b/src/timezone.zig @@ -72,4 +72,32 @@ pub const TimeZone = union(TimeZoneTag) { } } else if (minutes) |m| Self{ .offset = Offset.new(0, m).? } else .utc; } + + pub fn format( + self: Self, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = fmt; + _ = options; + + switch (self) { + .utc => try writer.writeAll("Z"), + .offset => |ofs| switch (ofs) { + .positive => |p| { + try writer.print("+{d:0>2}", .{p.hours}); + if (p.minutes) |m| { + try writer.print(":{d:0>2}", .{m}); + } + }, + .negative => |n| { + try writer.print("-{d:0>2}", .{n.hours}); + if (n.minutes) |m| { + try writer.print(":{d:0>2}", .{m}); + } + }, + }, + } + } }; diff --git a/src/year.zig b/src/year.zig index 1faa7d5..1d8ea9f 100644 --- a/src/year.zig +++ b/src/year.zig @@ -50,4 +50,21 @@ pub const Year = union(YearTag) { pub fn previous(self: Self) Self { return Self.new(self.get() - 1); } + + pub fn format( + self: Self, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = fmt; + _ = options; + + const year = self.get(); + if (year > 0) { + try writer.print("{d:0>4}", .{@intCast(u32, year)}); + } else { + try writer.print("{d:0>4}", .{year}); + } + } };