authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-10-16 17:33:51 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2021-10-16 17:33:51 -07:00
log12ee22949f562288588f8fe612c3bce3b258c036
tree217771945f7f107eb69f961bea85a24487f4ffd1
parentbffffa79c54b5902086fa464b97743e7780e7b94

initial code commit


6 files changed, 379 insertions(+), 0 deletions(-)

.gitignore created+3
...@@ -0,0 +1,3 @@
1zig-*
2.zigmod
3deps.zig
build.zig created+27
...@@ -0,0 +1,27 @@
1const std = @import("std");
2
3pub fn build(b: *std.build.Builder) void {
4 // Standard target options allows the person running `zig build` to choose
5 // what target to build for. Here we do not override the defaults, which
6 // means any target is allowed, and the default is native. Other options
7 // for restricting supported target set are available.
8 const target = b.standardTargetOptions(.{});
9
10 // Standard release options allow the person running `zig build` to select
11 // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
12 const mode = b.standardReleaseOptions();
13
14 const exe = b.addExecutable("zig-time", "main.zig");
15 exe.setTarget(target);
16 exe.setBuildMode(mode);
17 exe.install();
18
19 const run_cmd = exe.run();
20 run_cmd.step.dependOn(b.getInstallStep());
21 if (b.args) |args| {
22 run_cmd.addArgs(args);
23 }
24
25 const run_step = b.step("run", "Run the app");
26 run_step.dependOn(&run_cmd.step);
27}
main.zig created+5
...@@ -0,0 +1,5 @@
1const std = @import("std");
2
3pub fn main() anyerror!void {
4 std.log.info("All your codebase are belong to us.", .{});
5}
time.zig created+335
...@@ -0,0 +1,335 @@
1const std = @import("std");
2const string = []const u8;
3const range = @import("range").range;
4
5pub const DateTime = struct {
6 ms: u16,
7 seconds: u16,
8 minutes: u16,
9 hours: u16,
10 days: u16,
11 months: u16,
12 years: u16,
13 timezone: TimeZone,
14 weekday: WeekDay,
15
16 const Self = @This();
17
18 pub fn initUnixMs(unix: u64) Self {
19 return unix_epoch.addMs(unix);
20 }
21
22 /// Caller asserts that this is > epoch
23 pub fn init(year: u16, month: u16, day: u16, hr: u16, min: u16, sec: u16) Self {
24 return unix_epoch
25 .addYears(year - unix_epoch.years)
26 .addMonths(month)
27 .addDays(day)
28 .addHours(hr)
29 .addMins(min)
30 .addSecs(sec);
31 }
32
33 pub fn now() Self {
34 return initUnixMs(@intCast(u64, std.time.milliTimestamp()));
35 }
36
37 pub const unix_epoch = Self{
38 .ms = 0,
39 .seconds = 0,
40 .minutes = 0,
41 .hours = 0,
42 .days = 0,
43 .months = 0,
44 .years = 1970,
45 .timezone = .UTC,
46 .weekday = .Thu,
47 };
48
49 pub fn addMs(self: Self, count: u64) Self {
50 if (count == 0) return self;
51 var result = self;
52 result.ms += @intCast(u16, count % 1000);
53 return result.addSecs(count / 1000);
54 }
55
56 pub fn addSecs(self: Self, count: u64) Self {
57 if (count == 0) return self;
58 var result = self;
59 result.seconds += @intCast(u16, count % 60);
60 return result.addMins(count / 60);
61 }
62
63 pub fn addMins(self: Self, count: u64) Self {
64 if (count == 0) return self;
65 var result = self;
66 result.minutes += @intCast(u16, count % 60);
67 return result.addHours(count / 60);
68 }
69
70 pub fn addHours(self: Self, count: u64) Self {
71 if (count == 0) return self;
72 var result = self;
73 result.hours += @intCast(u16, count % 24);
74 return result.addDays(count / 24);
75 }
76
77 pub fn addDays(self: Self, count: u64) Self {
78 if (count == 0) return self;
79 var result = self;
80 var input = count;
81
82 while (true) {
83 const year_len = self.daysThisYear();
84 if (input >= year_len) {
85 result.years += 1;
86 input -= year_len;
87 continue;
88 }
89 break;
90 }
91 while (true) {
92 const month_len = self.daysThisMonth();
93 if (input >= month_len) {
94 result.months += 1;
95 input -= month_len;
96
97 if (result.months == 12) {
98 result.years += 1;
99 result.months = 0;
100 }
101 continue;
102 }
103 break;
104 }
105 {
106 const month_len = self.daysThisMonth();
107 if (result.days + input > month_len) {
108 const left = month_len - result.days;
109 input -= left;
110 result.months += 1;
111 result.days = 0;
112 result.incrementWeekday(left);
113 }
114 result.days += @intCast(u16, input);
115 result.incrementWeekday(input);
116
117 if (result.months == 12) {
118 result.years += 1;
119 result.months = 0;
120 }
121 }
122
123 return result;
124 }
125
126 pub fn addMonths(self: Self, count: u64) Self {
127 if (count == 0) return self;
128 var result = self;
129 var input = count;
130 while (input > 0) {
131 const new = result.addDays(result.daysThisMonth());
132 result = new;
133 input -= 1;
134 }
135 return result;
136 }
137
138 pub fn addYears(self: Self, count: u64) Self {
139 if (count == 0) return self;
140 return self.addMonths(count * 12);
141 }
142
143 pub fn isLeapYear(self: Self) bool {
144 const y = self.years;
145 var ret = false;
146 if (y % 4 == 0) ret = true;
147 if (y % 100 == 0) ret = false;
148 if (y % 400 == 0) ret = true;
149 return ret;
150 }
151
152 pub fn daysThisYear(self: Self) u64 {
153 return if (self.isLeapYear()) 366 else 365;
154 }
155
156 pub fn daysThisMonth(self: Self) u64 {
157 const norm = [12]u64{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
158 const leap = [12]u64{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
159 const month_days = if (!self.isLeapYear()) norm else leap;
160 return month_days[self.months];
161 }
162
163 fn incrementWeekday(self: *Self, count: u64) void {
164 for (range(count % 7)) |_| {
165 self.weekday = self.weekday.next();
166 }
167 }
168
169 /// fmt is defined by https://momentjs.com/docs/#/displaying/format/
170 pub fn format(self: Self, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void {
171 _ = options;
172
173 if (fmt.len == 0) @compileError("DateTime: format string can't be empty");
174
175 _ = writer;
176 _ = self;
177
178 @setEvalBranchQuota(100000);
179
180 comptime var s = 0;
181 comptime var e = 0;
182 comptime var next: ?FormatSeq = null;
183 inline for (fmt) |c, i| {
184 e = i + 1;
185
186 if (comptime std.meta.stringToEnum(FormatSeq, fmt[s..e])) |tag| {
187 next = tag;
188 if (i < fmt.len - 1) continue;
189 }
190
191 if (next) |tag| {
192 switch (tag) {
193 .ddd => try writer.writeAll(@tagName(self.weekday)),
194 .DD => try writer.print("{:0>2}", .{self.days + 1}),
195 .YYYY => try writer.print("{:0>4}", .{self.years}),
196 .HH => try writer.print("{:0>2}", .{self.hours}),
197 .mm => try writer.print("{:0>2}", .{self.minutes}),
198 .ss => try writer.print("{:0>2}", .{self.seconds}),
199 .MM => try writer.print("{:0>2}", .{self.months}),
200 .z => try writer.writeAll(@tagName(self.timezone)),
201
202 .MMM => {
203 const names = [_]string{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
204 try writer.writeAll(names[self.months]);
205 },
206
207 else => @compileError("'" ++ @tagName(tag) ++ "' not currently supported"),
208
209 // stubs to make the parser work
210 .YYY => @compileError(comptime std.fmt.comptimePrint("'{s}' is not a valid format sequence", .{@tagName(tag)})),
211 }
212 next = null;
213 s = i;
214 }
215
216 switch (c) {
217 ',',
218 ' ',
219 ':',
220 => {
221 try writer.writeAll(&.{c});
222 s = i + 1;
223 continue;
224 },
225 else => {},
226 }
227
228 if (i < fmt.len - 1) @compileError(comptime std.fmt.comptimePrint("'{s}' is not a valid format sequence", .{fmt[s..e]}));
229 }
230 }
231
232 pub fn formatAlloc(self: Self, alloc: *std.mem.Allocator, comptime fmt: string) !string {
233 var list = std.ArrayList(u8).init(alloc);
234 defer list.deinit();
235
236 try self.format(fmt, .{}, list.writer());
237 return list.toOwnedSlice();
238 }
239
240 const FormatSeq = enum {
241 M, // 1 2 ... 11 12
242 Mo, // 1st 2nd ... 11th 12th
243 MM, // 01 02 ... 11 12
244 MMM, // Jan Feb ... Nov Dec
245 MMMM, // January February ... November December
246 Q, // 1 2 3 4
247 Qo, // 1st 2nd 3rd 4th
248 D, // 1 2 ... 30 31
249 Do, // 1st 2nd ... 30th 31st
250 DD, // 01 02 ... 30 31
251 DDD, // 1 2 ... 364 365
252 DDDo, // 1st 2nd ... 364th 365th
253 DDDD, // 001 002 ... 364 365
254 d, // 0 1 ... 5 6
255 do, // 0th 1st ... 5th 6th
256 dd, // Su Mo ... Fr Sa
257 ddd, // Sun Mon ... Fri Sat
258 dddd, // Sunday Monday ... Friday Saturday
259 e, // 0 1 ... 5 6 (locale)
260 E, // 1 2 ... 6 7 (ISO)
261 w, // 1 2 ... 52 53
262 wo, // 1st 2nd ... 52nd 53rd
263 ww, // 01 02 ... 52 53
264 W, // 1 2 ... 52 53 (ISO)
265 Wo, // 1st 2nd ... 52nd 53rd
266 WW, // 01 02 ... 52 53
267 YY, // 70 71 ... 29 30
268 YYY, // stub
269 YYYY, // 1970 1971 ... 2029 2030
270 YYYYYY, // -001970 -001971 ... +001907 +001971
271 Y, // 1970 1971 ... 9999 +10000 +10001
272 y, // 1 2 ... 2020 ... (era)
273 N, // BC AD
274 NN, // Before Christ ... Anno Domini
275 A, // AM PM
276 a, // am pm
277 H, // 0 1 ... 22 23
278 HH, // 00 01 ... 22 23
279 h, // 1 2 ... 11 12
280 hh, // 01 02 ... 11 12
281 k, // 1 2 ... 23 24
282 kk, // 01 02 ... 23 24
283 m, // 0 1 ... 58 59
284 mm, // 00 01 ... 58 59
285 s, // 0 1 ... 58 59
286 ss, // 00 01 ... 58 59
287 S, // 0 1 ... 8 9 (second fraction)
288 SS, // 00 01 ... 98 99
289 SSS, // 000 001 ... 998 999
290 z, // EST CST ... MST PST
291 Z, // -07:00 -06:00 ... +06:00 +07:00
292 ZZ, // -0700 -0600 ... +0600 +0700
293 X, // unix
294 x, // unix milli
295 };
296};
297
298pub const format = struct {
299 pub const LT = "";
300 pub const LTS = "";
301 pub const L = "";
302 pub const l = "";
303 pub const LL = "";
304 pub const ll = "";
305 pub const LLL = "";
306 pub const lll = "";
307 pub const LLLL = "";
308 pub const llll = "";
309};
310
311pub const TimeZone = enum {
312 UTC,
313};
314
315pub const WeekDay = enum {
316 Sun,
317 Mon,
318 Tue,
319 Wed,
320 Thu,
321 Fri,
322 Sat,
323
324 pub fn next(self: WeekDay) WeekDay {
325 return switch (self) {
326 .Sun => .Mon,
327 .Mon => .Tue,
328 .Tue => .Wed,
329 .Wed => .Thu,
330 .Thu => .Fri,
331 .Fri => .Sat,
332 .Sat => .Sun,
333 };
334 }
335};
zig.mod created+7
...@@ -0,0 +1,7 @@
1id: iecwp4b3bsfmpp4x99gjo4a5ljv6ix4owy8czip32yanpvlb
2name: time
3main: time.zig
4license: MIT
5description: A date and time parsing and formatting library for Zig.
6dependencies:
7 - src: git https://github.com/nektro/zig-range
zigmod.lock created+2
...@@ -0,0 +1,2 @@
12
2git https://github.com/nektro/zig-range commit-890ca308fe09b3d5c866d5cfb3b3d7a95dbf939f