Initial commit
This commit is contained in:
commit
2029bf3778
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
zig-out/
|
||||||
|
zig-cache/
|
||||||
|
tags
|
||||||
|
tags.temp
|
||||||
|
tags.lock
|
17
build.zig
Normal file
17
build.zig
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn build(b: *std.build.Builder) void {
|
||||||
|
// Standard release options allow the person running `zig build` to select
|
||||||
|
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||||
|
const mode = b.standardReleaseOptions();
|
||||||
|
|
||||||
|
const lib = b.addStaticLibrary("zigDateTime", "src/main.zig");
|
||||||
|
lib.setBuildMode(mode);
|
||||||
|
lib.install();
|
||||||
|
|
||||||
|
const main_tests = b.addTest("src/main.zig");
|
||||||
|
main_tests.setBuildMode(mode);
|
||||||
|
|
||||||
|
const test_step = b.step("test", "Run library tests");
|
||||||
|
test_step.dependOn(&main_tests.step);
|
||||||
|
}
|
223
src/main.zig
Normal file
223
src/main.zig
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
pub const SECONDS_PER_MINUTE = 60;
|
||||||
|
pub const SECONDS_PER_HOUR = 60 * 60;
|
||||||
|
pub const SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
|
||||||
|
|
||||||
|
pub const YearTag = enum(u1) {
|
||||||
|
normal,
|
||||||
|
leap,
|
||||||
|
|
||||||
|
fn new(year: u31) YearTag {
|
||||||
|
return if (year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)) .leap else .normal;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Year = union(YearTag) {
|
||||||
|
normal: u31,
|
||||||
|
leap: u31,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn new(year: u31) Self {
|
||||||
|
return switch (YearTag.new(year)) {
|
||||||
|
.normal => Self{ .normal = year },
|
||||||
|
.leap => Self{ .leap = year },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn days(self: Self) u16 {
|
||||||
|
return switch (self) {
|
||||||
|
.normal => 365,
|
||||||
|
.leap => 366,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seconds(self: Self) i64 {
|
||||||
|
return self.days * SECONDS_PER_DAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: Self) u31 {
|
||||||
|
return switch (self) {
|
||||||
|
.normal => |year| year,
|
||||||
|
.leap => |year| year,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(self: Self) Self {
|
||||||
|
return Self.new(self.get() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn previous(self: Self) Self {
|
||||||
|
return Self.new(self.get() - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "new year" {
|
||||||
|
try testing.expectEqual(Year.new(2023), Year{ .normal = 2023 });
|
||||||
|
try testing.expectEqual(Year.new(2024), Year{ .leap = 2024 });
|
||||||
|
}
|
||||||
|
|
||||||
|
test "get year" {
|
||||||
|
try testing.expectEqual(Year.new(2023).get(), 2023);
|
||||||
|
try testing.expectEqual(Year.new(2024).get(), 2024);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "next year" {
|
||||||
|
try testing.expectEqual(Year.new(2023).next(), Year{ .leap = 2024 });
|
||||||
|
}
|
||||||
|
|
||||||
|
test "last year" {
|
||||||
|
try testing.expectEqual(Year.new(2024).previous(), Year{ .normal = 2023 });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Month = enum(u4) {
|
||||||
|
january = 1,
|
||||||
|
february = 2,
|
||||||
|
march = 3,
|
||||||
|
april = 4,
|
||||||
|
may = 5,
|
||||||
|
june = 6,
|
||||||
|
july = 7,
|
||||||
|
august = 8,
|
||||||
|
september = 9,
|
||||||
|
october = 10,
|
||||||
|
november = 11,
|
||||||
|
december = 12,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn days(self: Self, year: Year) u5 {
|
||||||
|
return switch (@enumToInt(self)) {
|
||||||
|
1, 3, 5, 7, 8, 10, 12 => 31,
|
||||||
|
2 => switch (year) {
|
||||||
|
.normal => 28,
|
||||||
|
.leap => 29,
|
||||||
|
},
|
||||||
|
else => 30,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn seconds(self: Self) u32 {
|
||||||
|
return self.days() * SECONDS_PER_DAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next(self: Self) ?Self {
|
||||||
|
const num = @enumToInt(self);
|
||||||
|
return if (num < 12) @intToEnum(Self, num + 1) else null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn previous(self: Self) ?Self {
|
||||||
|
const num = @enumToInt(self);
|
||||||
|
return if (num > 1) @intToEnum(Self, num - 1) else null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "get days in month" {
|
||||||
|
const year = Year.new(2023);
|
||||||
|
const month = Month.february;
|
||||||
|
try testing.expectEqual(month.days(year), 28);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "next month" {
|
||||||
|
try testing.expectEqual(Month.june.next(), .july);
|
||||||
|
try testing.expectEqual(Month.december.next(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "last month" {
|
||||||
|
try testing.expectEqual(Month.june.previous(), .may);
|
||||||
|
try testing.expectEqual(Month.january.previous(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TimeZoneTag = enum(u1) {
|
||||||
|
utc,
|
||||||
|
offset,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const TimeZone = union(TimeZoneTag) {
|
||||||
|
utc: void,
|
||||||
|
offset: i8,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn new(offset: ?i8) ?Self {
|
||||||
|
return if (offset) |ofs| blk: {
|
||||||
|
if (ofs < -12 or ofs > 12) {
|
||||||
|
break :blk null;
|
||||||
|
} else if (ofs == 0) {
|
||||||
|
break :blk .utc;
|
||||||
|
} else {
|
||||||
|
break :blk Self{ .offset = ofs };
|
||||||
|
}
|
||||||
|
} else .utc;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "new timezone" {
|
||||||
|
const tz = TimeZone.new(-5).?;
|
||||||
|
try testing.expectEqual(@as(TimeZoneTag, tz), .offset);
|
||||||
|
switch (tz) {
|
||||||
|
.offset => |ofs| try testing.expectEqual(ofs, -5),
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test "new timezone utc" {
|
||||||
|
const tz0 = TimeZone.new(null).?;
|
||||||
|
const tz1 = TimeZone.new(0).?;
|
||||||
|
try testing.expectEqual(@as(TimeZoneTag, tz0), .utc);
|
||||||
|
try testing.expectEqual(@as(TimeZoneTag, tz1), .utc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DateTime = struct {
|
||||||
|
year: Year,
|
||||||
|
month: Month,
|
||||||
|
day: u8,
|
||||||
|
hour: ?u5,
|
||||||
|
minute: ?u6,
|
||||||
|
second: ?u6,
|
||||||
|
nanos: ?u32,
|
||||||
|
tz: TimeZone,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn getYear(self: Self) u32 {
|
||||||
|
return self.year.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getOffset(self: Self) ?i8 {
|
||||||
|
return switch (self.tz) {
|
||||||
|
.utc => null,
|
||||||
|
.offset => |ofs| ofs,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "get year" {
|
||||||
|
const dt = DateTime{
|
||||||
|
.year = Year.new(2023),
|
||||||
|
.month = .june,
|
||||||
|
.day = 12,
|
||||||
|
.hour = 1,
|
||||||
|
.minute = 5,
|
||||||
|
.second = 14,
|
||||||
|
.nanos = null,
|
||||||
|
.tz = TimeZone.new(-5).?,
|
||||||
|
};
|
||||||
|
try testing.expectEqual(dt.getYear(), 2023);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "get offset" {
|
||||||
|
const dt = DateTime{
|
||||||
|
.year = Year.new(2023),
|
||||||
|
.month = .june,
|
||||||
|
.day = 12,
|
||||||
|
.hour = 1,
|
||||||
|
.minute = 5,
|
||||||
|
.second = 14,
|
||||||
|
.nanos = null,
|
||||||
|
.tz = TimeZone.new(-5).?,
|
||||||
|
};
|
||||||
|
try testing.expectEqual(dt.getOffset().?, -5);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user