📄 srfi-19.scm
字号:
#\0 2) port)))) (cons #\y (lambda (date pad-with port) (display (priv:padding (priv:last-n-digits (date-year date) 2) pad-with 2) port))) (cons #\Y (lambda (date pad-with port) (display (date-year date) port))) (cons #\z (lambda (date pad-with port) (priv:tz-printer (date-zone-offset date) port))) (cons #\Z (lambda (date pad-with port) (priv:locale-print-time-zone date port))) (cons #\1 (lambda (date pad-with port) (display (date->string date "~Y-~m-~d") port))) (cons #\2 (lambda (date pad-with port) (display (date->string date "~k:~M:~S~z") port))) (cons #\3 (lambda (date pad-with port) (display (date->string date "~k:~M:~S") port))) (cons #\4 (lambda (date pad-with port) (display (date->string date "~Y-~m-~dT~k:~M:~S~z") port))) (cons #\5 (lambda (date pad-with port) (display (date->string date "~Y-~m-~dT~k:~M:~S") port)))))(define (priv:get-formatter char) (let ((associated (assoc char priv:directives))) (if associated (cdr associated) #f)))(define (priv:date-printer date index format-string str-len port) (if (>= index str-len) (values) (let ((current-char (string-ref format-string index))) (if (not (char=? current-char #\~)) (begin (display current-char port) (priv:date-printer date (+ index 1) format-string str-len port)) (if (= (+ index 1) str-len) ; bad format string. (priv:time-error 'priv:date-printer 'bad-date-format-string format-string) (let ((pad-char? (string-ref format-string (+ index 1)))) (cond ((char=? pad-char? #\-) (if (= (+ index 2) str-len) ; bad format string. (priv:time-error 'priv:date-printer 'bad-date-format-string format-string) (let ((formatter (priv:get-formatter (string-ref format-string (+ index 2))))) (if (not formatter) (priv:time-error 'priv:date-printer 'bad-date-format-string format-string) (begin (formatter date #f port) (priv:date-printer date (+ index 3) format-string str-len port)))))) ((char=? pad-char? #\_) (if (= (+ index 2) str-len) ; bad format string. (priv:time-error 'priv:date-printer 'bad-date-format-string format-string) (let ((formatter (priv:get-formatter (string-ref format-string (+ index 2))))) (if (not formatter) (priv:time-error 'priv:date-printer 'bad-date-format-string format-string) (begin (formatter date #\Space port) (priv:date-printer date (+ index 3) format-string str-len port)))))) (else (let ((formatter (priv:get-formatter (string-ref format-string (+ index 1))))) (if (not formatter) (priv:time-error 'priv:date-printer 'bad-date-format-string format-string) (begin (formatter date #\0 port) (priv:date-printer date (+ index 2) format-string str-len port))))))))))))(define (date->string date . format-string) (let ((str-port (open-output-string)) (fmt-str (if (null? format-string) "~c" (car format-string)))) (priv:date-printer date 0 fmt-str (string-length fmt-str) str-port) (get-output-string str-port)))(define (priv:char->int ch) (case ch ((#\0) 0) ((#\1) 1) ((#\2) 2) ((#\3) 3) ((#\4) 4) ((#\5) 5) ((#\6) 6) ((#\7) 7) ((#\8) 8) ((#\9) 9) (else (priv:time-error 'bad-date-template-string (list "Non-integer character" ch i)))));; read an integer upto n characters long on port; upto -> #f is any length(define (priv:integer-reader upto port) (let loop ((accum 0) (nchars 0)) (let ((ch (peek-char port))) (if (or (eof-object? ch) (not (char-numeric? ch)) (and upto (>= nchars upto))) accum (loop (+ (* accum 10) (priv:char->int (read-char port))) (+ nchars 1))))))(define (priv:make-integer-reader upto) (lambda (port) (priv:integer-reader upto port)));; read *exactly* n characters and convert to integer; could be padded(define (priv:integer-reader-exact n port) (let ((padding-ok #t)) (define (accum-int port accum nchars) (let ((ch (peek-char port))) (cond ((>= nchars n) accum) ((eof-object? ch) (priv:time-error 'string->date 'bad-date-template-string "Premature ending to integer read.")) ((char-numeric? ch) (set! padding-ok #f) (accum-int port (+ (* accum 10) (priv:char->int (read-char port))) (+ nchars 1))) (padding-ok (read-char port) ; consume padding (accum-int port accum (+ nchars 1))) (else ; padding where it shouldn't be (priv:time-error 'string->date 'bad-date-template-string "Non-numeric characters in integer read."))))) (accum-int port 0 0)))(define (priv:make-integer-exact-reader n) (lambda (port) (priv:integer-reader-exact n port)))(define (priv:zone-reader port) (let ((offset 0) (positive? #f)) (let ((ch (read-char port))) (if (eof-object? ch) (priv:time-error 'string->date 'bad-date-template-string (list "Invalid time zone +/-" ch))) (if (or (char=? ch #\Z) (char=? ch #\z)) 0 (begin (cond ((char=? ch #\+) (set! positive? #t)) ((char=? ch #\-) (set! positive? #f)) (else (priv:time-error 'string->date 'bad-date-template-string (list "Invalid time zone +/-" ch)))) (let ((ch (read-char port))) (if (eof-object? ch) (priv:time-error 'string->date 'bad-date-template-string (list "Invalid time zone number" ch))) (set! offset (* (priv:char->int ch) 10 60 60))) (let ((ch (read-char port))) (if (eof-object? ch) (priv:time-error 'string->date 'bad-date-template-string (list "Invalid time zone number" ch))) (set! offset (+ offset (* (priv:char->int ch) 60 60)))) (let ((ch (read-char port))) (if (eof-object? ch) (priv:time-error 'string->date 'bad-date-template-string (list "Invalid time zone number" ch))) (set! offset (+ offset (* (priv:char->int ch) 10 60)))) (let ((ch (read-char port))) (if (eof-object? ch) (priv:time-error 'string->date 'bad-date-template-string (list "Invalid time zone number" ch))) (set! offset (+ offset (* (priv:char->int ch) 60)))) (if positive? offset (- offset)))))));; looking at a char, read the char string, run thru indexer, return index(define (priv:locale-reader port indexer) (define (read-char-string result) (let ((ch (peek-char port))) (if (char-alphabetic? ch) (read-char-string (cons (read-char port) result)) (list->string (reverse! result))))) (let* ((str (read-char-string '())) (index (indexer str))) (if index index (priv:time-error 'string->date 'bad-date-template-string (list "Invalid string for " indexer)))))(define (priv:make-locale-reader indexer) (lambda (port) (priv:locale-reader port indexer)))(define (priv:make-char-id-reader char) (lambda (port) (if (char=? char (read-char port)) char (priv:time-error 'string->date 'bad-date-template-string "Invalid character match."))));; A List of formatted read directives.;; Each entry is a list.;; 1. the character directive;;; a procedure, which takes a character as input & returns;; 2. #t as soon as a character on the input port is acceptable;; for input,;; 3. a port reader procedure that knows how to read the current port;; for a value. Its one parameter is the port.;; 4. a action procedure, that takes the value (from 3.) and some;; object (here, always the date) and (probably) side-effects it.;; In some cases (e.g., ~A) the action is to do nothing(define priv:read-directives (let ((ireader4 (priv:make-integer-reader 4)) (ireader2 (priv:make-integer-reader 2)) (ireaderf (priv:make-integer-reader #f)) (eireader2 (priv:make-integer-exact-reader 2)) (eireader4 (priv:make-integer-exact-reader 4)) (locale-reader-abbr-weekday (priv:make-locale-reader priv:locale-abbr-weekday->index)) (locale-reader-long-weekday (priv:make-locale-reader priv:locale-long-weekday->index)) (locale-reader-abbr-month (priv:make-locale-reader priv:locale-abbr-month->index)) (locale-reader-long-month (priv:make-locale-reader priv:locale-long-month->index)) (char-fail (lambda (ch) #t)) (do-nothing (lambda (val object) (values)))) (list (list #\~ char-fail (priv:make-char-id-reader #\~) do-nothing) (list #\a char-alphabetic? locale-reader-abbr-weekday do-nothing) (list #\A char-alphabetic? locale-reader-long-weekday do-nothing) (list #\b char-alphabetic? locale-reader-abbr-month (lambda (val object) (set-date-month! object val))) (list #\B char-alphabetic? locale-reader-long-month (lambda (val object) (set-date-month! object val))) (list #\d char-numeric? ireader2 (lambda (val object) (set-date-day! object val))) (list #\e char-fail eireader2 (lambda (val object) (set-date-day! object val))) (list #\h char-alphabetic? locale-reader-abbr-month (lambda (val object) (set-date-month! object val))) (list #\H char-numeric? ireader2 (lambda (val object) (set-date-hour! object val))) (list #\k char-fail eireader2 (lambda (val object) (set-date-hour! object val))) (list #\m char-numeric? ireader2 (lambda (val object) (set-date-month! object val))) (list #\M char-numeric? ireader2 (lambda (val object) (set-date-minute! object val))) (list #\S char-numeric? ireader2 (lambda (val object) (set-date-second! object val))) (list #\y char-fail eireader2 (lambda (val object) (set-date-year! object (priv:natural-year val)))) (list #\Y char-numeric? ireader4 (lambda (val object) (set-date-year! object val))) (list #\z (lambda (c) (or (char=? c #\Z) (char=? c #\z) (char=? c #\+) (char=? c #\-))) priv:zone-reader (lambda (val object) (set-date-zone-offset! object val))))))(define (priv:string->date date index format-string str-len port template-string) (define (skip-until port skipper) (let ((ch (peek-char port))) (if (eof-object? port) (priv:time-error 'string->date 'bad-date-format-string template-string) (if (not (skipper ch)) (begin (read-char port) (skip-until port skipper)))))) (if (>= index str-len) (begin (values)) (let ((current-char (string-ref format-string index))) (if (not (char=? current-char #\~)) (let ((port-char (read-char port))) (if (or (eof-object? port-char) (not (char=? current-char port-char))) (priv:time-error 'string->date 'bad-date-format-string template-string)) (priv:string->date date (+ index 1) format-string str-len port template-string)) ;; otherwise, it's an escape, we hope (if (> (+ index 1) str-len) (priv:time-error 'string->date 'bad-date-format-string template-string) (let* ((format-char (string-ref format-string (+ index 1))) (format-info (assoc format-char priv:read-directives))) (if (not format-info) (priv:time-error 'string->date 'bad-date-format-string template-string) (begin (let ((skipper (cadr format-info)) (reader (caddr format-info)) (actor (cadddr format-info))) (skip-until port skipper) (let ((val (reader port))) (if (eof-object? val) (priv:time-error 'string->date 'bad-date-format-string template-string) (actor val date))) (priv:string->date date (+ index 2) format-string str-len port template-string))))))))))(define (string->date input-string template-string) (define (priv:date-ok? date) (and (date-nanosecond date) (date-second date) (date-minute date) (date-hour date) (date-day date) (date-month date) (date-year date) (date-zone-offset date))) (let ((newdate (make-date 0 0 0 0 #f #f #f #f))) (priv:string->date newdate 0 template-string (string-length template-string) (open-input-string input-string) template-string) (if (not (date-zone-offset newdate)) (begin ;; this is necessary to get DST right -- as far as we can ;; get it right (think of the double/missing hour in the ;; night when we are switching between normal time and DST). (set-date-zone-offset! newdate (priv:local-tz-offset (make-time time-utc 0 0))) (set-date-zone-offset! newdate (priv:local-tz-offset (date->time-utc newdate))))) (if (priv:date-ok? newdate) newdate (priv:time-error 'string->date 'bad-date-format-string (list "Incomplete date read. " newdate template-string)))));;; srfi-19.scm ends here
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -