cripslock

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

lib.fnl (3062B)


      1 (import-macros { : define-tests : expect : expect= } :assert)
      2 (local { : view} (require :fennel))
      3 
      4 
      5 (fn prepend [head tbl]
      6   (if tbl
      7       (doto tbl
      8         (table.insert 1 head))
      9       [head]))
     10 
     11 (fn clone [tbl]
     12   (collect [k v (pairs tbl)] (values k v)))
     13 
     14 
     15 (fn string-stream []
     16   (let [strings []]
     17     {
     18      :write #(table.insert strings $2)
     19      :to-string #(table.concat strings)
     20      }))
     21 
     22 (fn trace [x] (print :trace (view x)) x)
     23 
     24 
     25 ;; there are two date formats used in most of the extant posts:
     26 ;; "Fri Jun 29 14:17:56 2018" (emacs current-time-string)
     27 ;; and "Fri, 18 Oct 2013 10:18:34 +0100" (*rfc2822")
     28 
     29 (local months
     30        {"jan" 1
     31         "feb" 2
     32         "mar" 3
     33         "apr" 4
     34         "may" 5
     35         "jun" 6
     36         "jul" 7
     37         "aug" 8
     38         "sep" 9
     39         "oct" 10
     40         "nov" 11
     41         "dec" 12
     42         })
     43 
     44 (fn parse-rfc2822-timestamp [date-str]
     45   (let [(s _ weekday day month year hour min sec offset)
     46         (string.find date-str "(%a+), (%d+) (%a+) (%d+) (%d+):(%d+):(%d+) ([+-]%d+)" 1)]
     47     (and s
     48          (os.time {
     49                    : year
     50                    :month (. months (string.lower month))
     51                    : day
     52                    : hour
     53                    : min
     54                    : sec
     55                    :isdst (not (= offset "+0000")) ;; massive cheating here
     56                    }))))
     57 
     58 (fn parse-emacs-timestamp [date-str]
     59   (let [(s _ weekday month day hour min sec  year)
     60         (string.find date-str "(%a+) (%a+) +(%d+) (%d+):(%d+):(%d+) (%d+)" 1)]
     61     (and s
     62          (os.time {
     63                    : year
     64                    :month (. months (string.lower month))
     65                    : day
     66                    : hour
     67                    : min
     68                    : sec
     69                    :isdst true ; probably?
     70                    }))))
     71 
     72 (fn parse-iso-timestamp [date-str]
     73   (let [(s _ year month day hour min sec frac)
     74         (string.find date-str "(%d+)%-(%d+)%-(%d+)[T ](%d+):(%d+):(%d+)%.(%d+) -Z")]
     75     (and s
     76          (os.time {
     77                    : year
     78                    : month
     79                    : day
     80                    : hour
     81                    : min
     82                    : sec
     83                    :isdst false
     84                    }))))
     85 
     86 (fn parse-timestamp [s]
     87   (or (parse-iso-timestamp s)
     88       (parse-rfc2822-timestamp s)
     89       (parse-emacs-timestamp s)))
     90 
     91 (define-tests :date-parsing
     92   (expect= (parse-rfc2822-timestamp "Fri, 18 Oct 2013 10:18:34 +0100")
     93            1382087914)
     94   (expect= (parse-rfc2822-timestamp "Tue, 28 Dec 2004 21:41:24 +0000")
     95            1104270084)
     96   (expect= (parse-emacs-timestamp "Sat Jul 19 23:53:21 2025") 1752965601)
     97   (expect= (parse-rfc2822-timestamp "Sat Jul 19 23:53:21 2025") nil)
     98   (expect= (parse-timestamp "Sat Jul 19 23:53:21 2025") 1752965601)
     99   (expect= (parse-timestamp "Wed Aug  8 12:51:52 2018") 1533729112)
    100 
    101   (expect= (parse-timestamp "2024-05-08T12:46:56.865432Z") 1715172416)
    102 
    103   (expect= (parse-timestamp "2023-10-03 19:10:23.000000000 Z") 1696360223)
    104 
    105 
    106   )
    107 
    108 
    109 
    110 
    111 {
    112  : prepend : string-stream : trace "%%" string.format
    113  : clone
    114  : parse-timestamp
    115  }