time.odin 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. package time
  2. Duration :: distinct i64;
  3. Nanosecond :: Duration(1);
  4. Microsecond :: 1000 * Nanosecond;
  5. Millisecond :: 1000 * Microsecond;
  6. Second :: 1000 * Millisecond;
  7. Minute :: 60 * Second;
  8. Hour :: 60 * Minute;
  9. MIN_DURATION :: Duration(-1 << 63);
  10. MAX_DURATION :: Duration(1<<63 - 1);
  11. Time :: struct {
  12. _nsec: i64, // zero is 1970-01-01 00:00:00
  13. }
  14. Month :: enum int {
  15. January = 1,
  16. February,
  17. March,
  18. April,
  19. May,
  20. June,
  21. July,
  22. August,
  23. September,
  24. October,
  25. November,
  26. December,
  27. }
  28. Weekday :: enum int {
  29. Sunday = 0,
  30. Monday,
  31. Tuesday,
  32. Wednesday,
  33. Thursday,
  34. Friday,
  35. Saturday,
  36. }
  37. diff :: proc(start, end: Time) -> Duration {
  38. d := end._nsec - start._nsec;
  39. return Duration(d);
  40. }
  41. duration_nanoseconds :: proc(d: Duration) -> i64 {
  42. return i64(d);
  43. }
  44. duration_seconds :: proc(d: Duration) -> f64 {
  45. sec := d / Second;
  46. nsec := d % Second;
  47. return f64(sec) + f64(nsec)/1e9;
  48. }
  49. duration_minutes :: proc(d: Duration) -> f64 {
  50. min := d / Minute;
  51. nsec := d % Minute;
  52. return f64(min) + f64(nsec)/(60*1e9);
  53. }
  54. duration_hours :: proc(d: Duration) -> f64 {
  55. hour := d / Hour;
  56. nsec := d % Hour;
  57. return f64(hour) + f64(nsec)/(60*60*1e9);
  58. }
  59. _less_than_half :: inline proc(x, y: Duration) -> bool {
  60. return u64(x)+u64(x) < u64(y);
  61. }
  62. duration_round :: proc(d, m: Duration) -> Duration {
  63. if m <= 0 do return d;
  64. r := d % m;
  65. if d < 0 {
  66. r = -r;
  67. if _less_than_half(r, m) {
  68. return d + r;
  69. }
  70. if d1 := d-m+r; d1 < d {
  71. return d1;
  72. }
  73. return MIN_DURATION;
  74. }
  75. if _less_than_half(r, m) {
  76. return d - r;
  77. }
  78. if d1 := d+m-r; d1 > d {
  79. return d1;
  80. }
  81. return MAX_DURATION;
  82. }
  83. duration_truncate :: proc(d, m: Duration) -> Duration {
  84. return m <= 0 ? d : d - d%m;
  85. }
  86. date :: proc(t: Time) -> (year: int, month: Month, day: int) {
  87. year, month, day, _ = _abs_date(_time_abs(t), true);
  88. return;
  89. }
  90. year :: proc(t: Time) -> (year: int) {
  91. year, _, _, _ = _date(t, true);
  92. return;
  93. }
  94. month :: proc(t: Time) -> (month: Month) {
  95. _, month, _, _ = _date(t, true);
  96. return;
  97. }
  98. day :: proc(t: Time) -> (day: int) {
  99. _, _, day, _ = _date(t, true);
  100. return;
  101. }
  102. clock :: proc(t: Time) -> (hour, min, sec: int) {
  103. sec = int(_time_abs(t) % SECONDS_PER_DAY);
  104. hour = sec / SECONDS_PER_HOUR;
  105. sec -= hour * SECONDS_PER_HOUR;
  106. min = sec / SECONDS_PER_MINUTE;
  107. sec -= min * SECONDS_PER_MINUTE;
  108. return;
  109. }
  110. ABSOLUTE_ZERO_YEAR :: -292277022399; // Day is chosen so that 2001-01-01 is Monday in the calculations
  111. UNIX_TO_ABSOLUTE :: (1969*365 + 1969/4 - 1969/100 + 1969/400 - ((ABSOLUTE_ZERO_YEAR - 1) * 365.2425)) * SECONDS_PER_DAY;
  112. _is_leap_year :: proc(year: int) -> bool {
  113. return year%4 == 0 && (year%100 != 0 || year%400 == 0);
  114. }
  115. _date :: proc(t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  116. year, month, day, yday = _abs_date(_time_abs(t), full);
  117. return;
  118. }
  119. _time_abs :: proc(t: Time) -> u64 {
  120. return u64(t._nsec/1e9 + UNIX_TO_ABSOLUTE);
  121. }
  122. _abs_date :: proc(abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  123. d := abs / SECONDS_PER_DAY;
  124. // 400 year cycles
  125. n := d / DAYS_PER_400_YEARS;
  126. y := 400 * n;
  127. d -= DAYS_PER_400_YEARS * n;
  128. // Cut-off 100 year cycles
  129. n = d / DAYS_PER_100_YEARS;
  130. n -= n >> 2;
  131. y += 100 * n;
  132. d -= DAYS_PER_100_YEARS * n;
  133. // Cut-off 4 year cycles
  134. n = d / DAYS_PER_4_YEARS;
  135. y += 4 * n;
  136. d -= DAYS_PER_4_YEARS * n;
  137. n = d / 365;
  138. n -= n >> 2;
  139. y += n;
  140. d -= 365 * n;
  141. year = int(i64(y) + ABSOLUTE_ZERO_YEAR);
  142. yday = int(d);
  143. if !full {
  144. return;
  145. }
  146. day = yday;
  147. if _is_leap_year(year) do switch {
  148. case day < 31+29-1:
  149. day -= 1;
  150. case day == 31+29-1:
  151. month = Month.February;
  152. day = 29;
  153. return;
  154. }
  155. month = Month(day / 31);
  156. end := int(days_before[int(month)+1]);
  157. begin: int;
  158. if day >= end {
  159. (^int)(&month)^ += 1;
  160. begin = end;
  161. } else {
  162. begin = int(days_before[month]);
  163. }
  164. (^int)(&month)^ += 1; // January is 1
  165. day = day - begin + 1;
  166. return;
  167. }
  168. days_before := [?]i32{
  169. 0,
  170. 31,
  171. 31 + 28,
  172. 31 + 28 + 31,
  173. 31 + 28 + 31 + 30,
  174. 31 + 28 + 31 + 30 + 31,
  175. 31 + 28 + 31 + 30 + 31 + 30,
  176. 31 + 28 + 31 + 30 + 31 + 30 + 31,
  177. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  178. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  179. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  180. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  181. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
  182. };
  183. SECONDS_PER_MINUTE :: 60;
  184. SECONDS_PER_HOUR :: 60 * SECONDS_PER_MINUTE;
  185. SECONDS_PER_DAY :: 24 * SECONDS_PER_HOUR;
  186. SECONDS_PER_WEEK :: 7 * SECONDS_PER_DAY;
  187. DAYS_PER_400_YEARS :: 365*400 + 97;
  188. DAYS_PER_100_YEARS :: 365*100 + 24;
  189. DAYS_PER_4_YEARS :: 365*4 + 1;