mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Add std.fmt.formatDuration and std.fmt.duration (#7297)
`formatDuration` works on a writer, and `duration` wraps a u64 to allow pleasant injection into format strings.
This commit is contained in:
parent
025f1559a0
commit
fc10c9c4ce
1 changed files with 97 additions and 0 deletions
|
|
@ -1119,6 +1119,103 @@ pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, uppercase: bool, op
|
|||
return fbs.pos;
|
||||
}
|
||||
|
||||
/// Formats a number of nanoseconds according to its magnitude:
|
||||
///
|
||||
/// - #ns
|
||||
/// - [#y][#w][#d][#h][#m]#[.###][u|m]s
|
||||
pub fn formatDuration(ns: u64, writer: anytype) !void {
|
||||
var ns_remaining = ns;
|
||||
inline for (.{
|
||||
.{ .ns = 365 * std.time.ns_per_day, .sep = 'y' },
|
||||
.{ .ns = std.time.ns_per_week, .sep = 'w' },
|
||||
.{ .ns = std.time.ns_per_day, .sep = 'd' },
|
||||
.{ .ns = std.time.ns_per_hour, .sep = 'h' },
|
||||
.{ .ns = std.time.ns_per_min, .sep = 'm' },
|
||||
}) |unit| {
|
||||
if (ns_remaining >= unit.ns) {
|
||||
const units = ns_remaining / unit.ns;
|
||||
try formatInt(units, 10, false, .{}, writer);
|
||||
try writer.writeByte(unit.sep);
|
||||
ns_remaining -= units * unit.ns;
|
||||
if (ns_remaining == 0) return;
|
||||
}
|
||||
}
|
||||
|
||||
inline for (.{
|
||||
.{ .ns = std.time.ns_per_s, .sep = "s" },
|
||||
.{ .ns = std.time.ns_per_ms, .sep = "ms" },
|
||||
.{ .ns = std.time.ns_per_us, .sep = "us" },
|
||||
}) |unit| {
|
||||
const kunits = ns_remaining * 1000 / unit.ns;
|
||||
if (kunits >= 1000) {
|
||||
try formatInt(kunits / 1000, 10, false, .{}, writer);
|
||||
if (kunits > 1000) {
|
||||
// Write up to 3 decimal places
|
||||
const frac = kunits % 1000;
|
||||
var buf = [_]u8{ '.', 0, 0, 0 };
|
||||
_ = formatIntBuf(buf[1..], frac, 10, false, .{ .fill = '0', .width = 3 });
|
||||
var end: usize = 4;
|
||||
while (end > 1) : (end -= 1) {
|
||||
if (buf[end - 1] != '0') break;
|
||||
}
|
||||
try writer.writeAll(buf[0..end]);
|
||||
}
|
||||
try writer.writeAll(unit.sep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try formatInt(ns, 10, false, .{}, writer);
|
||||
try writer.writeAll("ns");
|
||||
return;
|
||||
}
|
||||
|
||||
test "formatDuration" {
|
||||
var buf: [24]u8 = undefined;
|
||||
inline for (.{
|
||||
.{ .s = "0ns", .d = 0 },
|
||||
.{ .s = "1ns", .d = 1 },
|
||||
.{ .s = "999ns", .d = std.time.ns_per_us - 1 },
|
||||
.{ .s = "1us", .d = std.time.ns_per_us },
|
||||
.{ .s = "1.45us", .d = 1450 },
|
||||
.{ .s = "1.5us", .d = 3 * std.time.ns_per_us / 2 },
|
||||
.{ .s = "999.999us", .d = std.time.ns_per_ms - 1 },
|
||||
.{ .s = "1ms", .d = std.time.ns_per_ms + 1 },
|
||||
.{ .s = "1.5ms", .d = 3 * std.time.ns_per_ms / 2 },
|
||||
.{ .s = "999.999ms", .d = std.time.ns_per_s - 1 },
|
||||
.{ .s = "1s", .d = std.time.ns_per_s },
|
||||
.{ .s = "59.999s", .d = std.time.ns_per_min - 1 },
|
||||
.{ .s = "1m", .d = std.time.ns_per_min },
|
||||
.{ .s = "1h", .d = std.time.ns_per_hour },
|
||||
.{ .s = "1d", .d = std.time.ns_per_day },
|
||||
.{ .s = "1w", .d = std.time.ns_per_week },
|
||||
.{ .s = "1y", .d = 365 * std.time.ns_per_day },
|
||||
.{ .s = "1y52w23h59m59.999s", .d = 730 * std.time.ns_per_day - 1 }, // 365d = 52w1d
|
||||
.{ .s = "1y1h1.001s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + std.time.ns_per_ms },
|
||||
.{ .s = "1y1h1s", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_s + 999 * std.time.ns_per_us },
|
||||
.{ .s = "1y1h999.999us", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms - 1 },
|
||||
.{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms },
|
||||
.{ .s = "1y1h1ms", .d = 365 * std.time.ns_per_day + std.time.ns_per_hour + std.time.ns_per_ms + 1 },
|
||||
}) |tc| {
|
||||
const slice = try bufPrint(&buf, "{}", .{duration(tc.d)});
|
||||
std.testing.expectEqualStrings(tc.s, slice);
|
||||
}
|
||||
}
|
||||
|
||||
/// Wraps a `u64` to format with `formatDuration`.
|
||||
const Duration = struct {
|
||||
ns: u64,
|
||||
|
||||
pub fn format(self: Duration, comptime fmt: []const u8, options: FormatOptions, writer: anytype) !void {
|
||||
return formatDuration(self.ns, writer);
|
||||
}
|
||||
};
|
||||
|
||||
/// Formats a number of nanoseconds according to its magnitude. See `formatDuration`.
|
||||
pub fn duration(ns: u64) Duration {
|
||||
return Duration{ .ns = ns };
|
||||
}
|
||||
|
||||
pub const ParseIntError = error{
|
||||
/// The result cannot fit in the type specified
|
||||
Overflow,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue