|
@@ -0,0 +1,220 @@
|
|
|
|
+package time
|
|
|
|
+
|
|
|
|
+Duration :: distinct i64;
|
|
|
|
+
|
|
|
|
+Nanosecond :: Duration(1);
|
|
|
|
+Microsecond :: 1000 * Nanosecond;
|
|
|
|
+Millisecond :: 1000 * Microsecond;
|
|
|
|
+Second :: 1000 * Millisecond;
|
|
|
|
+Minute :: 60 * Second;
|
|
|
|
+Hour :: 60 * Minute;
|
|
|
|
+
|
|
|
|
+MIN_DURATION :: Duration(-1 << 63);
|
|
|
|
+MAX_DURATION :: Duration(1<<63 - 1);
|
|
|
|
+
|
|
|
|
+Time :: struct {
|
|
|
|
+ _nsec: i64, // zero is 1970-01-01 00:00:00
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Month :: enum int {
|
|
|
|
+ January = 1,
|
|
|
|
+ February,
|
|
|
|
+ March,
|
|
|
|
+ April,
|
|
|
|
+ May,
|
|
|
|
+ June,
|
|
|
|
+ July,
|
|
|
|
+ August,
|
|
|
|
+ September,
|
|
|
|
+ October,
|
|
|
|
+ November,
|
|
|
|
+ December,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Weekday :: enum int {
|
|
|
|
+ Sunday = 0,
|
|
|
|
+ Monday,
|
|
|
|
+ Tuesday,
|
|
|
|
+ Wednesday,
|
|
|
|
+ Thursday,
|
|
|
|
+ Friday,
|
|
|
|
+ Saturday,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+duration_nanoseconds :: proc(d: Duration) -> i64 {
|
|
|
|
+ return i64(d);
|
|
|
|
+}
|
|
|
|
+duration_seconds :: proc(d: Duration) -> f64 {
|
|
|
|
+ sec := d / Second;
|
|
|
|
+ nsec := d % Second;
|
|
|
|
+ return f64(sec) + f64(nsec)/1e9;
|
|
|
|
+}
|
|
|
|
+duration_minutes :: proc(d: Duration) -> f64 {
|
|
|
|
+ min := d / Minute;
|
|
|
|
+ nsec := d % Minute;
|
|
|
|
+ return f64(min) + f64(nsec)/(60*1e9);
|
|
|
|
+}
|
|
|
|
+duration_hours :: proc(d: Duration) -> f64 {
|
|
|
|
+ hour := d / Hour;
|
|
|
|
+ nsec := d % Hour;
|
|
|
|
+ return f64(hour) + f64(nsec)/(60*60*1e9);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+_less_than_half :: inline proc(x, y: Duration) -> bool {
|
|
|
|
+ return u64(x)+u64(x) < u64(y);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+duration_round :: proc(d, m: Duration) -> Duration {
|
|
|
|
+ if m <= 0 do return d;
|
|
|
|
+
|
|
|
|
+ r := d % m;
|
|
|
|
+ if d < 0 {
|
|
|
|
+ r = -r;
|
|
|
|
+ if _less_than_half(r, m) {
|
|
|
|
+ return d + r;
|
|
|
|
+ }
|
|
|
|
+ if d1 := d-m+r; d1 < d {
|
|
|
|
+ return d1;
|
|
|
|
+ }
|
|
|
|
+ return MIN_DURATION;
|
|
|
|
+ }
|
|
|
|
+ if _less_than_half(r, m) {
|
|
|
|
+ return d - r;
|
|
|
|
+ }
|
|
|
|
+ if d1 := d+m-r; d1 > d {
|
|
|
|
+ return d1;
|
|
|
|
+ }
|
|
|
|
+ return MAX_DURATION;
|
|
|
|
+}
|
|
|
|
+duration_truncate :: proc(d, m: Duration) -> Duration {
|
|
|
|
+ return m <= 0 ? d : d - d%m;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+date :: proc(t: Time) -> (year: int, month: Month, day: int) {
|
|
|
|
+ year, month, day, _ = _abs_date(_time_abs(t), true);
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+year :: proc(t: Time) -> (year: int) {
|
|
|
|
+ year, _, _, _ = _date(t, true);
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+month :: proc(t: Time) -> (month: Month) {
|
|
|
|
+ _, month, _, _ = _date(t, true);
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+day :: proc(t: Time) -> (day: int) {
|
|
|
|
+ _, _, day, _ = _date(t, true);
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+clock :: proc(t: Time) -> (hour, min, sec: int) {
|
|
|
|
+ sec = int(_time_abs(t) % SECONDS_PER_DAY);
|
|
|
|
+ hour = sec / SECONDS_PER_HOUR;
|
|
|
|
+ sec -= hour * SECONDS_PER_HOUR;
|
|
|
|
+ min = sec / SECONDS_PER_MINUTE;
|
|
|
|
+ sec -= min * SECONDS_PER_MINUTE;
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ABSOLUTE_ZERO_YEAR :: -292277022399; // Day is chosen so that 2001-01-01 is Monday in the calculations
|
|
|
|
+UNIX_TO_ABSOLUTE :: (1969*365 + 1969/4 - 1969/100 + 1969/400 - ((ABSOLUTE_ZERO_YEAR - 1) * 365.2425)) * SECONDS_PER_DAY;
|
|
|
|
+
|
|
|
|
+_is_leap_year :: proc(year: int) -> bool {
|
|
|
|
+ return year%4 == 0 && (year%100 != 0 || year%400 == 0);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+_date :: proc(t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
|
|
|
|
+ year, month, day, yday = _abs_date(_time_abs(t), full);
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+_time_abs :: proc(t: Time) -> u64 {
|
|
|
|
+ return u64(t._nsec/1e9 + UNIX_TO_ABSOLUTE);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+_abs_date :: proc(abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
|
|
|
|
+ d := abs / SECONDS_PER_DAY;
|
|
|
|
+
|
|
|
|
+ // 400 year cycles
|
|
|
|
+ n := d / DAYS_PER_400_YEARS;
|
|
|
|
+ y := 400 * n;
|
|
|
|
+ d -= DAYS_PER_400_YEARS * n;
|
|
|
|
+
|
|
|
|
+ // Cut-off 100 year cycles
|
|
|
|
+ n = d / DAYS_PER_100_YEARS;
|
|
|
|
+ n -= n >> 2;
|
|
|
|
+ y += 100 * n;
|
|
|
|
+ d -= DAYS_PER_100_YEARS * n;
|
|
|
|
+
|
|
|
|
+ // Cut-off 4 year cycles
|
|
|
|
+ n = d / DAYS_PER_4_YEARS;
|
|
|
|
+ y += 4 * n;
|
|
|
|
+ d -= DAYS_PER_4_YEARS * n;
|
|
|
|
+
|
|
|
|
+ n = d / 365;
|
|
|
|
+ n -= n >> 2;
|
|
|
|
+ y += n;
|
|
|
|
+ d -= 365 * n;
|
|
|
|
+
|
|
|
|
+ year = int(i64(y) + ABSOLUTE_ZERO_YEAR);
|
|
|
|
+ yday = int(d);
|
|
|
|
+
|
|
|
|
+ if !full {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ day = yday;
|
|
|
|
+ if _is_leap_year(year) do switch {
|
|
|
|
+ case day < 31+29-1:
|
|
|
|
+ day -= 1;
|
|
|
|
+ case day == 31+29-1:
|
|
|
|
+ month = Month.February;
|
|
|
|
+ day = 29;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ month = Month(day / 31);
|
|
|
|
+ end := int(days_before[int(month)+1]);
|
|
|
|
+ begin: int;
|
|
|
|
+ if day >= end {
|
|
|
|
+ (^int)(&month)^ += 1;
|
|
|
|
+ begin = end;
|
|
|
|
+ } else {
|
|
|
|
+ begin = int(days_before[month]);
|
|
|
|
+ }
|
|
|
|
+ (^int)(&month)^ += 1; // January is 1
|
|
|
|
+ day = day - begin + 1;
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+days_before := [?]i32{
|
|
|
|
+ 0,
|
|
|
|
+ 31,
|
|
|
|
+ 31 + 28,
|
|
|
|
+ 31 + 28 + 31,
|
|
|
|
+ 31 + 28 + 31 + 30,
|
|
|
|
+ 31 + 28 + 31 + 30 + 31,
|
|
|
|
+ 31 + 28 + 31 + 30 + 31 + 30,
|
|
|
|
+ 31 + 28 + 31 + 30 + 31 + 30 + 31,
|
|
|
|
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
|
|
|
|
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
|
|
|
|
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
|
|
|
|
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
|
|
|
|
+ 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+SECONDS_PER_MINUTE :: 60;
|
|
|
|
+SECONDS_PER_HOUR :: 60 * SECONDS_PER_MINUTE;
|
|
|
|
+SECONDS_PER_DAY :: 24 * SECONDS_PER_HOUR;
|
|
|
|
+SECONDS_PER_WEEK :: 7 * SECONDS_PER_DAY;
|
|
|
|
+DAYS_PER_400_YEARS :: 365*400 + 97;
|
|
|
|
+DAYS_PER_100_YEARS :: 365*100 + 24;
|
|
|
|
+DAYS_PER_4_YEARS :: 365*4 + 1;
|