time.odin 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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. Stopwatch :: struct {
  39. running: bool,
  40. _start_time: Tick,
  41. _accumulation: Duration,
  42. }
  43. stopwatch_start :: proc(using stopwatch: ^Stopwatch) {
  44. if !running {
  45. _start_time = tick_now()
  46. running = true
  47. }
  48. }
  49. stopwatch_stop :: proc(using stopwatch: ^Stopwatch) {
  50. if running {
  51. _accumulation += tick_diff(_start_time, tick_now())
  52. running = false
  53. }
  54. }
  55. stopwatch_reset :: proc(using stopwatch: ^Stopwatch) {
  56. _accumulation = {}
  57. running = false
  58. }
  59. stopwatch_duration :: proc(using stopwatch: Stopwatch) -> Duration {
  60. if !running { return _accumulation }
  61. return _accumulation + tick_diff(_start_time, tick_now())
  62. }
  63. diff :: proc(start, end: Time) -> Duration {
  64. d := end._nsec - start._nsec
  65. return Duration(d)
  66. }
  67. since :: proc(start: Time) -> Duration {
  68. return diff(start, now())
  69. }
  70. duration_nanoseconds :: proc(d: Duration) -> i64 {
  71. return i64(d)
  72. }
  73. duration_microseconds :: proc(d: Duration) -> f64 {
  74. return duration_seconds(d) * 1e6
  75. }
  76. duration_milliseconds :: proc(d: Duration) -> f64 {
  77. return duration_seconds(d) * 1e3
  78. }
  79. duration_seconds :: proc(d: Duration) -> f64 {
  80. sec := d / Second
  81. nsec := d % Second
  82. return f64(sec) + f64(nsec)/1e9
  83. }
  84. duration_minutes :: proc(d: Duration) -> f64 {
  85. min := d / Minute
  86. nsec := d % Minute
  87. return f64(min) + f64(nsec)/(60*1e9)
  88. }
  89. duration_hours :: proc(d: Duration) -> f64 {
  90. hour := d / Hour
  91. nsec := d % Hour
  92. return f64(hour) + f64(nsec)/(60*60*1e9)
  93. }
  94. _less_than_half :: #force_inline proc(x, y: Duration) -> bool {
  95. return u64(x)+u64(x) < u64(y)
  96. }
  97. duration_round :: proc(d, m: Duration) -> Duration {
  98. if m <= 0 {
  99. return d
  100. }
  101. r := d % m
  102. if d < 0 {
  103. r = -r
  104. if _less_than_half(r, m) {
  105. return d + r
  106. }
  107. if d1 := d-m+r; d1 < d {
  108. return d1
  109. }
  110. return MIN_DURATION
  111. }
  112. if _less_than_half(r, m) {
  113. return d - r
  114. }
  115. if d1 := d+m-r; d1 > d {
  116. return d1
  117. }
  118. return MAX_DURATION
  119. }
  120. duration_truncate :: proc(d, m: Duration) -> Duration {
  121. return d if m <= 0 else d - d%m
  122. }
  123. date :: proc(t: Time) -> (year: int, month: Month, day: int) {
  124. year, month, day, _ = _abs_date(_time_abs(t), true)
  125. return
  126. }
  127. year :: proc(t: Time) -> (year: int) {
  128. year, _, _, _ = _date(t, true)
  129. return
  130. }
  131. month :: proc(t: Time) -> (month: Month) {
  132. _, month, _, _ = _date(t, true)
  133. return
  134. }
  135. day :: proc(t: Time) -> (day: int) {
  136. _, _, day, _ = _date(t, true)
  137. return
  138. }
  139. clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
  140. clock_from_time :: proc(t: Time) -> (hour, min, sec: int) {
  141. return clock_from_seconds(_time_abs(t))
  142. }
  143. clock_from_duration :: proc(d: Duration) -> (hour, min, sec: int) {
  144. return clock_from_seconds(u64(d/1e9))
  145. }
  146. clock_from_stopwatch :: proc(s: Stopwatch) -> (hour, min, sec: int) {
  147. return clock_from_duration(stopwatch_duration(s))
  148. }
  149. clock_from_seconds :: proc(nsec: u64) -> (hour, min, sec: int) {
  150. sec = int(nsec % SECONDS_PER_DAY)
  151. hour = sec / SECONDS_PER_HOUR
  152. sec -= hour * SECONDS_PER_HOUR
  153. min = sec / SECONDS_PER_MINUTE
  154. sec -= min * SECONDS_PER_MINUTE
  155. return
  156. }
  157. read_cycle_counter :: proc() -> u64 {
  158. return u64(intrinsics.read_cycle_counter())
  159. }
  160. unix :: proc(sec: i64, nsec: i64) -> Time {
  161. sec, nsec := sec, nsec
  162. if nsec < 0 || nsec >= 1e9 {
  163. n := nsec / 1e9
  164. sec += n
  165. nsec -= n * 1e9
  166. if nsec < 0 {
  167. nsec += 1e9
  168. sec -= 1
  169. }
  170. }
  171. return Time{(sec*1e9 + nsec) + UNIX_TO_INTERNAL}
  172. }
  173. time_to_unix :: proc(t: Time) -> i64 {
  174. return t._nsec/1e9
  175. }
  176. time_to_unix_nano :: proc(t: Time) -> i64 {
  177. return t._nsec
  178. }
  179. time_add :: proc(t: Time, d: Duration) -> Time {
  180. return Time{t._nsec + i64(d)}
  181. }
  182. ABSOLUTE_ZERO_YEAR :: i64(-292277022399) // Day is chosen so that 2001-01-01 is Monday in the calculations
  183. ABSOLUTE_TO_INTERNAL :: i64(-9223371966579724800) // i64((ABSOLUTE_ZERO_YEAR - 1) * 365.2425 * SECONDS_PER_DAY);
  184. INTERNAL_TO_ABSOLUTE :: -ABSOLUTE_TO_INTERNAL
  185. UNIX_TO_INTERNAL :: i64((1969*365 + 1969/4 - 1969/100 + 1969/400) * SECONDS_PER_DAY)
  186. INTERNAL_TO_UNIX :: -UNIX_TO_INTERNAL
  187. WALL_TO_INTERNAL :: i64((1884*365 + 1884/4 - 1884/100 + 1884/400) * SECONDS_PER_DAY)
  188. INTERNAL_TO_WALL :: -WALL_TO_INTERNAL
  189. UNIX_TO_ABSOLUTE :: UNIX_TO_INTERNAL + INTERNAL_TO_ABSOLUTE
  190. ABSOLUTE_TO_UNIX :: -UNIX_TO_ABSOLUTE
  191. _is_leap_year :: proc(year: int) -> bool {
  192. return year%4 == 0 && (year%100 != 0 || year%400 == 0)
  193. }
  194. _date :: proc(t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  195. year, month, day, yday = _abs_date(_time_abs(t), full)
  196. return
  197. }
  198. _time_abs :: proc(t: Time) -> u64 {
  199. return u64(t._nsec/1e9 + UNIX_TO_ABSOLUTE)
  200. }
  201. _abs_date :: proc(abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  202. d := abs / SECONDS_PER_DAY
  203. // 400 year cycles
  204. n := d / DAYS_PER_400_YEARS
  205. y := 400 * n
  206. d -= DAYS_PER_400_YEARS * n
  207. // Cut-off 100 year cycles
  208. n = d / DAYS_PER_100_YEARS
  209. n -= n >> 2
  210. y += 100 * n
  211. d -= DAYS_PER_100_YEARS * n
  212. // Cut-off 4 year cycles
  213. n = d / DAYS_PER_4_YEARS
  214. y += 4 * n
  215. d -= DAYS_PER_4_YEARS * n
  216. n = d / 365
  217. n -= n >> 2
  218. y += n
  219. d -= 365 * n
  220. year = int(i64(y) + ABSOLUTE_ZERO_YEAR)
  221. yday = int(d)
  222. if !full {
  223. return
  224. }
  225. day = yday
  226. if _is_leap_year(year) {
  227. switch {
  228. case day > 31+29-1:
  229. day -= 1
  230. case day == 31+29-1:
  231. month = .February
  232. day = 29
  233. return
  234. }
  235. }
  236. month = Month(day / 31)
  237. end := int(days_before[int(month)+1])
  238. begin: int
  239. if day >= end {
  240. (^int)(&month)^ += 1
  241. begin = end
  242. } else {
  243. begin = int(days_before[month])
  244. }
  245. (^int)(&month)^ += 1 // January is 1
  246. day = day - begin + 1
  247. return
  248. }
  249. datetime_to_time :: proc(year, month, day, hour, minute, second: int, nsec := int(0)) -> (t: Time, ok: bool) {
  250. divmod :: proc(year: int, divisor: int) -> (div: int, mod: int) {
  251. assert(divisor > 0)
  252. div = int(year / divisor)
  253. mod = year % divisor
  254. return
  255. }
  256. ok = true
  257. _y := year - 1970
  258. _m := month - 1
  259. _d := day - 1
  260. if month < 1 || month > 12 {
  261. _m %= 12; ok = false
  262. }
  263. if day < 1 || day > 31 {
  264. _d %= 31; ok = false
  265. }
  266. s := i64(0)
  267. div, mod := divmod(_y, 400)
  268. days := div * DAYS_PER_400_YEARS
  269. div, mod = divmod(mod, 100)
  270. days += div * DAYS_PER_100_YEARS
  271. div, mod = divmod(mod, 4)
  272. days += (div * DAYS_PER_4_YEARS) + (mod * 365)
  273. days += int(days_before[_m]) + _d
  274. s += i64(days) * SECONDS_PER_DAY
  275. s += i64(hour) * SECONDS_PER_HOUR
  276. s += i64(minute) * SECONDS_PER_MINUTE
  277. s += i64(second)
  278. t._nsec = (s * 1e9) + i64(nsec)
  279. return
  280. }
  281. days_before := [?]i32{
  282. 0,
  283. 31,
  284. 31 + 28,
  285. 31 + 28 + 31,
  286. 31 + 28 + 31 + 30,
  287. 31 + 28 + 31 + 30 + 31,
  288. 31 + 28 + 31 + 30 + 31 + 30,
  289. 31 + 28 + 31 + 30 + 31 + 30 + 31,
  290. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  291. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  292. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  293. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  294. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
  295. }
  296. SECONDS_PER_MINUTE :: 60
  297. SECONDS_PER_HOUR :: 60 * SECONDS_PER_MINUTE
  298. SECONDS_PER_DAY :: 24 * SECONDS_PER_HOUR
  299. SECONDS_PER_WEEK :: 7 * SECONDS_PER_DAY
  300. DAYS_PER_400_YEARS :: 365*400 + 97
  301. DAYS_PER_100_YEARS :: 365*100 + 24
  302. DAYS_PER_4_YEARS :: 365*4 + 1