A basic datetime module in zig
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

zig 0.16 #1

open opened by dryfish.tngl.sh targeting trunk from 0.16
  • std.Io
  • fn format
  • juicy main
Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:rtby3a2iy6ms2sgpw7jx64hw/sh.tangled.repo.pull/3mkrtvguuei22
+83 -40
Diff #0
+3 -2
build.zig.zon
··· 1 1 .{ 2 2 .name = .datetime, 3 3 .fingerprint = 0x93f3c6ca32d93f18, 4 - .version = "0.0.3", 5 - .minimum_zig_version = "0.15.2", 4 + .version = "0.0.6", 5 + .minimum_zig_version = "0.16.0", 6 6 .paths = .{ 7 7 "build.zig", 8 + "build.zig.zon",
+41 -12
src/datetime.zig
··· 88 88 return self._format(DefaultFormat, writer); 89 89 } 90 90 91 + pub fn formatNumber(self: Self, writer: *std.Io.Writer, options: anytype) std.Io.Writer.Error!void { 92 + _ = options; 93 + return writer.print("{d}", .{self.toTimestamp()}); 94 + } 95 + 91 96 /// To format as a timestamp. 92 97 /// Usage: std.fmt.alt(yourTimestamp, .timestampFormatter) 93 98 pub fn timestampFormatter(self: Self, writer: *std.Io.Writer) std.Io.Writer.Error!void { 94 99 return writer.print("{d}", .{self.toTimestamp()}); 95 100 } 96 101 102 + const Formatter = struct { 103 + dtval: Self, 104 + fmt: []const u8, 105 + pub inline fn format(self: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { 106 + try self.dtval._format(self.fmt, writer); 107 + } 108 + }; 109 + 110 + pub fn formatter(self: Self, fmt: []const u8) Formatter { 111 + return .{ .dtval = self, .fmt = fmt }; 112 + } 113 + 97 114 /// Formatting using our own simple format string. 98 115 fn _format(self: Self, fmt: []const u8, writer: *std.Io.Writer) std.Io.Writer.Error!void { 99 116 for (fmt) |c| { 117 + switch (c) { 118 + 'Y' => try writer.print("{d:0>4}", .{self.year}), 119 + 'm' => try writer.print("{d:0>2}", .{@intFromEnum(self.month)}), 120 + 'b' => try writer.print("{t}", .{self.month}), 121 + 'd' => try writer.print("{d:0>2}", .{self.day}), 122 + 'H' => try writer.print("{d:0>2}", .{self.hour}), 123 + 'M' => try writer.print("{d:0>2}", .{self.minute}), 100 124 101 125 102 126 127 + } 128 + } 103 129 130 + const NanoMultiplier: i128 = 1000000000; 104 131 132 + /// Parsed now. 133 + pub fn now(io: std.Io) Self { 134 + const timestamp = std.Io.Timestamp.now(io, .real); 135 + return fromTimestamp(@intCast(@divFloor(timestamp.nanoseconds, NanoMultiplier))); 136 + } 105 137 106 - 107 - 108 - 109 - 110 - 111 - 112 - 113 - 114 - 115 - 116 - 117 - 138 + /// Fairly simple conversion of seconds since epoch into parsed datetime. 118 139 119 140 120 141 ··· 258 279 259 280 try std.testing.expectEqualStrings("1737478323", try std.fmt.bufPrint(&buf, "{d}", .{a1})); 260 281 } 282 + 283 + test formatter { 284 + const a1 = fromTimestamp(1737478323); 285 + var buf: [128]u8 = undefined; 286 + var writer: std.Io.Writer = .fixed(&buf); 287 + try writer.print("{f}", .{a1.formatter("Y H S")}); 288 + try std.testing.expectEqualStrings("2025 16 03", writer.buffered()); 289 + }
+14 -13
src/date.zig
··· 2 2 const datetime = @import("datetime"); 3 3 const zoneinfo = @import("zoneinfo"); 4 4 5 - pub fn main() !void { 6 - var mem: [65535]u8 = undefined; 7 - var fba = std.heap.FixedBufferAllocator.init(&mem); 8 - const allocator = fba.allocator(); 5 + const NanoMultiplier: i128 = 1000000000; 6 + 7 + pub fn main(init: std.process.Init) !void { 8 + const gpa = init.gpa; 9 + const io = init.io; 10 + const args = try init.minimal.args.toSlice(init.arena.allocator()); 11 + 9 12 var jsonOutput: bool = false; 10 13 11 - { 12 - const args = try std.process.argsAlloc(allocator); 13 - defer std.process.argsFree(allocator, args); 14 - if (args.len > 1 and std.mem.eql(u8, args[1], "--json")) 15 - jsonOutput = true; 16 - } 14 + if (args.len > 1 and std.mem.eql(u8, args[1], "--json")) 15 + jsonOutput = true; 17 16 18 17 var buf: [128]u8 = undefined; 19 - var stdout_writer = std.fs.File.stdout().writer(&buf); 18 + var stdout_writer = std.Io.File.stdout().writer(io, &buf); 20 19 const stdout = &stdout_writer.interface; 21 - const tz: ?zoneinfo = zoneinfo.loadTz(allocator) catch null; 22 - var timestamp = std.time.timestamp(); 20 + var tz: ?zoneinfo = zoneinfo.loadTz(gpa, io, init.environ_map) catch null; 21 + defer if (tz != null) tz.?.deinit(); 22 + const realTimestamp = std.Io.Timestamp.now(io, .real); 23 + var timestamp: i64 = @intCast(@divFloor(realTimestamp.nanoseconds, NanoMultiplier)); 23 24 var name: []const u8 = ""; 24 25 25 26 if (tz) |_| {
+25 -13
src/zoneinfo.zig
··· 2 2 3 3 const Self = @This(); 4 4 5 - allocator: std.mem.Allocator, 5 + gpa: std.mem.Allocator, 6 6 tz: std.tz.Tz, 7 7 8 8 /// Load timezone data. 9 - pub fn loadTz(allocator: std.mem.Allocator) !Self { 10 - if (std.posix.getenv("TZ")) |tzname| { 11 - var dir = try std.fs.openDirAbsolute("/usr/share/zoneinfo", .{ .access_sub_paths = true }); 12 - defer dir.close(); 13 - var tzfile = try dir.openFile(tzname, .{}); 14 - defer tzfile.close(); 15 - return .{ .allocator = allocator, .tz = try std.tz.Tz.parse(allocator, tzfile.deprecatedReader()) }; 9 + pub fn loadTz(gpa: std.mem.Allocator, io: std.Io, environ_map: ?*std.process.Environ.Map) !Self { 10 + if (environ_map) |e| { 11 + if (e.get("TZ")) |tzname| { 12 + var dir = try std.Io.Dir.openDirAbsolute(io, "/usr/share/zoneinfo", .{ .access_sub_paths = true }); 13 + defer dir.close(io); 14 + var tzfile = try dir.openFile(io, tzname, .{}); 15 + defer tzfile.close(io); 16 + var buf: [256]u8 = undefined; 17 + var reader = tzfile.reader(io, &buf); 18 + const tz = try std.tz.Tz.parse(gpa, &reader.interface); 19 + return .{ .gpa = gpa, .tz = tz }; 20 + } 16 21 } 17 22 18 - var cwd = std.fs.cwd(); 19 - var tzfile = try cwd.openFile("/etc/localtime", .{}); 20 - defer tzfile.close(); 21 - return .{ .allocator = allocator, .tz = try std.tz.Tz.parse(allocator, tzfile.deprecatedReader()) }; 23 + var cwd = std.Io.Dir.cwd(); 24 + var tzfile = try cwd.openFile(io, "/etc/localtime", .{}); 25 + defer tzfile.close(io); 26 + var buf: [256]u8 = undefined; 27 + var reader = tzfile.reader(io, &buf); 28 + const tz = try std.tz.Tz.parse(gpa, &reader.interface); 29 + return .{ .gpa = gpa, .tz = tz }; 30 + } 31 + 32 + pub fn deinit(self: *Self) void { 33 + self.tz.deinit(); 22 34 } 23 35 24 36 pub fn getOffset(self: Self, timestamp: i64) ?*std.tz.Timetype { ··· 34 46 test loadTz { 35 47 const epoch = std.time.timestamp(); 36 48 std.debug.assert(epoch > 0); 37 - const tz_ = try loadTz(std.testing.allocator); 49 + const tz_ = try loadTz(std.testing.gpa, std.testing.io, null); 38 50 var tz = tz_.tz; 39 51 defer tz.deinit(); 40 52 if (tz.footer) |footer| {

History

1 round 0 comments
sign up or login to add to the discussion
dryfish.tngl.sh submitted #0
3 commits
expand
datetime: any formatter
datetime: b for abbreviated month
zig 0.16
merge conflicts detected
expand
  • build.zig.zon:1
  • src/datetime.zig:88
expand 0 comments