(module iso-8601 mzscheme ; This module contains the beginnings of a generic ISO 8601 date/time parser. ; The eventual aim is to have a procedure that turns any ISO 8601 string into ; some uniform data structure. ; This module: ; - WILL support dates, times and date/time combinations; ; - WILL support timezones; ; - WILL support up to 9 optional fractional digits on seconds; ; - WILL NOT support hyphen-prefixed abbreviations; ; - WILL NOT support periods of time. (require (lib "pregexp.ss")) ; Calendar date formats: (define px:ccyy-mm-dd #px"^(\\d{4})-(\\d{2})-(\\d{2})$") ; 4 2 2 (define px:ccyymmdd #px"^(\\d{4})(\\d{2})(\\d{2})$") ; 8 (define px:ccyy-mm #px"^(\\d{4})-(\\d{2})$") ; 4 2 (define px:ccyy #px"^(\\d{4})$") ; 4 (define px:cc #px"^(\\d{2})$") ; 2 (define px:yy-mm-dd #px"^(\\d{2})-(\\d{2})-(\\d{2})$") ; 2 2 2 (define px:yymmdd #px"^(\\d{2})(\\d{2})(\\d{2})$") ; 6 ; Ordinal date formats: (define px:ccyy-ddd #px"^(\\d{4})-(\\d{3})$") ; 4 3 (define px:ccyyddd #px"^(\\d{4})(\\d{3})$") ; 7 (define px:yy-ddd #px"^(\\d{2})-(\\d{3})$") ; 2 3 (define px:yyddd #px"^(\\d{2})(\\d{3})$") ; 5 ; Week/day formats: (define px:ccyy-www-d #px"^(\\d{4})-W(\\d{2})-(\\d)$") ; W 4 2 1 (define px:ccyywwwd #px"^(\\d{4})W(\\d{2})(\\d)$") ; W 4 3 (define px:ccyy-www #px"^(\\d{4})-W(\\d{2})$") ; W 4 2 (define px:ccyywww #px"^(\\d{4})W(\\d{2})$") ; W 4 2 (define px:yy-www-d #px"^(\\d{2})-W(\\d{2})-(\\d)$") ; W 2 2 1 (define px:yywwwd #px"^(\\d{2})W(\\d{2})(\\d)$") ; W 2 3 (define px:yy-www #px"^(\\d{2})-W(\\d{2})$") ; W 2 2 (define px:yywww #px"^(\\d{2})W(\\d{2})$") ; W 2 2 ; Local time of day: (define px:hh:mm:ss #px"^(\\d{2}):(\\d{2}):(\\d{2})$") ; 2 2 2 (define px:hhmmss #px"^(\\d{2})(\\d{2})(\\d{2})$") ; 6 (define px:hh:mm #px"^(\\d{2}):(\\d{2})$") ; 2 2 (define px:hhmm #px"^(\\d{2})(\\d{2})$") ; 4 (define px:hh #px"^(\\d{2})$") ; 2 ; Utility procedures --------------------------- ;; read-digit : string integer -> (U integer #f) ;(define (read-digit str pos) ; (let ([chr (string-ref str pos)]) ; (if (char-numeric? chr) ; (char->integer chr) ; #f))) ;; read-number : string integer integer -> (U integer #f) ;(define (read-number str start end) ; (let loop ([accum 0] [pos start]) ; (if (< pos end) ; (let ([digit (read-digit str pos)]) ; (loop (+ (* 10 accum) digit) (add1 pos))) ; accum))) ;; read-fraction : string integer integer integer -> (U integer #f) ;(define (read-fraction input start end normalize-to) ; ; First read the digits that are available: ; (let loop ([accum 0] [pos start]) ; (if (< pos end) ; (let ([digit (read-digit input pos)]) ; (loop (+ (* 10 accum) digit) (add1 pos))) ; ; Normalize the result: ; (let loop ([accum accum] [pos (- pos start)]) ; (if (< pos normalize-to) ; (loop (* 10 accum) (add1 pos)) ; accum))))) ; Parsing dates -------------------------------- ;; parse-normal-date : string (list-of integer) -> date ;(define (parse-normal-date str format) ; (match format ; [(list 4 2 2) ; ] ; [(list 8) ; ] ; [(list 4 2) ; ] ; [(list 4) ; ] ; [(list 2) ; ] ; [(list 2 2 2) ; ] ; [(list 6) ; ] ; [(list 4 3) ; ] ; [(list 7) ; ])) ;(define parse-date ; (case-lambda ; [(str) (parse-date str (date-format str))] ; [(str format) ; (case (car format) ; [(#\D) ; Normal date format ; (parse-normal-date str (cdr format))] ; [(#\W) ; Week date format ; (parse-week-date str (cdr format))])])) )