-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdatetime.zig
119 lines (104 loc) · 3.04 KB
/
datetime.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
const std = @import("std");
pub const DateTime = struct {
year: u16,
month: Month,
day: u8,
hour: u8,
minute: u8,
second: u8,
};
pub const Month = enum(u8) {
January = 1,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December,
pub fn fromInt(value: u8) !Month {
return switch (value) {
1 => Month.January,
2 => Month.February,
3 => Month.March,
4 => Month.April,
5 => Month.May,
6 => Month.June,
7 => Month.July,
8 => Month.August,
9 => Month.September,
10 => Month.October,
11 => Month.November,
12 => Month.December,
else => return error.InvalidMonth,
};
}
};
pub fn fromTimestamp(ts: u64) DateTime {
const SECONDS_PER_DAY = 86400;
const DAYS_PER_YEAR = 365;
const DAYS_IN_4YEARS = 1461;
const DAYS_IN_100YEARS = 36524;
const DAYS_IN_400YEARS = 146097;
const DAYS_BEFORE_EPOCH = 719468;
const seconds_since_midnight: u64 = @rem(ts, SECONDS_PER_DAY);
var day_n: u64 = DAYS_BEFORE_EPOCH + ts / SECONDS_PER_DAY;
var temp: u64 = 0;
temp = 4 * (day_n + DAYS_IN_100YEARS + 1) / DAYS_IN_400YEARS - 1;
var year: u16 = @intCast(100 * temp);
day_n -= DAYS_IN_100YEARS * temp + temp / 4;
temp = 4 * (day_n + DAYS_PER_YEAR + 1) / DAYS_IN_4YEARS - 1;
year += @intCast(temp);
day_n -= DAYS_PER_YEAR * temp + temp / 4;
var month_idx: u8 = @intCast((5 * day_n + 2) / 153);
const day: u8 = @intCast(day_n - (@as(u64, @intCast(month_idx)) * 153 + 2) / 5 + 1);
month_idx += 3;
if (month_idx > 12) {
month_idx -= 12;
year += 1;
}
const month = Month.fromInt(month_idx) catch Month.January;
return DateTime{
.year = year,
.month = month,
.day = day,
.hour = @intCast(seconds_since_midnight / 3600),
.minute = @intCast(seconds_since_midnight % 3600 / 60),
.second = @intCast(seconds_since_midnight % 60),
};
}
pub fn toRFC3339(dt: DateTime) [20]u8 {
var buf: [20]u8 = undefined;
_ = std.fmt.formatIntBuf(buf[0..4], dt.year, 10, .lower, .{ .width = 4, .fill = '0' });
buf[4] = '-';
paddingTwoDigits(buf[5..7], @intFromEnum(dt.month));
buf[7] = '-';
paddingTwoDigits(buf[8..10], dt.day);
buf[10] = 'T';
paddingTwoDigits(buf[11..13], dt.hour);
buf[13] = ':';
paddingTwoDigits(buf[14..16], dt.minute);
buf[16] = ':';
paddingTwoDigits(buf[17..19], dt.second);
buf[19] = 'Z';
return buf;
}
fn paddingTwoDigits(buf: *[2]u8, value: u8) void {
switch (value) {
0 => buf.* = "00".*,
1 => buf.* = "01".*,
2 => buf.* = "02".*,
3 => buf.* = "03".*,
4 => buf.* = "04".*,
5 => buf.* = "05".*,
6 => buf.* = "06".*,
7 => buf.* = "07".*,
8 => buf.* = "08".*,
9 => buf.* = "09".*,
else => _ = std.fmt.formatIntBuf(buf, value, 10, .lower, .{}),
}
}