time.odin 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. package time
  2. import "core:intrinsics"
  3. Duration :: distinct i64;
  4. Nanosecond :: Duration(1);
  5. Microsecond :: 1000 * Nanosecond;
  6. Millisecond :: 1000 * Microsecond;
  7. Second :: 1000 * Millisecond;
  8. Minute :: 60 * Second;
  9. Hour :: 60 * Minute;
  10. MIN_DURATION :: Duration(-1 << 63);
  11. MAX_DURATION :: Duration(1<<63 - 1);
  12. Time :: struct {
  13. _nsec: i64, // zero is 1970-01-01 00:00:00
  14. }
  15. Month :: enum int {
  16. January = 1,
  17. February,
  18. March,
  19. April,
  20. May,
  21. June,
  22. July,
  23. August,
  24. September,
  25. October,
  26. November,
  27. December,
  28. }
  29. Weekday :: enum int {
  30. Sunday = 0,
  31. Monday,
  32. Tuesday,
  33. Wednesday,
  34. Thursday,
  35. Friday,
  36. Saturday,
  37. }
  38. diff :: proc(start, end: Time) -> Duration {
  39. d := end._nsec - start._nsec;
  40. return Duration(d);
  41. }
  42. since :: proc(start: Time) -> Duration {
  43. return diff(start, now());
  44. }
  45. duration_nanoseconds :: proc(d: Duration) -> i64 {
  46. return i64(d);
  47. }
  48. duration_microseconds :: proc(d: Duration) -> f64 {
  49. return duration_seconds(d) * 1e6;
  50. }
  51. duration_milliseconds :: proc(d: Duration) -> f64 {
  52. return duration_seconds(d) * 1e3;
  53. }
  54. duration_seconds :: proc(d: Duration) -> f64 {
  55. sec := d / Second;
  56. nsec := d % Second;
  57. return f64(sec) + f64(nsec)/1e9;
  58. }
  59. duration_minutes :: proc(d: Duration) -> f64 {
  60. min := d / Minute;
  61. nsec := d % Minute;
  62. return f64(min) + f64(nsec)/(60*1e9);
  63. }
  64. duration_hours :: proc(d: Duration) -> f64 {
  65. hour := d / Hour;
  66. nsec := d % Hour;
  67. return f64(hour) + f64(nsec)/(60*60*1e9);
  68. }
  69. _less_than_half :: #force_inline proc(x, y: Duration) -> bool {
  70. return u64(x)+u64(x) < u64(y);
  71. }
  72. duration_round :: proc(d, m: Duration) -> Duration {
  73. if m <= 0 {
  74. return d;
  75. }
  76. r := d % m;
  77. if d < 0 {
  78. r = -r;
  79. if _less_than_half(r, m) {
  80. return d + r;
  81. }
  82. if d1 := d-m+r; d1 < d {
  83. return d1;
  84. }
  85. return MIN_DURATION;
  86. }
  87. if _less_than_half(r, m) {
  88. return d - r;
  89. }
  90. if d1 := d+m-r; d1 > d {
  91. return d1;
  92. }
  93. return MAX_DURATION;
  94. }
  95. duration_truncate :: proc(d, m: Duration) -> Duration {
  96. return d if m <= 0 else d - d%m;
  97. }
  98. date :: proc(t: Time) -> (year: int, month: Month, day: int) {
  99. year, month, day, _ = _abs_date(_time_abs(t), true);
  100. return;
  101. }
  102. year :: proc(t: Time) -> (year: int) {
  103. year, _, _, _ = _date(t, true);
  104. return;
  105. }
  106. month :: proc(t: Time) -> (month: Month) {
  107. _, month, _, _ = _date(t, true);
  108. return;
  109. }
  110. day :: proc(t: Time) -> (day: int) {
  111. _, _, day, _ = _date(t, true);
  112. return;
  113. }
  114. clock :: proc(t: Time) -> (hour, min, sec: int) {
  115. sec = int(_time_abs(t) % SECONDS_PER_DAY);
  116. hour = sec / SECONDS_PER_HOUR;
  117. sec -= hour * SECONDS_PER_HOUR;
  118. min = sec / SECONDS_PER_MINUTE;
  119. sec -= min * SECONDS_PER_MINUTE;
  120. return;
  121. }
  122. read_cycle_counter :: proc() -> u64 {
  123. return u64(intrinsics.read_cycle_counter());
  124. }
  125. unix :: proc(sec: i64, nsec: i64) -> Time {
  126. sec, nsec := sec, nsec;
  127. if nsec < 0 || nsec >= 1e9 {
  128. n := nsec / 1e9;
  129. sec += n;
  130. nsec -= n * 1e9;
  131. if nsec < 0 {
  132. nsec += 1e9;
  133. sec -= 1;
  134. }
  135. }
  136. return Time{(sec*1e9 + nsec) + UNIX_TO_INTERNAL};
  137. }
  138. time_to_unix :: proc(t: Time) -> i64 {
  139. return t._nsec/1e9;
  140. }
  141. time_to_unix_nano :: proc(t: Time) -> i64 {
  142. return t._nsec;
  143. }
  144. time_add :: proc(t: Time, d: Duration) -> Time {
  145. return Time{t._nsec + i64(d)};
  146. }
  147. ABSOLUTE_ZERO_YEAR :: i64(-292277022399); // Day is chosen so that 2001-01-01 is Monday in the calculations
  148. ABSOLUTE_TO_INTERNAL :: i64(-9223371966579724800); // i64((ABSOLUTE_ZERO_YEAR - 1) * 365.2425 * SECONDS_PER_DAY);
  149. INTERNAL_TO_ABSOLUTE :: -ABSOLUTE_TO_INTERNAL;
  150. UNIX_TO_INTERNAL :: i64((1969*365 + 1969/4 - 1969/100 + 1969/400) * SECONDS_PER_DAY);
  151. INTERNAL_TO_UNIX :: -UNIX_TO_INTERNAL;
  152. WALL_TO_INTERNAL :: i64((1884*365 + 1884/4 - 1884/100 + 1884/400) * SECONDS_PER_DAY);
  153. INTERNAL_TO_WALL :: -WALL_TO_INTERNAL;
  154. UNIX_TO_ABSOLUTE :: UNIX_TO_INTERNAL + INTERNAL_TO_ABSOLUTE;
  155. ABSOLUTE_TO_UNIX :: -UNIX_TO_ABSOLUTE;
  156. _is_leap_year :: proc(year: int) -> bool {
  157. return year%4 == 0 && (year%100 != 0 || year%400 == 0);
  158. }
  159. _date :: proc(t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  160. year, month, day, yday = _abs_date(_time_abs(t), full);
  161. return;
  162. }
  163. _time_abs :: proc(t: Time) -> u64 {
  164. return u64(t._nsec/1e9 + UNIX_TO_ABSOLUTE);
  165. }
  166. _abs_date :: proc(abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  167. d := abs / SECONDS_PER_DAY;
  168. // 400 year cycles
  169. n := d / DAYS_PER_400_YEARS;
  170. y := 400 * n;
  171. d -= DAYS_PER_400_YEARS * n;
  172. // Cut-off 100 year cycles
  173. n = d / DAYS_PER_100_YEARS;
  174. n -= n >> 2;
  175. y += 100 * n;
  176. d -= DAYS_PER_100_YEARS * n;
  177. // Cut-off 4 year cycles
  178. n = d / DAYS_PER_4_YEARS;
  179. y += 4 * n;
  180. d -= DAYS_PER_4_YEARS * n;
  181. n = d / 365;
  182. n -= n >> 2;
  183. y += n;
  184. d -= 365 * n;
  185. year = int(i64(y) + ABSOLUTE_ZERO_YEAR);
  186. yday = int(d);
  187. if !full {
  188. return;
  189. }
  190. day = yday;
  191. if _is_leap_year(year) {
  192. switch {
  193. case day > 31+29-1:
  194. day -= 1;
  195. case day == 31+29-1:
  196. month = .February;
  197. day = 29;
  198. return;
  199. }
  200. }
  201. month = Month(day / 31);
  202. end := int(days_before[int(month)+1]);
  203. begin: int;
  204. if day >= end {
  205. (^int)(&month)^ += 1;
  206. begin = end;
  207. } else {
  208. begin = int(days_before[month]);
  209. }
  210. (^int)(&month)^ += 1; // January is 1
  211. day = day - begin + 1;
  212. return;
  213. }
  214. datetime_to_time :: proc(year, month, day, hour, minute, second: int, nsec := int(0)) -> (t: Time, ok: bool) {
  215. divmod :: proc(year: int, divisor: int) -> (div: int, mod: int) {
  216. assert(divisor > 0);
  217. div = int(year / divisor);
  218. mod = year % divisor;
  219. return;
  220. }
  221. ok = true;
  222. _y := year - 1970;
  223. _m := month - 1;
  224. _d := day - 1;
  225. if month < 1 || month > 12 {
  226. _m %= 12; ok = false;
  227. }
  228. if day < 1 || day > 31 {
  229. _d %= 31; ok = false;
  230. }
  231. s := i64(0);
  232. div, mod := divmod(_y, 400);
  233. days := div * DAYS_PER_400_YEARS;
  234. div, mod = divmod(mod, 100);
  235. days += div * DAYS_PER_100_YEARS;
  236. div, mod = divmod(mod, 4);
  237. days += (div * DAYS_PER_4_YEARS) + (mod * 365);
  238. days += int(days_before[_m]) + _d;
  239. s += i64(days) * SECONDS_PER_DAY;
  240. s += i64(hour) * SECONDS_PER_HOUR;
  241. s += i64(minute) * SECONDS_PER_MINUTE;
  242. s += i64(second);
  243. t._nsec = (s * 1e9) + i64(nsec);
  244. return;
  245. }
  246. days_before := [?]i32{
  247. 0,
  248. 31,
  249. 31 + 28,
  250. 31 + 28 + 31,
  251. 31 + 28 + 31 + 30,
  252. 31 + 28 + 31 + 30 + 31,
  253. 31 + 28 + 31 + 30 + 31 + 30,
  254. 31 + 28 + 31 + 30 + 31 + 30 + 31,
  255. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  256. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  257. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  258. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  259. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
  260. };
  261. SECONDS_PER_MINUTE :: 60;
  262. SECONDS_PER_HOUR :: 60 * SECONDS_PER_MINUTE;
  263. SECONDS_PER_DAY :: 24 * SECONDS_PER_HOUR;
  264. SECONDS_PER_WEEK :: 7 * SECONDS_PER_DAY;
  265. DAYS_PER_400_YEARS :: 365*400 + 97;
  266. DAYS_PER_100_YEARS :: 365*100 + 24;
  267. DAYS_PER_4_YEARS :: 365*4 + 1;