You can not generate a code for a specific time. Currently only UTC is supported.
103 lines
3.2 KiB
Zig
103 lines
3.2 KiB
Zig
const std = @import("std");
|
|
|
|
const expect = std.testing.expect;
|
|
const expectEqualStrings = std.testing.expectEqualStrings;
|
|
const expectEqual = std.testing.expectEqual;
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
pub const TimeError = error{ParsingError};
|
|
|
|
pub const Time = struct {
|
|
/// expecting a date in the format yyyy-MM-dd'T'HH:mm:ss
|
|
/// returning a unix timestamp
|
|
/// does not handle leap seconds
|
|
/// only handles UTC
|
|
pub fn parseIso8601(data: []const u8) !i64 {
|
|
const format = "nnnn-nn-nnTnn:nn:nn";
|
|
// 0123456789012345678
|
|
|
|
// validate the format
|
|
if (data.len != 19) {
|
|
return TimeError.ParsingError;
|
|
}
|
|
|
|
for (format, 0..) |formatChar, index| {
|
|
if (index >= data.len) {
|
|
return TimeError.ParsingError;
|
|
}
|
|
|
|
const c = data[index];
|
|
switch (formatChar) {
|
|
'n' => {
|
|
if (!isDigit(c)) return TimeError.ParsingError;
|
|
},
|
|
else => {
|
|
if (formatChar != c) return TimeError.ParsingError;
|
|
},
|
|
}
|
|
}
|
|
|
|
const year = try std.fmt.parseInt(i64, data[0..4], 10);
|
|
const month = try std.fmt.parseInt(i64, data[5..7], 10);
|
|
const day = try std.fmt.parseInt(i64, data[8..10], 10);
|
|
const hour = try std.fmt.parseInt(i64, data[11..13], 10);
|
|
const minute = try std.fmt.parseInt(i64, data[14..16], 10);
|
|
const second = try std.fmt.parseInt(i64, data[17..19], 10);
|
|
|
|
const unixTime: i64 = (year - 1970) * 365 * 24 * 3600 //
|
|
+ leapDays(year, month) * 24 * 3600 //
|
|
+ dayInYear(month, day) * 24 * 3600 //
|
|
+ hour * 3600 //
|
|
+ minute * 60 //
|
|
+ second;
|
|
|
|
return unixTime;
|
|
}
|
|
|
|
fn isDigit(byte: u8) bool {
|
|
return byte >= '0' and byte <= '9';
|
|
}
|
|
|
|
fn dayInYear(month: i64, day: i64) i64 {
|
|
const daysPerMonth = [_]u8{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
|
var result: i64 = 0;
|
|
var i: u8 = 0;
|
|
while (i < (month - 1)) : (i += 1) {
|
|
result += daysPerMonth[i];
|
|
}
|
|
result += day - 1;
|
|
return result;
|
|
}
|
|
fn leapDays(year: i64, month: i64) i64 {
|
|
var i: u64 = 1972;
|
|
var result: i64 = 0;
|
|
while (i < year) : (i += 1) {
|
|
if (@mod(i, 4) == 0 and (i % 100 != 0 or @mod(i, 400) == 0)) {
|
|
result += 1;
|
|
}
|
|
}
|
|
if (month > 2 and @mod(year, 4) == 0 and (@mod(year, 100) != 0 or @mod(year, 400) == 0)) {
|
|
result += 1;
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
test "parsing error 'x025-01-01T00:00:00'" {
|
|
try std.testing.expectError(TimeError.ParsingError, Time.parseIso8601("x025-01-01T00:00:00"));
|
|
}
|
|
|
|
test "parsing error '2025-01-01'" {
|
|
try std.testing.expectError(TimeError.ParsingError, Time.parseIso8601("2025-01-01T"));
|
|
}
|
|
|
|
//test "parsing validation successfull" {
|
|
// const y = try Time.parseIso8601("2025-12-13T01:02:03");
|
|
// try expectEqual(12, y);
|
|
//}
|
|
|
|
test "parse 2025-02-18T18:37:45, expecting 1739903865" {
|
|
const unixTime = try Time.parseIso8601("2025-02-18T18:37:45");
|
|
try expectEqual(1739903865, unixTime);
|
|
}
|