Something went wrong. Try again.
Development fork of jetzig-framework
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245const Time = @This();
const std = @import("std");const Allocator = std.mem.Allocator;const Stringify = std.json.Stringify;
const datetime = @import("root.zig");const Error = datetime.Error;const Parser = @import("Parser.zig");const utils = @import("utils.zig");const t = utils.testing;const test_time = utils.test_time;const TestStruct = utils.TestStruct;const Format = datetime.Format;
hour: u8,min: u8,sec: u8,micros: u32,
pub fn init(hour: u8, min: u8, sec: u8, micros: u32) !Time { if (!valid(hour, min, sec, micros)) return Error.InvalidTime;
return .{ .hour = hour, .min = min, .sec = sec, .micros = micros, };}
pub fn valid(hour: u8, min: u8, sec: u8, micros: u32) bool { if (hour > 23) { return false; }
if (min > 59) { return false; }
if (sec > 59) { return false; }
if (micros > 999999) { return false; }
return true;}
pub fn parse(fmt: Format, input: []const u8) !Time { var parser = Parser.init(input); const time = switch (fmt) { .rfc3339 => try parser.time(), .iso8601 => return Error.NotImplemented, };
if (parser.unconsumed() != 0) return error.InvalidTime; return time;}
pub fn order(a: Time, b: Time) std.math.Order { const hour_order = std.math.order(a.hour, b.hour); if (hour_order != .eq) return hour_order;
const min_order = std.math.order(a.min, b.min); if (min_order != .eq) return min_order;
const sec_order = std.math.order(a.sec, b.sec); if (sec_order != .eq) return sec_order;
return std.math.order(a.micros, b.micros);}
pub fn format(self: Time, writer: *std.Io.Writer) !void { var buf: [15]u8 = undefined; const n = utils.writeTime(&buf, self); try writer.writeAll(buf[0..n]);}
pub fn jsonStringify(self: Time, out: anytype) !void { // Our goal here isn't to validate the time. It's to write what we have // in a hh:mm:ss.sss format. If the data in Time isn't valid, that's not // our problem and we don't guarantee any reasonable output in such cases. var buf: [17]u8 = undefined; const n = utils.writeTime(buf[1..16], self); buf[0] = '"'; buf[n + 1] = '"'; try out.print("{s}", .{buf[0 .. n + 2]});}
pub fn jsonParse(allocator: Allocator, source: anytype, options: anytype) !Time { _ = options;
switch (try source.nextAlloc(allocator, .alloc_if_needed)) { inline .string, .allocated_string => |str| return parse(.rfc3339, str) catch return error.InvalidCharacter, else => return error.UnexpectedToken, }}
test "Time: json" { { // time no fraction const time = Time{ .hour = 23, .min = 59, .sec = 2, .micros = 0 }; const out = try Stringify.valueAlloc(t.allocator, time, .{}); defer t.allocator.free(out); try t.expectEqual("\"23:59:02\"", out); }
{ // time, milliseconds only const time = Time{ .hour = 7, .min = 9, .sec = 32, .micros = 202000 }; const out = try Stringify.valueAlloc(t.allocator, time, .{}); defer t.allocator.free(out); try t.expectEqual("\"07:09:32.202\"", out); }
{ // time, micros const time = Time{ .hour = 1, .min = 2, .sec = 3, .micros = 123456 }; const out = try Stringify.valueAlloc(t.allocator, time, .{}); defer t.allocator.free(out); try t.expectEqual("\"01:02:03.123456\"", out); }
{ // parse const ts = try std.json.parseFromSlice(TestStruct, t.allocator, "{\"time\":\"01:02:03.123456\"}", .{}); defer ts.deinit(); try t.expectEqual(Time{ .hour = 1, .min = 2, .sec = 3, .micros = 123456 }, ts.value.time.?); }}
test "Time: format" { { var buf: [20]u8 = undefined; const out = try std.fmt.bufPrint(&buf, "{f}", .{Time{ .hour = 23, .min = 59, .sec = 59, .micros = 0 }}); try t.expectEqual("23:59:59", out); }
{ var buf: [20]u8 = undefined; const out = try std.fmt.bufPrint(&buf, "{f}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 12 }}); try t.expectEqual("08:09:10.000012", out); }
{ var buf: [20]u8 = undefined; const out = try std.fmt.bufPrint(&buf, "{f}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 123 }}); try t.expectEqual("08:09:10.000123", out); }
{ var buf: [20]u8 = undefined; const out = try std.fmt.bufPrint(&buf, "{f}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 1234 }}); try t.expectEqual("08:09:10.001234", out); }
{ var buf: [20]u8 = undefined; const out = try std.fmt.bufPrint(&buf, "{f}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 12345 }}); try t.expectEqual("08:09:10.012345", out); }
{ var buf: [20]u8 = undefined; const out = try std.fmt.bufPrint(&buf, "{f}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 123456 }}); try t.expectEqual("08:09:10.123456", out); }}
test "Time: parse" { for ([_]test_time{ //valid .init(.{ .hour = 9, .min = 8, .sec = 5, .micros = 123000 }, try .parse(.rfc3339, "09:08:05.123")), .init(.{ .hour = 23, .min = 59, .sec = 59, .micros = 0 }, try .parse(.rfc3339, "23:59:59")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 0 }, try .parse(.rfc3339, "00:00:00")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 0 }, try .parse(.rfc3339, "00:00:00.0")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 1 }, try .parse(.rfc3339, "00:00:00.000001")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 12 }, try .parse(.rfc3339, "00:00:00.000012")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 123 }, try .parse(.rfc3339, "00:00:00.000123")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 1234 }, try .parse(.rfc3339, "00:00:00.001234")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 12345 }, try .parse(.rfc3339, "00:00:00.012345")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 123456 }, try .parse(.rfc3339, "00:00:00.123456")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 123456 }, try .parse(.rfc3339, "00:00:00.1234567")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 123456 }, try .parse(.rfc3339, "00:00:00.12345678")), .init(.{ .hour = 0, .min = 0, .sec = 0, .micros = 123456 }, try .parse(.rfc3339, "00:00:00.123456789")), .init(.{ .hour = 9, .min = 8, .sec = 0, .micros = 0 }, try .parse(.rfc3339, "09:08")), }) |tm| try t.expectEqual(tm.expected, tm.actual); for ([_][]const u8{ "", "01:00:", "1:00:00", "10:1:00", "10:11:4", "10:20:30.", "10:20:30.a", "10:20:30.1234567899", "10:20:30.123Z", "24:00:00", "00:60:00", "00:00:60", "0a:00:00", "00:0a:00", "00:00:0a", "00/00:00", "00:00 00", "2023-10-10T", "2023-10-10T01:00:", "2023-10-10T1:00:00", "2023-10-10T10:1:00", "2023-10-10T10:11:4", "2023-10-10T10:20:30.", "2023-10-10T10:20:30.1234567899", "2023-10-10T24:00:00", "2023-10-10T00:60:00", "2023-10-10T00:00:60", "2023-10-10T0a:00:00", "2023-10-10T00:0a:00", "2023-10-10T00:00:0a", "2023-10-10T00/00:00", }) |string| try t.expectError(Error.InvalidTime, parse(.rfc3339, string));}
test "Time: order" { { const a: Time = .{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; const b: Time = .{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; try t.expectEqual(.eq, a.order(b)); }
{ const a: Time = .{ .hour = 20, .min = 17, .sec = 22, .micros = 101002 }; const b: Time = .{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; try t.expectEqual(.gt, a.order(b)); try t.expectEqual(.lt, b.order(a)); }
{ const a: Time = .{ .hour = 19, .min = 18, .sec = 22, .micros = 101002 }; const b: Time = .{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; try t.expectEqual(.gt, a.order(b)); try t.expectEqual(.lt, b.order(a)); }
{ const a: Time = .{ .hour = 19, .min = 17, .sec = 23, .micros = 101002 }; const b: Time = .{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; try t.expectEqual(.gt, a.order(b)); try t.expectEqual(.lt, b.order(a)); }
{ const a: Time = .{ .hour = 19, .min = 17, .sec = 22, .micros = 101003 }; const b: Time = .{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; try t.expectEqual(.gt, a.order(b)); try t.expectEqual(.lt, b.order(a)); }}