| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const string = []const u8; | 2 | const string = []const u8; |
| 3 | const range = @import("range").range; | 3 | const range = @import("range").range; |
| | 4 | const time = @This(); |
| 4 | | 5 | |
| 5 | pub const DateTime = struct { | 6 | pub const DateTime = struct { |
| 6 | ms: u16, | 7 | ms: u16, |
| ... | @@ -161,16 +162,11 @@ pub const DateTime = struct { | ... | @@ -161,16 +162,11 @@ pub const DateTime = struct { |
| 161 | } | 162 | } |
| 162 | | 163 | |
| 163 | pub fn isLeapYear(self: Self) bool { | 164 | pub fn isLeapYear(self: Self) bool { |
| 164 | const y = self.years; | 165 | return time.isLeapYear(self.years); |
| 165 | var ret = false; | | |
| 166 | if (y % 4 == 0) ret = true; | | |
| 167 | if (y % 100 == 0) ret = false; | | |
| 168 | if (y % 400 == 0) ret = true; | | |
| 169 | return ret; | | |
| 170 | } | 166 | } |
| 171 | | 167 | |
| 172 | pub fn daysThisYear(self: Self) u64 { | 168 | pub fn daysThisYear(self: Self) u64 { |
| 173 | return if (self.isLeapYear()) 366 else 365; | 169 | return time.daysInYear(self.years); |
| 174 | } | 170 | } |
| 175 | | 171 | |
| 176 | pub fn daysThisMonth(self: Self) u16 { | 172 | pub fn daysThisMonth(self: Self) u16 { |
| ... | @@ -178,10 +174,7 @@ pub const DateTime = struct { | ... | @@ -178,10 +174,7 @@ pub const DateTime = struct { |
| 178 | } | 174 | } |
| 179 | | 175 | |
| 180 | fn daysInMonth(self: Self, month: u16) u16 { | 176 | fn daysInMonth(self: Self, month: u16) u16 { |
| 181 | const norm = [12]u16{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | 177 | return time.daysInMonth(self.years, month); |
| 182 | const leap = [12]u16{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | | |
| 183 | const month_days = if (!self.isLeapYear()) norm else leap; | | |
| 184 | return month_days[month]; | | |
| 185 | } | 178 | } |
| 186 | | 179 | |
| 187 | fn incrementWeekday(self: *Self, count: u64) void { | 180 | fn incrementWeekday(self: *Self, count: u64) void { |
| ... | @@ -199,6 +192,29 @@ pub const DateTime = struct { | ... | @@ -199,6 +192,29 @@ pub const DateTime = struct { |
| 199 | return ret; | 192 | return ret; |
| 200 | } | 193 | } |
| 201 | | 194 | |
| | 195 | // pub fn toUnix(self: Self) u64 { |
| | 196 | // const x = self.toUnix(); |
| | 197 | // return x / 1000; |
| | 198 | // } |
| | 199 | |
| | 200 | pub fn toUnixMilli(self: Self) u64 { |
| | 201 | var res: u64 = 0; |
| | 202 | res += self.ms; |
| | 203 | res += @as(u64, self.seconds) * std.time.ms_per_s; |
| | 204 | res += @as(u64, self.minutes) * std.time.ms_per_min; |
| | 205 | res += @as(u64, self.hours) * std.time.ms_per_hour; |
| | 206 | res += self.daysSinceEpoch() * std.time.ms_per_day; |
| | 207 | return res; |
| | 208 | } |
| | 209 | |
| | 210 | fn daysSinceEpoch(self: Self) u64 { |
| | 211 | var res: u64 = 0; |
| | 212 | res += self.days; |
| | 213 | for (range(self.years - epoch_unix.years)) |_, i| res += time.daysInYear(@intCast(u16, i)); |
| | 214 | for (range(self.months)) |_, i| res += self.daysInMonth(@intCast(u16, i)); |
| | 215 | return res; |
| | 216 | } |
| | 217 | |
| 202 | /// fmt is based on https://momentjs.com/docs/#/displaying/format/ | 218 | /// fmt is based on https://momentjs.com/docs/#/displaying/format/ |
| 203 | pub fn format(self: Self, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void { | 219 | pub fn format(self: Self, comptime fmt: string, options: std.fmt.FormatOptions, writer: anytype) !void { |
| 204 | _ = options; | 220 | _ = options; |
| ... | @@ -239,6 +255,7 @@ pub const DateTime = struct { | ... | @@ -239,6 +255,7 @@ pub const DateTime = struct { |
| 239 | .DDD => try writer.print("{}", .{self.dayOfThisYear() + 1}), | 255 | .DDD => try writer.print("{}", .{self.dayOfThisYear() + 1}), |
| 240 | .DDDo => try printOrdinal(writer, self.dayOfThisYear() + 1), | 256 | .DDDo => try printOrdinal(writer, self.dayOfThisYear() + 1), |
| 241 | .DDDD => try writer.print("{:0>3}", .{self.dayOfThisYear() + 1}), | 257 | .DDDD => try writer.print("{:0>3}", .{self.dayOfThisYear() + 1}), |
| | 258 | |
| 242 | .d => try writer.print("{}", .{@enumToInt(self.weekday)}), | 259 | .d => try writer.print("{}", .{@enumToInt(self.weekday)}), |
| 243 | .do => try printOrdinal(writer, @enumToInt(self.weekday)), | 260 | .do => try printOrdinal(writer, @enumToInt(self.weekday)), |
| 244 | .dd => try writer.writeAll(@tagName(self.weekday)[0..2]), | 261 | .dd => try writer.writeAll(@tagName(self.weekday)[0..2]), |
| ... | @@ -283,7 +300,8 @@ pub const DateTime = struct { | ... | @@ -283,7 +300,8 @@ pub const DateTime = struct { |
| 283 | .Z => try writer.writeAll("+00:00"), | 300 | .Z => try writer.writeAll("+00:00"), |
| 284 | .ZZ => try writer.writeAll("+0000"), | 301 | .ZZ => try writer.writeAll("+0000"), |
| 285 | | 302 | |
| 286 | else => @compileError("'" ++ @tagName(tag) ++ "' not currently supported"), | 303 | .x => try writer.print("{}", .{self.toUnixMilli()}), |
| | 304 | // .X => try writer.print("{}", .{self.toUnix()}), |
| 287 | } | 305 | } |
| 288 | next = null; | 306 | next = null; |
| 289 | s = i; | 307 | s = i; |
| ... | @@ -365,8 +383,8 @@ pub const DateTime = struct { | ... | @@ -365,8 +383,8 @@ pub const DateTime = struct { |
| 365 | z, // EST CST ... MST PST | 383 | z, // EST CST ... MST PST |
| 366 | Z, // -07:00 -06:00 ... +06:00 +07:00 | 384 | Z, // -07:00 -06:00 ... +06:00 +07:00 |
| 367 | ZZ, // -0700 -0600 ... +0600 +0700 | 385 | ZZ, // -0700 -0600 ... +0600 +0700 |
| 368 | X, // unix | | |
| 369 | x, // unix milli | 386 | x, // unix milli |
| | 387 | // X, // unix |
| 370 | }; | 388 | }; |
| 371 | }; | 389 | }; |
| 372 | | 390 | |
| ... | @@ -414,6 +432,25 @@ pub const Era = enum { | ... | @@ -414,6 +432,25 @@ pub const Era = enum { |
| 414 | AD, | 432 | AD, |
| 415 | }; | 433 | }; |
| 416 | | 434 | |
| | 435 | pub fn isLeapYear(year: u16) bool { |
| | 436 | var ret = false; |
| | 437 | if (year % 4 == 0) ret = true; |
| | 438 | if (year % 100 == 0) ret = false; |
| | 439 | if (year % 400 == 0) ret = true; |
| | 440 | return ret; |
| | 441 | } |
| | 442 | |
| | 443 | pub fn daysInYear(year: u16) u16 { |
| | 444 | return if (isLeapYear(year)) 366 else 365; |
| | 445 | } |
| | 446 | |
| | 447 | fn daysInMonth(year: u16, month: u16) u16 { |
| | 448 | const norm = [12]u16{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
| | 449 | const leap = [12]u16{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
| | 450 | const month_days = if (!isLeapYear(year)) norm else leap; |
| | 451 | return month_days[month]; |
| | 452 | } |
| | 453 | |
| 417 | fn printOrdinal(writer: anytype, num: u16) !void { | 454 | fn printOrdinal(writer: anytype, num: u16) !void { |
| 418 | try writer.print("{}", .{num}); | 455 | try writer.print("{}", .{num}); |
| 419 | try writer.writeAll(switch (num) { | 456 | try writer.writeAll(switch (num) { |