Split off timezone
module
This commit is contained in:
parent
2578b0f4fa
commit
8ab36acb45
217
src/main.zig
217
src/main.zig
@ -3,154 +3,14 @@ const debug = std.debug;
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
pub const Year = @import("year.zig").Year;
|
pub const Year = @import("year.zig").Year;
|
||||||
pub const Month = @import("month.zig").Month;
|
pub const Month = @import("month.zig").Month;
|
||||||
|
pub const tz = @import("timezone.zig");
|
||||||
|
pub const Offset = tz.Offset;
|
||||||
|
pub const TimeZone = tz.TimeZone;
|
||||||
|
|
||||||
pub const SECONDS_PER_MINUTE = 60;
|
pub const SECONDS_PER_MINUTE = 60;
|
||||||
pub const SECONDS_PER_HOUR = 60 * 60;
|
pub const SECONDS_PER_HOUR = 60 * 60;
|
||||||
pub const SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
|
pub const SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
|
||||||
|
|
||||||
pub const TimeZoneTag = enum(u1) {
|
|
||||||
utc,
|
|
||||||
offset,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Sign = enum(u1) {
|
|
||||||
positive,
|
|
||||||
negative,
|
|
||||||
};
|
|
||||||
|
|
||||||
const HoursMinutes = struct {
|
|
||||||
hours: u4,
|
|
||||||
minutes: ?u6,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Offset = union(Sign) {
|
|
||||||
positive: HoursMinutes,
|
|
||||||
negative: HoursMinutes,
|
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
fn new(hours: i8, minutes: ?u6) ?Self {
|
|
||||||
if (hours > 12 or hours < -12) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (minutes) |m| {
|
|
||||||
if (m > 59) return null;
|
|
||||||
if (hours == 0 and m == 0) return null;
|
|
||||||
} else if (hours == 0) return null;
|
|
||||||
if (hours < 0) {
|
|
||||||
const h = @intCast(u4, @as(i8, hours) * -1);
|
|
||||||
return Self{ .negative = .{ .hours = h, .minutes = minutes } };
|
|
||||||
} else {
|
|
||||||
return Self{ .positive = .{ .hours = @intCast(u4, hours), .minutes = minutes } };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn asSeconds(self: Self) i64 {
|
|
||||||
return switch (self) {
|
|
||||||
.positive => |ofs| blk: {
|
|
||||||
var seconds = @as(i64, ofs.hours) * 3600;
|
|
||||||
if (ofs.minutes) |m| seconds += (@as(i64, m) * 60);
|
|
||||||
break :blk seconds;
|
|
||||||
},
|
|
||||||
.negative => |ofs| blk: {
|
|
||||||
var seconds = @as(i64, ofs.hours) * 3600;
|
|
||||||
if (ofs.minutes) |m| seconds += (@as(i64, m) * 60);
|
|
||||||
break :blk seconds * -1;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
test "new year" {
|
|
||||||
try testing.expectEqual(Year.new(2023), Year{ .normal = 2023 });
|
|
||||||
try testing.expectEqual(Year.new(2024), Year{ .leap = 2024 });
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "get year" {
|
|
||||||
try testing.expectEqual(Year.new(2023).get(), 2023);
|
|
||||||
try testing.expectEqual(Year.new(2024).get(), 2024);
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "next year" {
|
|
||||||
try testing.expectEqual(Year.new(2023).next(), Year{ .leap = 2024 });
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "last year" {
|
|
||||||
try testing.expectEqual(Year.new(2024).previous(), Year{ .normal = 2023 });
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "get days in month" {
|
|
||||||
const year = Year.new(2023);
|
|
||||||
const month = Month.february;
|
|
||||||
try testing.expectEqual(month.days(year), 28);
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "next month" {
|
|
||||||
try testing.expectEqual(Month.june.next(), .july);
|
|
||||||
try testing.expectEqual(Month.december.next(), null);
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "last month" {
|
|
||||||
try testing.expectEqual(Month.june.previous(), .may);
|
|
||||||
try testing.expectEqual(Month.january.previous(), null);
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "new offsets" {
|
|
||||||
try testing.expectEqual(Offset.new(-5, null), Offset{ .negative = .{ .hours = 5, .minutes = null } });
|
|
||||||
try testing.expectEqual(Offset.new(3, null), Offset{ .positive = .{ .hours = 3, .minutes = null } });
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "as seconds" {
|
|
||||||
try testing.expectEqual(Offset.new(-4, 30).?.asSeconds(), -16200);
|
|
||||||
try testing.expectEqual(Offset.new(3, null).?.asSeconds(), 10800);
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const TimeZone = union(TimeZoneTag) {
|
|
||||||
utc: void,
|
|
||||||
offset: Offset,
|
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
pub fn new(hours: ?i8, minutes: ?u6) ?Self {
|
|
||||||
return if (hours) |h| blk: {
|
|
||||||
if (h == 0) {
|
|
||||||
break :blk .utc;
|
|
||||||
} else if (Offset.new(h, minutes)) |ofs| {
|
|
||||||
break :blk Self{ .offset = ofs };
|
|
||||||
} else {
|
|
||||||
break :blk null;
|
|
||||||
}
|
|
||||||
} else if (minutes) |m| Self{ .offset = Offset.new(0, m).? } else .utc;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
test "new timezone" {
|
|
||||||
const tz = TimeZone.new(-5, null).?;
|
|
||||||
try testing.expectEqual(@as(TimeZoneTag, tz), .offset);
|
|
||||||
switch (tz) {
|
|
||||||
.offset => |ofs| try testing.expectEqual(ofs, Offset{ .negative = .{ .hours = 5, .minutes = null } }),
|
|
||||||
else => unreachable,
|
|
||||||
}
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
test "new timezone utc" {
|
|
||||||
const tz0 = TimeZone.new(null, null).?;
|
|
||||||
const tz1 = TimeZone.new(0, null).?;
|
|
||||||
try testing.expectEqual(@as(TimeZoneTag, tz0), .utc);
|
|
||||||
try testing.expectEqual(@as(TimeZoneTag, tz1), .utc);
|
|
||||||
debug.print("Passed\n", .{});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const WeekDay = enum(u3) {
|
pub const WeekDay = enum(u3) {
|
||||||
thursday = 0,
|
thursday = 0,
|
||||||
friday,
|
friday,
|
||||||
@ -323,6 +183,77 @@ pub const DateTime = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test "new year" {
|
||||||
|
try testing.expectEqual(Year.new(2023), Year{ .normal = 2023 });
|
||||||
|
try testing.expectEqual(Year.new(2024), Year{ .leap = 2024 });
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "get year" {
|
||||||
|
try testing.expectEqual(Year.new(2023).get(), 2023);
|
||||||
|
try testing.expectEqual(Year.new(2024).get(), 2024);
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "next year" {
|
||||||
|
try testing.expectEqual(Year.new(2023).next(), Year{ .leap = 2024 });
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "last year" {
|
||||||
|
try testing.expectEqual(Year.new(2024).previous(), Year{ .normal = 2023 });
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "get days in month" {
|
||||||
|
const year = Year.new(2023);
|
||||||
|
const month = Month.february;
|
||||||
|
try testing.expectEqual(month.days(year), 28);
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "next month" {
|
||||||
|
try testing.expectEqual(Month.june.next(), .july);
|
||||||
|
try testing.expectEqual(Month.december.next(), null);
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "last month" {
|
||||||
|
try testing.expectEqual(Month.june.previous(), .may);
|
||||||
|
try testing.expectEqual(Month.january.previous(), null);
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "new offsets" {
|
||||||
|
try testing.expectEqual(Offset.new(-5, null), Offset{ .negative = .{ .hours = 5, .minutes = null } });
|
||||||
|
try testing.expectEqual(Offset.new(3, null), Offset{ .positive = .{ .hours = 3, .minutes = null } });
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "as seconds" {
|
||||||
|
try testing.expectEqual(Offset.new(-4, 30).?.asSeconds(), -16200);
|
||||||
|
try testing.expectEqual(Offset.new(3, null).?.asSeconds(), 10800);
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "new timezone" {
|
||||||
|
const zone = TimeZone.new(-5, null).?;
|
||||||
|
try testing.expectEqual(@as(tz.TimeZoneTag, zone), .offset);
|
||||||
|
switch (zone) {
|
||||||
|
.offset => |ofs| try testing.expectEqual(ofs, Offset{ .negative = .{ .hours = 5, .minutes = null } }),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
test "new timezone utc" {
|
||||||
|
const tz0 = TimeZone.new(null, null).?;
|
||||||
|
const tz1 = TimeZone.new(0, null).?;
|
||||||
|
try testing.expectEqual(@as(tz.TimeZoneTag, tz0), .utc);
|
||||||
|
try testing.expectEqual(@as(tz.TimeZoneTag, tz1), .utc);
|
||||||
|
debug.print("Passed\n", .{});
|
||||||
|
}
|
||||||
|
|
||||||
test "get year" {
|
test "get year" {
|
||||||
const dt = DateTime{
|
const dt = DateTime{
|
||||||
.year = Year.new(2023),
|
.year = Year.new(2023),
|
||||||
|
75
src/timezone.zig
Normal file
75
src/timezone.zig
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const debug = std.debug;
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
pub const TimeZoneTag = enum(u1) {
|
||||||
|
utc,
|
||||||
|
offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Sign = enum(u1) {
|
||||||
|
positive,
|
||||||
|
negative,
|
||||||
|
};
|
||||||
|
|
||||||
|
const HoursMinutes = struct {
|
||||||
|
hours: u4,
|
||||||
|
minutes: ?u6,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Offset = union(Sign) {
|
||||||
|
positive: HoursMinutes,
|
||||||
|
negative: HoursMinutes,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn new(hours: i8, minutes: ?u6) ?Self {
|
||||||
|
if (hours > 12 or hours < -12) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (minutes) |m| {
|
||||||
|
if (m > 59) return null;
|
||||||
|
if (hours == 0 and m == 0) return null;
|
||||||
|
} else if (hours == 0) return null;
|
||||||
|
if (hours < 0) {
|
||||||
|
const h = @intCast(u4, @as(i8, hours) * -1);
|
||||||
|
return Self{ .negative = .{ .hours = h, .minutes = minutes } };
|
||||||
|
} else {
|
||||||
|
return Self{ .positive = .{ .hours = @intCast(u4, hours), .minutes = minutes } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn asSeconds(self: Self) i64 {
|
||||||
|
return switch (self) {
|
||||||
|
.positive => |ofs| blk: {
|
||||||
|
var seconds = @as(i64, ofs.hours) * 3600;
|
||||||
|
if (ofs.minutes) |m| seconds += (@as(i64, m) * 60);
|
||||||
|
break :blk seconds;
|
||||||
|
},
|
||||||
|
.negative => |ofs| blk: {
|
||||||
|
var seconds = @as(i64, ofs.hours) * 3600;
|
||||||
|
if (ofs.minutes) |m| seconds += (@as(i64, m) * 60);
|
||||||
|
break :blk seconds * -1;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const TimeZone = union(TimeZoneTag) {
|
||||||
|
utc: void,
|
||||||
|
offset: Offset,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn new(hours: ?i8, minutes: ?u6) ?Self {
|
||||||
|
return if (hours) |h| blk: {
|
||||||
|
if (h == 0) {
|
||||||
|
break :blk .utc;
|
||||||
|
} else if (Offset.new(h, minutes)) |ofs| {
|
||||||
|
break :blk Self{ .offset = ofs };
|
||||||
|
} else {
|
||||||
|
break :blk null;
|
||||||
|
}
|
||||||
|
} else if (minutes) |m| Self{ .offset = Offset.new(0, m).? } else .utc;
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user