- std.Io
- fn format
- juicy main
+83
-40
Diff
round #0
+3
-2
build.zig.zon
+3
-2
build.zig.zon
+41
-12
src/datetime.zig
+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
+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
+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| {