time.odin 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  1. package time
  2. import "base:intrinsics"
  3. import dt "core:time/datetime"
  4. /*
  5. Type representing duration, with nanosecond precision.
  6. This is the regular Unix timestamp, scaled to nanosecond precision.
  7. */
  8. Duration :: distinct i64
  9. /*
  10. The duration equal to one nanosecond (1e-9 seconds).
  11. */
  12. Nanosecond :: Duration(1)
  13. /*
  14. The duration equal to one microsecond (1e-6 seconds).
  15. */
  16. Microsecond :: 1000 * Nanosecond
  17. /*
  18. The duration equal to one millisecond (1e-3 seconds).
  19. */
  20. Millisecond :: 1000 * Microsecond
  21. /*
  22. The duration equal to one second.
  23. */
  24. Second :: 1000 * Millisecond
  25. /*
  26. The duration equal to one minute (60 seconds).
  27. */
  28. Minute :: 60 * Second
  29. /*
  30. The duration equal to one hour (3600 seconds).
  31. */
  32. Hour :: 60 * Minute
  33. /*
  34. Minimum representable duration.
  35. */
  36. MIN_DURATION :: Duration(-1 << 63)
  37. /*
  38. Maximum representable duration.
  39. */
  40. MAX_DURATION :: Duration(1<<63 - 1)
  41. /*
  42. Value specifying whether the time procedures are supported by the current
  43. platform.
  44. */
  45. IS_SUPPORTED :: _IS_SUPPORTED
  46. /*
  47. Specifies time since the UNIX epoch, with nanosecond precision.
  48. Capable of representing any time within the following range:
  49. - `min: 1677-09-21 00:12:44.145224192 +0000 UTC`
  50. - `max: 2262-04-11 23:47:16.854775807 +0000 UTC`
  51. */
  52. Time :: struct {
  53. _nsec: i64, // Measured in UNIX nanonseconds
  54. }
  55. /*
  56. Type representing a month.
  57. */
  58. Month :: enum int {
  59. January = 1,
  60. February,
  61. March,
  62. April,
  63. May,
  64. June,
  65. July,
  66. August,
  67. September,
  68. October,
  69. November,
  70. December,
  71. }
  72. /*
  73. Type representing a weekday.
  74. */
  75. Weekday :: enum int {
  76. Sunday = 0,
  77. Monday,
  78. Tuesday,
  79. Wednesday,
  80. Thursday,
  81. Friday,
  82. Saturday,
  83. }
  84. /*
  85. Type representing a stopwatch.
  86. The stopwatch is used for measuring the total time in multiple "runs". When the
  87. stopwatch is started, it starts counting time. When the stopwatch is stopped,
  88. the difference in time between the last start and the stop is added to the
  89. total. When the stopwatch resets, the total is reset.
  90. */
  91. Stopwatch :: struct {
  92. running: bool,
  93. _start_time: Tick,
  94. _accumulation: Duration,
  95. }
  96. /*
  97. Obtain the current time.
  98. */
  99. now :: proc "contextless" () -> Time {
  100. return _now()
  101. }
  102. /*
  103. Sleep for the specified duration.
  104. */
  105. sleep :: proc "contextless" (d: Duration) {
  106. _sleep(d)
  107. }
  108. /*
  109. Start the stopwatch.
  110. */
  111. stopwatch_start :: proc "contextless" (stopwatch: ^Stopwatch) {
  112. if !stopwatch.running {
  113. stopwatch._start_time = tick_now()
  114. stopwatch.running = true
  115. }
  116. }
  117. /*
  118. Stop the stopwatch.
  119. */
  120. stopwatch_stop :: proc "contextless" (stopwatch: ^Stopwatch) {
  121. if stopwatch.running {
  122. stopwatch._accumulation += tick_diff(stopwatch._start_time, tick_now())
  123. stopwatch.running = false
  124. }
  125. }
  126. /*
  127. Reset the stopwatch.
  128. */
  129. stopwatch_reset :: proc "contextless" (stopwatch: ^Stopwatch) {
  130. stopwatch._accumulation = {}
  131. stopwatch.running = false
  132. }
  133. /*
  134. Obtain the total time, counted by the stopwatch.
  135. This procedure obtains the total time, counted by the stopwatch. If the stopwatch
  136. isn't stopped at the time of calling this procedure, the time between the last
  137. start and the current time is also accounted for.
  138. */
  139. stopwatch_duration :: proc "contextless" (stopwatch: Stopwatch) -> Duration {
  140. if !stopwatch.running {
  141. return stopwatch._accumulation
  142. }
  143. return stopwatch._accumulation + tick_diff(stopwatch._start_time, tick_now())
  144. }
  145. /*
  146. Calculate the duration elapsed between two times.
  147. */
  148. diff :: proc "contextless" (start, end: Time) -> Duration {
  149. d := end._nsec - start._nsec
  150. return Duration(d)
  151. }
  152. /*
  153. Calculate the duration elapsed since a specific time.
  154. */
  155. since :: proc "contextless" (start: Time) -> Duration {
  156. return diff(start, now())
  157. }
  158. /*
  159. Obtain the number of nanoseconds in a duration.
  160. */
  161. duration_nanoseconds :: proc "contextless" (d: Duration) -> i64 {
  162. return i64(d)
  163. }
  164. /*
  165. Obtain the number of microseconds in a duration.
  166. */
  167. duration_microseconds :: proc "contextless" (d: Duration) -> f64 {
  168. return duration_seconds(d) * 1e6
  169. }
  170. /*
  171. Obtain the number of milliseconds in a duration.
  172. */
  173. duration_milliseconds :: proc "contextless" (d: Duration) -> f64 {
  174. return duration_seconds(d) * 1e3
  175. }
  176. /*
  177. Obtain the number of seconds in a duration.
  178. */
  179. duration_seconds :: proc "contextless" (d: Duration) -> f64 {
  180. sec := d / Second
  181. nsec := d % Second
  182. return f64(sec) + f64(nsec)/1e9
  183. }
  184. /*
  185. Obtain the number of minutes in a duration.
  186. */
  187. duration_minutes :: proc "contextless" (d: Duration) -> f64 {
  188. min := d / Minute
  189. nsec := d % Minute
  190. return f64(min) + f64(nsec)/(60*1e9)
  191. }
  192. /*
  193. Obtain the number of hours in a duration.
  194. */
  195. duration_hours :: proc "contextless" (d: Duration) -> f64 {
  196. hour := d / Hour
  197. nsec := d % Hour
  198. return f64(hour) + f64(nsec)/(60*60*1e9)
  199. }
  200. /*
  201. Round a duration to a specific unit
  202. This procedure rounds the duration to a specific unit
  203. **Note**: Any duration can be supplied as a unit.
  204. Inputs:
  205. - d: The duration to round
  206. - m: The unit to round to
  207. Returns:
  208. - The duration `d`, rounded to the unit specified by `m`
  209. Example:
  210. time.duration_round(my_duration, time.Second)
  211. */
  212. duration_round :: proc "contextless" (d, m: Duration) -> Duration {
  213. _less_than_half :: #force_inline proc "contextless" (x, y: Duration) -> bool {
  214. return u64(x)+u64(x) < u64(y)
  215. }
  216. if m <= 0 {
  217. return d
  218. }
  219. r := d % m
  220. if d < 0 {
  221. r = -r
  222. if _less_than_half(r, m) {
  223. return d + r
  224. }
  225. if d1 := d-m+r; d1 < d {
  226. return d1
  227. }
  228. return MIN_DURATION
  229. }
  230. if _less_than_half(r, m) {
  231. return d - r
  232. }
  233. if d1 := d+m-r; d1 > d {
  234. return d1
  235. }
  236. return MAX_DURATION
  237. }
  238. /*
  239. Truncate the duration to the specified unit.
  240. This procedure truncates the duration `d` to the unit specified by `m`.
  241. **Note**: Any duration can be supplied as a unit.
  242. Inputs:
  243. - d: The duration to truncate.
  244. - m: The unit to truncate to.
  245. Returns:
  246. - The duration `d`, truncated to the unit specified by `m`.
  247. Example:
  248. time.duration_round(my_duration, time.Second)
  249. */
  250. duration_truncate :: proc "contextless" (d, m: Duration) -> Duration {
  251. return d if m <= 0 else d - d%m
  252. }
  253. /*
  254. Parse time into date components.
  255. */
  256. date :: proc "contextless" (t: Time) -> (year: int, month: Month, day: int) {
  257. year, month, day, _ = _abs_date(_time_abs(t), true)
  258. return
  259. }
  260. /*
  261. Obtain the year of the date specified by time.
  262. */
  263. year :: proc "contextless" (t: Time) -> (year: int) {
  264. year, _, _, _ = _date(t, true)
  265. return
  266. }
  267. /*
  268. Obtain the month of the date specified by time.
  269. */
  270. month :: proc "contextless" (t: Time) -> (month: Month) {
  271. _, month, _, _ = _date(t, true)
  272. return
  273. }
  274. /*
  275. Obtain the day of the date specified by time.
  276. */
  277. day :: proc "contextless" (t: Time) -> (day: int) {
  278. _, _, day, _ = _date(t, true)
  279. return
  280. }
  281. /*
  282. Obtain the week day of the date specified by time.
  283. */
  284. weekday :: proc "contextless" (t: Time) -> (weekday: Weekday) {
  285. abs := _time_abs(t)
  286. sec := (abs + u64(Weekday.Monday) * SECONDS_PER_DAY) % SECONDS_PER_WEEK
  287. return Weekday(int(sec) / SECONDS_PER_DAY)
  288. }
  289. /*
  290. Obtain the time components from a time, a duration or a stopwatch's total.
  291. */
  292. clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
  293. /*
  294. Obtain the time components from a time, a duration or a stopwatch's total, including nanoseconds.
  295. */
  296. precise_clock :: proc { precise_clock_from_time, precise_clock_from_duration, precise_clock_from_stopwatch }
  297. /*
  298. Obtain the time components from a time.
  299. */
  300. clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec: int) {
  301. hour, min, sec, _ = precise_clock_from_time(t)
  302. return
  303. }
  304. /*
  305. Obtain the time components from a time, including nanoseconds.
  306. */
  307. precise_clock_from_time :: proc "contextless" (t: Time) -> (hour, min, sec, nanos: int) {
  308. // Time in nanoseconds since 1-1-1970 00:00
  309. _sec, _nanos := t._nsec / 1e9, t._nsec % 1e9
  310. _sec += INTERNAL_TO_ABSOLUTE
  311. nanos = int(_nanos)
  312. sec = int(_sec % SECONDS_PER_DAY)
  313. hour = sec / SECONDS_PER_HOUR
  314. sec -= hour * SECONDS_PER_HOUR
  315. min = sec / SECONDS_PER_MINUTE
  316. sec -= min * SECONDS_PER_MINUTE
  317. return
  318. }
  319. /*
  320. Obtain the time components from a duration.
  321. */
  322. clock_from_duration :: proc "contextless" (d: Duration) -> (hour, min, sec: int) {
  323. return clock_from_seconds(u64(d/1e9))
  324. }
  325. /*
  326. Obtain the time components from a duration, including nanoseconds.
  327. */
  328. precise_clock_from_duration :: proc "contextless" (d: Duration) -> (hour, min, sec, nanos: int) {
  329. return precise_clock_from_time({_nsec=i64(d)})
  330. }
  331. /*
  332. Obtain the time components from a stopwatch's total.
  333. */
  334. clock_from_stopwatch :: proc "contextless" (s: Stopwatch) -> (hour, min, sec: int) {
  335. return clock_from_duration(stopwatch_duration(s))
  336. }
  337. /*
  338. Obtain the time components from a stopwatch's total, including nanoseconds
  339. */
  340. precise_clock_from_stopwatch :: proc "contextless" (s: Stopwatch) -> (hour, min, sec, nanos: int) {
  341. return precise_clock_from_duration(stopwatch_duration(s))
  342. }
  343. /*
  344. Obtain the time components from the number of seconds.
  345. */
  346. clock_from_seconds :: proc "contextless" (in_sec: u64) -> (hour, min, sec: int) {
  347. sec = int(in_sec % SECONDS_PER_DAY)
  348. hour = sec / SECONDS_PER_HOUR
  349. sec -= hour * SECONDS_PER_HOUR
  350. min = sec / SECONDS_PER_MINUTE
  351. sec -= min * SECONDS_PER_MINUTE
  352. return
  353. }
  354. MIN_HMS_LEN :: 8
  355. MIN_HMS_12_LEN :: 11
  356. MIN_YYYY_DATE_LEN :: 10
  357. MIN_YY_DATE_LEN :: 8
  358. /*
  359. Formats a `Time` as a 24-hour `hh:mm:ss` string.
  360. **Does not allocate**
  361. Inputs:
  362. - t: The Time to format.
  363. - buf: The backing buffer to use.
  364. Returns:
  365. - res: The formatted string, backed by buf
  366. Example:
  367. buf: [MIN_HMS_LEN]u8
  368. now := time.now()
  369. fmt.println(time.to_string_hms(now, buf[:]))
  370. */
  371. time_to_string_hms :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check {
  372. assert(len(buf) >= MIN_HMS_LEN)
  373. h, m, s := clock(t)
  374. buf[7] = '0' + u8(s % 10); s /= 10
  375. buf[6] = '0' + u8(s)
  376. buf[5] = ':'
  377. buf[4] = '0' + u8(m % 10); m /= 10
  378. buf[3] = '0' + u8(m)
  379. buf[2] = ':'
  380. buf[1] = '0' + u8(h % 10); h /= 10
  381. buf[0] = '0' + u8(h)
  382. return string(buf[:MIN_HMS_LEN])
  383. }
  384. /*
  385. Formats a `Duration` as a 24-hour `hh:mm:ss` string.
  386. **Does not allocate**
  387. Inputs:
  388. - d: The Duration to format.
  389. - buf: The backing buffer to use.
  390. Returns:
  391. - res: The formatted string, backed by buf
  392. Example:
  393. buf: [MIN_HMS_LEN]u8
  394. d := time.since(earlier)
  395. fmt.println(time.to_string_hms(now, buf[:]))
  396. */
  397. duration_to_string_hms :: proc(d: Duration, buf: []u8) -> (res: string) #no_bounds_check {
  398. return time_to_string_hms(Time{_nsec=i64(d)}, buf)
  399. }
  400. to_string_hms :: proc{time_to_string_hms, duration_to_string_hms}
  401. /*
  402. Formats a `Time` as a 12-hour `hh:mm:ss pm` string
  403. **Does not allocate**
  404. Inputs:
  405. - t: The Time to format
  406. - buf: The backing buffer to use
  407. - ampm: An optional pair of am/pm strings to use in place of the default
  408. Returns:
  409. - res: The formatted string, backed by buf
  410. Example:
  411. buf: [64]u8
  412. now := time.now()
  413. fmt.println(time.to_string_hms_12(now, buf[:]))
  414. fmt.println(time.to_string_hms_12(now, buf[:], {"㏂", "㏘"}))
  415. */
  416. to_string_hms_12 :: proc(t: Time, buf: []u8, ampm: [2]string = {" am", " pm"}) -> (res: string) #no_bounds_check {
  417. assert(len(buf) >= MIN_HMS_LEN + max(len(ampm[0]), len(ampm[1])))
  418. h, m, s := clock(t)
  419. _h := h % 12
  420. buf[7] = '0' + u8(s % 10); s /= 10
  421. buf[6] = '0' + u8(s)
  422. buf[5] = ':'
  423. buf[4] = '0' + u8(m % 10); m /= 10
  424. buf[3] = '0' + u8(m)
  425. buf[2] = ':'
  426. buf[1] = '0' + u8(_h% 10); _h /= 10
  427. buf[0] = '0' + u8(_h)
  428. if h < 13 {
  429. copy(buf[8:], ampm[0])
  430. return string(buf[:MIN_HMS_LEN+len(ampm[0])])
  431. } else {
  432. copy(buf[8:], ampm[1])
  433. return string(buf[:MIN_HMS_LEN+len(ampm[1])])
  434. }
  435. }
  436. /*
  437. Formats a Time as a yyyy-mm-dd date string.
  438. Inputs:
  439. - t: The Time to format.
  440. - buf: The backing buffer to use.
  441. Returns:
  442. - res: The formatted string, backed by `buf`.
  443. Example:
  444. buf: [MIN_YYYY_DATE_LEN]u8
  445. now := time.now()
  446. fmt.println(time.to_string_yyyy_mm_dd(now, buf[:]))
  447. */
  448. to_string_yyyy_mm_dd :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check {
  449. assert(len(buf) >= MIN_YYYY_DATE_LEN)
  450. y, _m, d := date(t)
  451. m := u8(_m)
  452. buf[9] = '0' + u8(d % 10); d /= 10
  453. buf[8] = '0' + u8(d % 10)
  454. buf[7] = '-'
  455. buf[6] = '0' + u8(m % 10); m /= 10
  456. buf[5] = '0' + u8(m % 10)
  457. buf[4] = '-'
  458. buf[3] = '0' + u8(y % 10); y /= 10
  459. buf[2] = '0' + u8(y % 10); y /= 10
  460. buf[1] = '0' + u8(y % 10); y /= 10
  461. buf[0] = '0' + u8(y)
  462. return string(buf[:MIN_YYYY_DATE_LEN])
  463. }
  464. /*
  465. Formats a Time as a yy-mm-dd date string.
  466. Inputs:
  467. - t: The Time to format.
  468. - buf: The backing buffer to use.
  469. Returns:
  470. - res: The formatted string, backed by `buf`.
  471. Example:
  472. buf: [MIN_YY_DATE_LEN]u8
  473. now := time.now()
  474. fmt.println(time.to_string_yy_mm_dd(now, buf[:]))
  475. */
  476. to_string_yy_mm_dd :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check {
  477. assert(len(buf) >= MIN_YY_DATE_LEN)
  478. y, _m, d := date(t)
  479. y %= 100; m := u8(_m)
  480. buf[7] = '0' + u8(d % 10); d /= 10
  481. buf[6] = '0' + u8(d % 10)
  482. buf[5] = '-'
  483. buf[4] = '0' + u8(m % 10); m /= 10
  484. buf[3] = '0' + u8(m % 10)
  485. buf[2] = '-'
  486. buf[1] = '0' + u8(y % 10); y /= 10
  487. buf[0] = '0' + u8(y)
  488. return string(buf[:MIN_YY_DATE_LEN])
  489. }
  490. /*
  491. Formats a Time as a dd-mm-yyyy date string.
  492. Inputs:
  493. - t: The Time to format.
  494. - buf: The backing buffer to use.
  495. Returns:
  496. - res: The formatted string, backed by `buf`.
  497. Example:
  498. buf: [MIN_YYYY_DATE_LEN]u8
  499. now := time.now()
  500. fmt.println(time.to_string_dd_mm_yyyy(now, buf[:]))
  501. */
  502. to_string_dd_mm_yyyy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check {
  503. assert(len(buf) >= MIN_YYYY_DATE_LEN)
  504. y, _m, d := date(t)
  505. m := u8(_m)
  506. buf[9] = '0' + u8(y % 10); y /= 10
  507. buf[8] = '0' + u8(y % 10); y /= 10
  508. buf[7] = '0' + u8(y % 10); y /= 10
  509. buf[6] = '0' + u8(y)
  510. buf[5] = '-'
  511. buf[4] = '0' + u8(m % 10); m /= 10
  512. buf[3] = '0' + u8(m % 10)
  513. buf[2] = '-'
  514. buf[1] = '0' + u8(d % 10); d /= 10
  515. buf[0] = '0' + u8(d % 10)
  516. return string(buf[:MIN_YYYY_DATE_LEN])
  517. }
  518. /*
  519. Formats a Time as a dd-mm-yy date string.
  520. Inputs:
  521. - t: The Time to format.
  522. - buf: The backing buffer to use.
  523. Returns:
  524. - res: The formatted string, backed by `buf`.
  525. Example:
  526. buf: [MIN_YY_DATE_LEN]u8
  527. now := time.now()
  528. fmt.println(time.to_string_dd_mm_yy(now, buf[:]))
  529. */
  530. to_string_dd_mm_yy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check {
  531. assert(len(buf) >= MIN_YY_DATE_LEN)
  532. y, _m, d := date(t)
  533. y %= 100; m := u8(_m)
  534. buf[7] = '0' + u8(y % 10); y /= 10
  535. buf[6] = '0' + u8(y)
  536. buf[5] = '-'
  537. buf[4] = '0' + u8(m % 10); m /= 10
  538. buf[3] = '0' + u8(m % 10)
  539. buf[2] = '-'
  540. buf[1] = '0' + u8(d % 10); d /= 10
  541. buf[0] = '0' + u8(d % 10)
  542. return string(buf[:MIN_YY_DATE_LEN])
  543. }
  544. /*
  545. Formats a Time as a mm-dd-yyyy date string.
  546. Inputs:
  547. - t: The Time to format.
  548. - buf: The backing buffer to use.
  549. Returns:
  550. - res: The formatted string, backed by `buf`.
  551. Example:
  552. buf: [MIN_YYYY_DATE_LEN]u8
  553. now := time.now()
  554. fmt.println(time.to_string_mm_dd_yyyy(now, buf[:]))
  555. */
  556. to_string_mm_dd_yyyy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check {
  557. assert(len(buf) >= MIN_YYYY_DATE_LEN)
  558. y, _m, d := date(t)
  559. m := u8(_m)
  560. buf[9] = '0' + u8(y % 10); y /= 10
  561. buf[8] = '0' + u8(y % 10); y /= 10
  562. buf[7] = '0' + u8(y % 10); y /= 10
  563. buf[6] = '0' + u8(y)
  564. buf[5] = '-'
  565. buf[4] = '0' + u8(d % 10); d /= 10
  566. buf[3] = '0' + u8(d % 10)
  567. buf[2] = '-'
  568. buf[1] = '0' + u8(m % 10); m /= 10
  569. buf[0] = '0' + u8(m % 10)
  570. return string(buf[:MIN_YYYY_DATE_LEN])
  571. }
  572. /*
  573. Formats a Time as a mm-dd-yy date string.
  574. Inputs:
  575. - t: The Time to format.
  576. - buf: The backing buffer to use.
  577. Returns:
  578. - res: The formatted string, backed by `buf`.
  579. Example:
  580. buf: [MIN_YY_DATE_LEN]u8
  581. now := time.now()
  582. fmt.println(time.to_string_mm_dd_yy(now, buf[:]))
  583. */
  584. to_string_mm_dd_yy :: proc(t: Time, buf: []u8) -> (res: string) #no_bounds_check {
  585. assert(len(buf) >= MIN_YY_DATE_LEN)
  586. y, _m, d := date(t)
  587. y %= 100; m := u8(_m)
  588. buf[7] = '0' + u8(y % 10); y /= 10
  589. buf[6] = '0' + u8(y)
  590. buf[5] = '-'
  591. buf[4] = '0' + u8(d % 10); d /= 10
  592. buf[3] = '0' + u8(d % 10)
  593. buf[2] = '-'
  594. buf[1] = '0' + u8(m % 10); m /= 10
  595. buf[0] = '0' + u8(m % 10)
  596. return string(buf[:MIN_YY_DATE_LEN])
  597. }
  598. /*
  599. Read the timestamp counter of the CPU.
  600. */
  601. read_cycle_counter :: proc "contextless" () -> u64 {
  602. return u64(intrinsics.read_cycle_counter())
  603. }
  604. /*
  605. Obtain time from unix seconds and unix nanoseconds.
  606. */
  607. unix :: proc "contextless" (sec: i64, nsec: i64) -> Time {
  608. sec, nsec := sec, nsec
  609. if nsec < 0 || nsec >= 1e9 {
  610. n := nsec / 1e9
  611. sec += n
  612. nsec -= n * 1e9
  613. if nsec < 0 {
  614. nsec += 1e9
  615. sec -= 1
  616. }
  617. }
  618. return Time{(sec*1e9 + nsec)}
  619. }
  620. /*
  621. Obtain time from unix nanoseconds.
  622. */
  623. from_nanoseconds :: #force_inline proc "contextless" (nsec: i64) -> Time {
  624. return Time{nsec}
  625. }
  626. /*
  627. Alias for `time_to_unix`.
  628. */
  629. to_unix_seconds :: time_to_unix
  630. /*
  631. Obtain the Unix timestamp in seconds from a Time.
  632. */
  633. time_to_unix :: proc "contextless" (t: Time) -> i64 {
  634. return t._nsec/1e9
  635. }
  636. /*
  637. Alias for `time_to_unix_nano`.
  638. */
  639. to_unix_nanoseconds :: time_to_unix_nano
  640. /*
  641. Obtain the Unix timestamp in nanoseconds from a Time.
  642. */
  643. time_to_unix_nano :: proc "contextless" (t: Time) -> i64 {
  644. return t._nsec
  645. }
  646. /*
  647. Add duration to a time.
  648. */
  649. time_add :: proc "contextless" (t: Time, d: Duration) -> Time {
  650. return Time{t._nsec + i64(d)}
  651. }
  652. /*
  653. Accurate sleep
  654. This procedure sleeps for the duration specified by `d`, very accurately.
  655. **Note**: Implementation borrowed from: [this source](https://blat-blatnik.github.io/computerBear/making-accurate-sleep-function/)
  656. **Note(linux)**: The accuracy is within around 4µs (microseconds), in the worst case.
  657. **Note(windows)**: The accuracy depends but is comparable with regular sleep in
  658. the worst case. To get the same kind of accuracy as on Linux, have your program
  659. call `windows.timeBeginPeriod(1)` to tell Windows to use a more accurate timer
  660. for your process. Additionally your program should call `windows.timeEndPeriod(1)`
  661. once you're done with `accurate_sleep`.
  662. */
  663. accurate_sleep :: proc "contextless" (d: Duration) {
  664. to_sleep, estimate, mean, m2, count: Duration
  665. to_sleep = d
  666. estimate = 5 * Millisecond
  667. mean = 5 * Millisecond
  668. count = 1
  669. for to_sleep > estimate {
  670. start := tick_now()
  671. sleep(1 * Millisecond)
  672. observed := tick_since(start)
  673. to_sleep -= observed
  674. count += 1
  675. delta := observed - mean
  676. mean += delta / count
  677. m2 += delta * (observed - mean)
  678. stddev := intrinsics.sqrt(f64(m2) / f64(count - 1))
  679. estimate = mean + Duration(stddev)
  680. }
  681. start := tick_now()
  682. for to_sleep > tick_since(start) {
  683. // prevent the spinlock from taking the thread hostage, still accurate enough
  684. _yield()
  685. // NOTE: it might be possible that it yields for too long, in that case it should spinlock freely for a while
  686. // TODO: needs actual testing done to check if that's the case
  687. }
  688. }
  689. ABSOLUTE_ZERO_YEAR :: i64(-292277022399) // Day is chosen so that 2001-01-01 is Monday in the calculations
  690. ABSOLUTE_TO_INTERNAL :: i64(-9223371966579724800) // i64((ABSOLUTE_ZERO_YEAR - 1) * 365.2425 * SECONDS_PER_DAY);
  691. INTERNAL_TO_ABSOLUTE :: -ABSOLUTE_TO_INTERNAL
  692. UNIX_TO_INTERNAL :: i64((1969*365 + 1969/4 - 1969/100 + 1969/400) * SECONDS_PER_DAY)
  693. INTERNAL_TO_UNIX :: -UNIX_TO_INTERNAL
  694. WALL_TO_INTERNAL :: i64((1884*365 + 1884/4 - 1884/100 + 1884/400) * SECONDS_PER_DAY)
  695. INTERNAL_TO_WALL :: -WALL_TO_INTERNAL
  696. UNIX_TO_ABSOLUTE :: UNIX_TO_INTERNAL + INTERNAL_TO_ABSOLUTE
  697. ABSOLUTE_TO_UNIX :: -UNIX_TO_ABSOLUTE
  698. @(private)
  699. _date :: proc "contextless" (t: Time, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  700. year, month, day, yday = _abs_date(_time_abs(t), full)
  701. return
  702. }
  703. @(private)
  704. _time_abs :: proc "contextless" (t: Time) -> u64 {
  705. return u64(t._nsec/1e9 + UNIX_TO_ABSOLUTE)
  706. }
  707. @(private)
  708. _abs_date :: proc "contextless" (abs: u64, full: bool) -> (year: int, month: Month, day: int, yday: int) {
  709. d := abs / SECONDS_PER_DAY
  710. // 400 year cycles
  711. n := d / DAYS_PER_400_YEARS
  712. y := 400 * n
  713. d -= DAYS_PER_400_YEARS * n
  714. // Cut-off 100 year cycles
  715. n = d / DAYS_PER_100_YEARS
  716. n -= n >> 2
  717. y += 100 * n
  718. d -= DAYS_PER_100_YEARS * n
  719. // Cut-off 4 year cycles
  720. n = d / DAYS_PER_4_YEARS
  721. y += 4 * n
  722. d -= DAYS_PER_4_YEARS * n
  723. n = d / 365
  724. n -= n >> 2
  725. y += n
  726. d -= 365 * n
  727. year = int(i64(y) + ABSOLUTE_ZERO_YEAR)
  728. yday = int(d)
  729. if !full {
  730. return
  731. }
  732. day = yday
  733. if is_leap_year(year) {
  734. switch {
  735. case day > 31+29-1:
  736. day -= 1
  737. case day == 31+29-1:
  738. month = .February
  739. day = 29
  740. return
  741. }
  742. }
  743. month = Month(day / 31)
  744. end := int(days_before[int(month)+1])
  745. begin: int
  746. if day >= end {
  747. (^int)(&month)^ += 1
  748. begin = end
  749. } else {
  750. begin = int(days_before[month])
  751. }
  752. (^int)(&month)^ += 1 // January is 1
  753. day = day - begin + 1
  754. return
  755. }
  756. /*
  757. Convert datetime components into time.
  758. This procedure calculates the time from datetime components supplied in the
  759. arguments to this procedure. If the datetime components don't represent a valid
  760. datetime, the function returns `false` in the second argument.
  761. */
  762. components_to_time :: proc "contextless" (#any_int year, #any_int month, #any_int day, #any_int hour, #any_int minute, #any_int second: i64, #any_int nsec := i64(0)) -> (t: Time, ok: bool) {
  763. this_date, err := dt.components_to_datetime(year, month, day, hour, minute, second, nsec)
  764. if err != .None {
  765. return
  766. }
  767. return compound_to_time(this_date)
  768. }
  769. /*
  770. Convert datetime into time.
  771. If the datetime represents a time outside of a valid range, `false` is returned
  772. as the second return value. See `Time` for the representable range.
  773. */
  774. compound_to_time :: proc "contextless" (datetime: dt.DateTime) -> (t: Time, ok: bool) {
  775. unix_epoch := dt.DateTime{{1970, 1, 1}, {0, 0, 0, 0}, nil}
  776. delta, err := dt.sub(datetime, unix_epoch)
  777. if err != .None {
  778. return
  779. }
  780. seconds := delta.days * 86_400 + delta.seconds
  781. // Can this moment be represented in i64 worth of nanoseconds?
  782. // min(Time): 1677-09-21 00:12:44.145224192 +0000 UTC
  783. // max(Time): 2262-04-11 23:47:16.854775807 +0000 UTC
  784. if seconds < -9223372036 || (seconds == -9223372036 && delta.nanos < -854775808) {
  785. return {}, false
  786. }
  787. if seconds > 9223372036 || (seconds == 9223372036 && delta.nanos > 854775807) {
  788. return {}, false
  789. }
  790. return Time{_nsec=seconds * 1e9 + delta.nanos}, true
  791. }
  792. /*
  793. Convert datetime components into time.
  794. */
  795. datetime_to_time :: proc{components_to_time, compound_to_time}
  796. /*
  797. Convert time into datetime.
  798. */
  799. time_to_datetime :: proc "contextless" (t: Time) -> (dt.DateTime, bool) {
  800. unix_epoch := dt.DateTime{{1970, 1, 1}, {0, 0, 0, 0}, nil}
  801. datetime, err := dt.add(unix_epoch, dt.Delta{ nanos = t._nsec })
  802. if err != .None {
  803. return {}, false
  804. }
  805. return datetime, true
  806. }
  807. /*
  808. Alias for `time_to_datetime`.
  809. */
  810. time_to_compound :: time_to_datetime
  811. /*
  812. Check if a year is a leap year.
  813. */
  814. is_leap_year :: proc "contextless" (year: int) -> (leap: bool) {
  815. return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
  816. }
  817. /*
  818. Days before each month in a year, not counting the leap day on february 29th.
  819. */
  820. @(rodata)
  821. days_before := [?]i32{
  822. 0,
  823. 31,
  824. 31 + 28,
  825. 31 + 28 + 31,
  826. 31 + 28 + 31 + 30,
  827. 31 + 28 + 31 + 30 + 31,
  828. 31 + 28 + 31 + 30 + 31 + 30,
  829. 31 + 28 + 31 + 30 + 31 + 30 + 31,
  830. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  831. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  832. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  833. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  834. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
  835. }
  836. /*
  837. Number of seconds in a minute (without leap seconds).
  838. */
  839. SECONDS_PER_MINUTE :: 60
  840. /*
  841. Number of seconds in an hour (without leap seconds).
  842. */
  843. SECONDS_PER_HOUR :: 60 * SECONDS_PER_MINUTE
  844. /*
  845. Number of seconds in a day (without leap seconds).
  846. */
  847. SECONDS_PER_DAY :: 24 * SECONDS_PER_HOUR
  848. /*
  849. Number of seconds in a week (without leap seconds).
  850. */
  851. SECONDS_PER_WEEK :: 7 * SECONDS_PER_DAY
  852. /*
  853. Days in 400 years, with leap days.
  854. */
  855. DAYS_PER_400_YEARS :: 365*400 + 97
  856. /*
  857. Days in 100 years, with leap days.
  858. */
  859. DAYS_PER_100_YEARS :: 365*100 + 24
  860. /*
  861. Days in 4 years, with leap days.
  862. */
  863. DAYS_PER_4_YEARS :: 365*4 + 1