2
0

time.odin 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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. weekday :: proc "contextless" (t: Time) -> (weekday: Weekday) {
  147. abs := _time_abs(t)
  148. sec := (abs + u64(Weekday.Monday) * SECONDS_PER_DAY) % SECONDS_PER_WEEK
  149. return Weekday(int(sec) / SECONDS_PER_DAY)
  150. }
  151. clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
  152. clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) {
  153. return clock_from_seconds(_time_abs(t))
  154. }
  155. clock_from_duration :: proc "contextless" (d: Duration) -> (hour, min, sec: int) {
  156. return clock_from_seconds(u64(d/1e9))
  157. }
  158. clock_from_stopwatch :: proc "contextless" (s: Stopwatch) -> (hour, min, sec: int) {
  159. return clock_from_duration(stopwatch_duration(s))
  160. }
  161. clock_from_seconds :: proc "contextless" (nsec: u64) -> (hour, min, sec: int) {
  162. sec = int(nsec % SECONDS_PER_DAY)
  163. hour = sec / SECONDS_PER_HOUR
  164. sec -= hour * SECONDS_PER_HOUR
  165. min = sec / SECONDS_PER_MINUTE
  166. sec -= min * SECONDS_PER_MINUTE
  167. return
  168. }
  169. read_cycle_counter :: proc "contextless" () -> u64 {
  170. return u64(intrinsics.read_cycle_counter())
  171. }
  172. unix :: proc "contextless" (sec: i64, nsec: i64) -> Time {
  173. sec, nsec := sec, nsec
  174. if nsec < 0 || nsec >= 1e9 {
  175. n := nsec / 1e9
  176. sec += n
  177. nsec -= n * 1e9
  178. if nsec < 0 {
  179. nsec += 1e9
  180. sec -= 1
  181. }
  182. }
  183. return Time{(sec*1e9 + nsec)}
  184. }
  185. to_unix_seconds :: time_to_unix
  186. time_to_unix :: proc "contextless" (t: Time) -> i64 {
  187. return t._nsec/1e9
  188. }
  189. to_unix_nanoseconds :: time_to_unix_nano
  190. time_to_unix_nano :: proc "contextless" (t: Time) -> i64 {
  191. return t._nsec
  192. }
  193. time_add :: proc "contextless" (t: Time, d: Duration) -> Time {
  194. return Time{t._nsec + i64(d)}
  195. }
  196. // Accurate sleep borrowed from: https://blat-blatnik.github.io/computerBear/making-accurate-sleep-function/
  197. //
  198. // Accuracy seems to be pretty good out of the box on Linux, to within around 4µs worst case.
  199. // On Windows it depends but is comparable with regular sleep in the worst case.
  200. // To get the same kind of accuracy as on Linux, have your program call `win32.time_begin_period(1)` to
  201. // tell Windows to use a more accurate timer for your process.
  202. accurate_sleep :: proc "contextless" (d: Duration) {
  203. to_sleep, estimate, mean, m2, count: Duration
  204. to_sleep = d
  205. estimate = 5 * Millisecond
  206. mean = 5 * Millisecond
  207. count = 1
  208. for to_sleep > estimate {
  209. start := tick_now()
  210. sleep(1 * Millisecond)
  211. observed := tick_since(start)
  212. to_sleep -= observed
  213. count += 1
  214. delta := observed - mean
  215. mean += delta / count
  216. m2 += delta * (observed - mean)
  217. stddev := intrinsics.sqrt(f64(m2) / f64(count - 1))
  218. estimate = mean + Duration(stddev)
  219. }
  220. start := tick_now()
  221. for to_sleep > tick_since(start) {
  222. // prevent the spinlock from taking the thread hostage, still accurate enough
  223. _yield()
  224. // NOTE: it might be possible that it yields for too long, in that case it should spinlock freely for a while
  225. // TODO: needs actual testing done to check if that's the case
  226. }
  227. }
  228. ABSOLUTE_ZERO_YEAR :: i64(-292277022399) // Day is chosen so that 2001-01-01 is Monday in the calculations
  229. ABSOLUTE_TO_INTERNAL :: i64(-9223371966579724800) // i64((ABSOLUTE_ZERO_YEAR - 1) * 365.2425 * SECONDS_PER_DAY);
  230. INTERNAL_TO_ABSOLUTE :: -ABSOLUTE_TO_INTERNAL
  231. UNIX_TO_INTERNAL :: i64((1969*365 + 1969/4 - 1969/100 + 1969/400) * SECONDS_PER_DAY)
  232. INTERNAL_TO_UNIX :: -UNIX_TO_INTERNAL
  233. WALL_TO_INTERNAL :: i64((1884*365 + 1884/4 - 1884/100 + 1884/400) * SECONDS_PER_DAY)
  234. INTERNAL_TO_WALL :: -WALL_TO_INTERNAL
  235. UNIX_TO_ABSOLUTE :: UNIX_TO_INTERNAL + INTERNAL_TO_ABSOLUTE
  236. ABSOLUTE_TO_UNIX :: -UNIX_TO_ABSOLUTE
  237. @(private)
  238. _date :: proc "contextless" (t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  239. year, month, day, yday = _abs_date(_time_abs(t), full)
  240. return
  241. }
  242. @(private)
  243. _time_abs :: proc "contextless" (t: Time) -> u64 {
  244. return u64(t._nsec/1e9 + UNIX_TO_ABSOLUTE)
  245. }
  246. @(private)
  247. _abs_date :: proc "contextless" (abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  248. _is_leap_year :: proc "contextless" (year: int) -> bool {
  249. return year%4 == 0 && (year%100 != 0 || year%400 == 0)
  250. }
  251. d := abs / SECONDS_PER_DAY
  252. // 400 year cycles
  253. n := d / DAYS_PER_400_YEARS
  254. y := 400 * n
  255. d -= DAYS_PER_400_YEARS * n
  256. // Cut-off 100 year cycles
  257. n = d / DAYS_PER_100_YEARS
  258. n -= n >> 2
  259. y += 100 * n
  260. d -= DAYS_PER_100_YEARS * n
  261. // Cut-off 4 year cycles
  262. n = d / DAYS_PER_4_YEARS
  263. y += 4 * n
  264. d -= DAYS_PER_4_YEARS * n
  265. n = d / 365
  266. n -= n >> 2
  267. y += n
  268. d -= 365 * n
  269. year = int(i64(y) + ABSOLUTE_ZERO_YEAR)
  270. yday = int(d)
  271. if !full {
  272. return
  273. }
  274. day = yday
  275. if _is_leap_year(year) {
  276. switch {
  277. case day > 31+29-1:
  278. day -= 1
  279. case day == 31+29-1:
  280. month = .February
  281. day = 29
  282. return
  283. }
  284. }
  285. month = Month(day / 31)
  286. end := int(days_before[int(month)+1])
  287. begin: int
  288. if day >= end {
  289. (^int)(&month)^ += 1
  290. begin = end
  291. } else {
  292. begin = int(days_before[month])
  293. }
  294. (^int)(&month)^ += 1 // January is 1
  295. day = day - begin + 1
  296. return
  297. }
  298. datetime_to_time :: proc "contextless" (year, month, day, hour, minute, second: int, nsec := int(0)) -> (t: Time, ok: bool) {
  299. divmod :: proc "contextless" (year: int, divisor: int) -> (div: int, mod: int) {
  300. if divisor <= 0 {
  301. intrinsics.debug_trap()
  302. }
  303. div = int(year / divisor)
  304. mod = year % divisor
  305. return
  306. }
  307. ok = true
  308. _y := year - 1970
  309. _m := month - 1
  310. _d := day - 1
  311. if month < 1 || month > 12 {
  312. _m %= 12; ok = false
  313. }
  314. if day < 1 || day > 31 {
  315. _d %= 31; ok = false
  316. }
  317. s := i64(0)
  318. div, mod := divmod(_y, 400)
  319. days := div * DAYS_PER_400_YEARS
  320. div, mod = divmod(mod, 100)
  321. days += div * DAYS_PER_100_YEARS
  322. div, mod = divmod(mod, 4)
  323. days += (div * DAYS_PER_4_YEARS) + (mod * 365)
  324. days += int(days_before[_m]) + _d
  325. s += i64(days) * SECONDS_PER_DAY
  326. s += i64(hour) * SECONDS_PER_HOUR
  327. s += i64(minute) * SECONDS_PER_MINUTE
  328. s += i64(second)
  329. t._nsec = (s * 1e9) + i64(nsec)
  330. return
  331. }
  332. days_before := [?]i32{
  333. 0,
  334. 31,
  335. 31 + 28,
  336. 31 + 28 + 31,
  337. 31 + 28 + 31 + 30,
  338. 31 + 28 + 31 + 30 + 31,
  339. 31 + 28 + 31 + 30 + 31 + 30,
  340. 31 + 28 + 31 + 30 + 31 + 30 + 31,
  341. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  342. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  343. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  344. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  345. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
  346. }
  347. SECONDS_PER_MINUTE :: 60
  348. SECONDS_PER_HOUR :: 60 * SECONDS_PER_MINUTE
  349. SECONDS_PER_DAY :: 24 * SECONDS_PER_HOUR
  350. SECONDS_PER_WEEK :: 7 * SECONDS_PER_DAY
  351. DAYS_PER_400_YEARS :: 365*400 + 97
  352. DAYS_PER_100_YEARS :: 365*100 + 24
  353. DAYS_PER_4_YEARS :: 365*4 + 1