time.odin 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. IS_SUPPORTED :: _IS_SUPPORTED
  13. Time :: struct {
  14. _nsec: i64, // Measured in UNIX nanonseconds
  15. }
  16. Month :: enum int {
  17. January = 1,
  18. February,
  19. March,
  20. April,
  21. May,
  22. June,
  23. July,
  24. August,
  25. September,
  26. October,
  27. November,
  28. December,
  29. }
  30. Weekday :: enum int {
  31. Sunday = 0,
  32. Monday,
  33. Tuesday,
  34. Wednesday,
  35. Thursday,
  36. Friday,
  37. Saturday,
  38. }
  39. Stopwatch :: struct {
  40. running: bool,
  41. _start_time: Tick,
  42. _accumulation: Duration,
  43. }
  44. now :: proc "contextless" () -> Time {
  45. return _now()
  46. }
  47. sleep :: proc "contextless" (d: Duration) {
  48. _sleep(d)
  49. }
  50. stopwatch_start :: proc "contextless" (using stopwatch: ^Stopwatch) {
  51. if !running {
  52. _start_time = tick_now()
  53. running = true
  54. }
  55. }
  56. stopwatch_stop :: proc "contextless" (using stopwatch: ^Stopwatch) {
  57. if running {
  58. _accumulation += tick_diff(_start_time, tick_now())
  59. running = false
  60. }
  61. }
  62. stopwatch_reset :: proc "contextless" (using stopwatch: ^Stopwatch) {
  63. _accumulation = {}
  64. running = false
  65. }
  66. stopwatch_duration :: proc "contextless" (using stopwatch: Stopwatch) -> Duration {
  67. if !running { return _accumulation }
  68. return _accumulation + tick_diff(_start_time, tick_now())
  69. }
  70. diff :: proc "contextless" (start, end: Time) -> Duration {
  71. d := end._nsec - start._nsec
  72. return Duration(d)
  73. }
  74. since :: proc "contextless" (start: Time) -> Duration {
  75. return diff(start, now())
  76. }
  77. duration_nanoseconds :: proc "contextless" (d: Duration) -> i64 {
  78. return i64(d)
  79. }
  80. duration_microseconds :: proc "contextless" (d: Duration) -> f64 {
  81. return duration_seconds(d) * 1e6
  82. }
  83. duration_milliseconds :: proc "contextless" (d: Duration) -> f64 {
  84. return duration_seconds(d) * 1e3
  85. }
  86. duration_seconds :: proc "contextless" (d: Duration) -> f64 {
  87. sec := d / Second
  88. nsec := d % Second
  89. return f64(sec) + f64(nsec)/1e9
  90. }
  91. duration_minutes :: proc "contextless" (d: Duration) -> f64 {
  92. min := d / Minute
  93. nsec := d % Minute
  94. return f64(min) + f64(nsec)/(60*1e9)
  95. }
  96. duration_hours :: proc "contextless" (d: Duration) -> f64 {
  97. hour := d / Hour
  98. nsec := d % Hour
  99. return f64(hour) + f64(nsec)/(60*60*1e9)
  100. }
  101. duration_round :: proc "contextless" (d, m: Duration) -> Duration {
  102. _less_than_half :: #force_inline proc "contextless" (x, y: Duration) -> bool {
  103. return u64(x)+u64(x) < u64(y)
  104. }
  105. if m <= 0 {
  106. return d
  107. }
  108. r := d % m
  109. if d < 0 {
  110. r = -r
  111. if _less_than_half(r, m) {
  112. return d + r
  113. }
  114. if d1 := d-m+r; d1 < d {
  115. return d1
  116. }
  117. return MIN_DURATION
  118. }
  119. if _less_than_half(r, m) {
  120. return d - r
  121. }
  122. if d1 := d+m-r; d1 > d {
  123. return d1
  124. }
  125. return MAX_DURATION
  126. }
  127. duration_truncate :: proc "contextless" (d, m: Duration) -> Duration {
  128. return d if m <= 0 else d - d%m
  129. }
  130. date :: proc "contextless" (t: Time) -> (year: int, month: Month, day: int) {
  131. year, month, day, _ = _abs_date(_time_abs(t), true)
  132. return
  133. }
  134. year :: proc "contextless" (t: Time) -> (year: int) {
  135. year, _, _, _ = _date(t, true)
  136. return
  137. }
  138. month :: proc "contextless" (t: Time) -> (month: Month) {
  139. _, month, _, _ = _date(t, true)
  140. return
  141. }
  142. day :: proc "contextless" (t: Time) -> (day: int) {
  143. _, _, day, _ = _date(t, true)
  144. return
  145. }
  146. clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
  147. clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) {
  148. return clock_from_seconds(_time_abs(t))
  149. }
  150. clock_from_duration :: proc "contextless" (d: Duration) -> (hour, min, sec: int) {
  151. return clock_from_seconds(u64(d/1e9))
  152. }
  153. clock_from_stopwatch :: proc "contextless" (s: Stopwatch) -> (hour, min, sec: int) {
  154. return clock_from_duration(stopwatch_duration(s))
  155. }
  156. clock_from_seconds :: proc "contextless" (nsec: u64) -> (hour, min, sec: int) {
  157. sec = int(nsec % SECONDS_PER_DAY)
  158. hour = sec / SECONDS_PER_HOUR
  159. sec -= hour * SECONDS_PER_HOUR
  160. min = sec / SECONDS_PER_MINUTE
  161. sec -= min * SECONDS_PER_MINUTE
  162. return
  163. }
  164. read_cycle_counter :: proc "contextless" () -> u64 {
  165. return u64(intrinsics.read_cycle_counter())
  166. }
  167. unix :: proc "contextless" (sec: i64, nsec: i64) -> Time {
  168. sec, nsec := sec, nsec
  169. if nsec < 0 || nsec >= 1e9 {
  170. n := nsec / 1e9
  171. sec += n
  172. nsec -= n * 1e9
  173. if nsec < 0 {
  174. nsec += 1e9
  175. sec -= 1
  176. }
  177. }
  178. return Time{(sec*1e9 + nsec)}
  179. }
  180. to_unix_seconds :: time_to_unix
  181. time_to_unix :: proc "contextless" (t: Time) -> i64 {
  182. return t._nsec/1e9
  183. }
  184. to_unix_nanoseconds :: time_to_unix_nano
  185. time_to_unix_nano :: proc "contextless" (t: Time) -> i64 {
  186. return t._nsec
  187. }
  188. time_add :: proc "contextless" (t: Time, d: Duration) -> Time {
  189. return Time{t._nsec + i64(d)}
  190. }
  191. // Accurate sleep borrowed from: https://blat-blatnik.github.io/computerBear/making-accurate-sleep-function/
  192. //
  193. // Accuracy seems to be pretty good out of the box on Linux, to within around 4µs worst case.
  194. // On Windows it depends but is comparable with regular sleep in the worst case.
  195. // To get the same kind of accuracy as on Linux, have your program call `win32.time_begin_period(1)` to
  196. // tell Windows to use a more accurate timer for your process.
  197. accurate_sleep :: proc "contextless" (d: Duration) {
  198. to_sleep, estimate, mean, m2, count: Duration
  199. to_sleep = d
  200. estimate = 5 * Millisecond
  201. mean = 5 * Millisecond
  202. count = 1
  203. for to_sleep > estimate {
  204. start := tick_now()
  205. sleep(1 * Millisecond)
  206. observed := tick_since(start)
  207. to_sleep -= observed
  208. count += 1
  209. delta := observed - mean
  210. mean += delta / count
  211. m2 += delta * (observed - mean)
  212. stddev := intrinsics.sqrt(f64(m2) / f64(count - 1))
  213. estimate = mean + Duration(stddev)
  214. }
  215. start := tick_now()
  216. for to_sleep > tick_since(start) {
  217. // prevent the spinlock from taking the thread hostage, still accurate enough
  218. _yield()
  219. // NOTE: it might be possible that it yields for too long, in that case it should spinlock freely for a while
  220. // TODO: needs actual testing done to check if that's the case
  221. }
  222. }
  223. ABSOLUTE_ZERO_YEAR :: i64(-292277022399) // Day is chosen so that 2001-01-01 is Monday in the calculations
  224. ABSOLUTE_TO_INTERNAL :: i64(-9223371966579724800) // i64((ABSOLUTE_ZERO_YEAR - 1) * 365.2425 * SECONDS_PER_DAY);
  225. INTERNAL_TO_ABSOLUTE :: -ABSOLUTE_TO_INTERNAL
  226. UNIX_TO_INTERNAL :: i64((1969*365 + 1969/4 - 1969/100 + 1969/400) * SECONDS_PER_DAY)
  227. INTERNAL_TO_UNIX :: -UNIX_TO_INTERNAL
  228. WALL_TO_INTERNAL :: i64((1884*365 + 1884/4 - 1884/100 + 1884/400) * SECONDS_PER_DAY)
  229. INTERNAL_TO_WALL :: -WALL_TO_INTERNAL
  230. UNIX_TO_ABSOLUTE :: UNIX_TO_INTERNAL + INTERNAL_TO_ABSOLUTE
  231. ABSOLUTE_TO_UNIX :: -UNIX_TO_ABSOLUTE
  232. @(private)
  233. _date :: proc "contextless" (t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  234. year, month, day, yday = _abs_date(_time_abs(t), full)
  235. return
  236. }
  237. @(private)
  238. _time_abs :: proc "contextless" (t: Time) -> u64 {
  239. return u64(t._nsec/1e9 + UNIX_TO_ABSOLUTE)
  240. }
  241. @(private)
  242. _abs_date :: proc "contextless" (abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  243. _is_leap_year :: proc "contextless" (year: int) -> bool {
  244. return year%4 == 0 && (year%100 != 0 || year%400 == 0)
  245. }
  246. d := abs / SECONDS_PER_DAY
  247. // 400 year cycles
  248. n := d / DAYS_PER_400_YEARS
  249. y := 400 * n
  250. d -= DAYS_PER_400_YEARS * n
  251. // Cut-off 100 year cycles
  252. n = d / DAYS_PER_100_YEARS
  253. n -= n >> 2
  254. y += 100 * n
  255. d -= DAYS_PER_100_YEARS * n
  256. // Cut-off 4 year cycles
  257. n = d / DAYS_PER_4_YEARS
  258. y += 4 * n
  259. d -= DAYS_PER_4_YEARS * n
  260. n = d / 365
  261. n -= n >> 2
  262. y += n
  263. d -= 365 * n
  264. year = int(i64(y) + ABSOLUTE_ZERO_YEAR)
  265. yday = int(d)
  266. if !full {
  267. return
  268. }
  269. day = yday
  270. if _is_leap_year(year) {
  271. switch {
  272. case day > 31+29-1:
  273. day -= 1
  274. case day == 31+29-1:
  275. month = .February
  276. day = 29
  277. return
  278. }
  279. }
  280. month = Month(day / 31)
  281. end := int(days_before[int(month)+1])
  282. begin: int
  283. if day >= end {
  284. (^int)(&month)^ += 1
  285. begin = end
  286. } else {
  287. begin = int(days_before[month])
  288. }
  289. (^int)(&month)^ += 1 // January is 1
  290. day = day - begin + 1
  291. return
  292. }
  293. datetime_to_time :: proc "contextless" (year, month, day, hour, minute, second: int, nsec := int(0)) -> (t: Time, ok: bool) {
  294. divmod :: proc "contextless" (year: int, divisor: int) -> (div: int, mod: int) {
  295. if divisor <= 0 {
  296. intrinsics.debug_trap()
  297. }
  298. div = int(year / divisor)
  299. mod = year % divisor
  300. return
  301. }
  302. ok = true
  303. _y := year - 1970
  304. _m := month - 1
  305. _d := day - 1
  306. if month < 1 || month > 12 {
  307. _m %= 12; ok = false
  308. }
  309. if day < 1 || day > 31 {
  310. _d %= 31; ok = false
  311. }
  312. s := i64(0)
  313. div, mod := divmod(_y, 400)
  314. days := div * DAYS_PER_400_YEARS
  315. div, mod = divmod(mod, 100)
  316. days += div * DAYS_PER_100_YEARS
  317. div, mod = divmod(mod, 4)
  318. days += (div * DAYS_PER_4_YEARS) + (mod * 365)
  319. days += int(days_before[_m]) + _d
  320. s += i64(days) * SECONDS_PER_DAY
  321. s += i64(hour) * SECONDS_PER_HOUR
  322. s += i64(minute) * SECONDS_PER_MINUTE
  323. s += i64(second)
  324. t._nsec = (s * 1e9) + i64(nsec)
  325. return
  326. }
  327. days_before := [?]i32{
  328. 0,
  329. 31,
  330. 31 + 28,
  331. 31 + 28 + 31,
  332. 31 + 28 + 31 + 30,
  333. 31 + 28 + 31 + 30 + 31,
  334. 31 + 28 + 31 + 30 + 31 + 30,
  335. 31 + 28 + 31 + 30 + 31 + 30 + 31,
  336. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  337. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  338. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  339. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  340. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
  341. }
  342. SECONDS_PER_MINUTE :: 60
  343. SECONDS_PER_HOUR :: 60 * SECONDS_PER_MINUTE
  344. SECONDS_PER_DAY :: 24 * SECONDS_PER_HOUR
  345. SECONDS_PER_WEEK :: 7 * SECONDS_PER_DAY
  346. DAYS_PER_400_YEARS :: 365*400 + 97
  347. DAYS_PER_100_YEARS :: 365*100 + 24
  348. DAYS_PER_4_YEARS :: 365*4 + 1