liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

tai64.fnl (4227B)


      1 (local { : base64 : assoc } (require :anoia))
      2 (import-macros { : expect= : define-tests } :anoia.assert)
      3 
      4 (local
      5  leap-seconds-list
      6  (let [tbl
      7        [
      8         ;; https://data.iana.org/time-zones/data/leap-seconds.list
      9         ;; comments are the _start_ of the day where the second was
     10         ;; added at the end of the previous day
     11         [2272060800      10]   ;    1 jan 1972 ; baseline, not a leap second
     12         [2287785600      11]   ;    1 jul 1972
     13         [2303683200      12]   ;    1 jan 1973
     14         [2335219200      13]   ;    1 jan 1974
     15         [2366755200      14]   ;    1 Jan 1975
     16         [2398291200      15]   ;    1 Jan 1976
     17         [2429913600      16]   ;    1 Jan 1977
     18         [2461449600      17]   ;    1 Jan 1978
     19         [2492985600      18]   ;    1 Jan 1979
     20         [2524521600      19]   ;    1 Jan 1980
     21         [2571782400      20]   ;    1 Jul 1981
     22         [2603318400      21]   ;    1 Jul 1982
     23         [2634854400      22]   ;    1 Jul 1983
     24         [2698012800      23]   ;    1 Jul 1985
     25         [2776982400      24]   ;    1 Jan 1988
     26         [2840140800      25]   ;    1 Jan 1990
     27         [2871676800      26]   ;    1 Jan 1991
     28         [2918937600      27]   ;    1 Jul 1992
     29         [2950473600      28]   ;    1 Jul 1993
     30         [2982009600      29]   ;    1 Jul 1994
     31         [3029443200      30]   ;    1 Jan 1996
     32         [3076704000      31]   ;    1 Jul 1997
     33         [3124137600      32]   ;    1 Jan 1999
     34         [3345062400      33]   ;    1 Jan 2006
     35         [3439756800      34]   ;    1 Jan 2009
     36         [3550089600      35]   ;    1 Jul 2012
     37         [3644697600      36]   ;    1 Jul 2015
     38         [3692217600      37]   ;    1 Jan 2017
     39         ]]
     40    {
     41     :tai
     42     (icollect [_ [ts dtai] (ipairs tbl)]
     43       [(+ (- ts 2208988800) dtai) dtai])
     44     :unix
     45     (icollect [_ [ts dtai] (ipairs tbl)]
     46       [(- ts 2208988800) dtai])
     47     }))
     48 
     49 
     50 (fn leap-seconds [timestamp list]
     51   (accumulate [secs 10
     52                _ [epoch leap-seconds] (ipairs list)
     53                &until (> epoch timestamp)]
     54     leap-seconds))
     55 
     56 (fn leap-seconds-tai [tai] (leap-seconds tai leap-seconds-list.tai))
     57 (fn leap-seconds-unix [unix] (leap-seconds unix leap-seconds-list.unix))
     58 
     59 (define-tests :leap-seconds
     60   (expect= (leap-seconds-tai 104694412) 12)
     61   (expect= (leap-seconds-tai 23) 10)
     62   (expect= (leap-seconds-tai (+ 3692217600 60)) 37)
     63   (expect= (leap-seconds-tai (+ 10 773020829)) 29)
     64   (expect= (leap-seconds-tai 362793520) 19))
     65 
     66 (fn from-timestamp [str]
     67   (if (= (string.sub str 1 1) "@")
     68       (let [s (tonumber (string.sub str 2 17) 16)
     69             two_62 (lshift 1 62)
     70             sec (if (>= s two_62)
     71                     (- s two_62)
     72                     (- two_62 s))
     73             nano (tonumber (string.sub str 18 25) 16)]
     74         {:s sec :n nano})
     75       nil))
     76 
     77 (fn to-timestamp [{: s : n }]
     78   (let [label (+ s (lshift 1 62))]
     79     (string.format "@%16x%08x" label n)))
     80 
     81 (fn to-unix [tai]
     82   (values (- tai.s (leap-seconds-tai tai.s)) tai.n))
     83 
     84 (fn from-unix [seconds nanos]
     85   (let [s (math.floor seconds)
     86         ;; subsecond value may be given as fraction or as a separate
     87         ;; param, but not both
     88         n (or nanos (* (- seconds s) 1e9))]
     89     { :s
     90       (+ s (leap-seconds-unix s))
     91       :n n }))
     92 
     93 (define-tests
     94   (expect=
     95    (from-timestamp "@4000000068e2f0d3257dc09b")
     96    {:s 1759703251 :n 628998299})
     97 
     98   (expect=
     99    (to-timestamp {:s 1759703251 :n 628998299})
    100    "@4000000068e2f0d3257dc09b")
    101 
    102   (expect=
    103    (to-timestamp {:s -43200 :n 0})
    104    "@3fffffffffff574000000000")
    105 
    106   (let [(s n) (to-unix (from-timestamp "@4000000068e2f0d3257dc09b"))]
    107     (expect= [s n] [1759703214 628998299]))
    108 
    109   (let [{ : s : n } (from-unix 1759703214 1e6)]
    110     (expect= [s n] [1759703251 1e6]))
    111 
    112   (let [{ : s : n } (from-unix 1759703214.5)]
    113     (expect= [s n] [1759703251 5e8]))
    114 
    115   ;; check the leap second count is looked up correctly around a
    116   ;; boundary
    117   (let [unix (os.time {:year 2016 :month 12 :day 31 :hour 23 :min 59 :sec 58})
    118         tai (from-unix unix)]
    119     (expect= (- tai.s unix) 36))
    120   (let [unix (os.time {:year 2016 :month 12 :day 31 :hour 23 :min 59 :sec 63})
    121         tai (from-unix unix)]
    122     (expect= (- tai.s unix) 37))
    123   )
    124 
    125 
    126 { : from-timestamp : to-timestamp : to-unix : from-unix }