iso8601.ss
#lang scheme/base
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; parsing and generating rfc2/822 dates.
;; rfc2822 is a more limited version of rfc822.
;; below is the syntax for both rfc822 & rfc2822. from
;; http://tools.ietf.org/html/rfc2822
;; http://tools.ietf.org/html/rfc822
;;
;; NOTE we do not have to worry about CFWS - those would be filtered out by
;; read-network-line module. 
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; iso8601.ss - parsing and generating iso8601 functions.
;; yc 7/6/2010 - first version
(require "base.ss" "date.ss" "depend.ss" "rfc822.ss")


(define date
  (seq year <- digit4 
       (zero-one #\- #f)
       month <- digit2 
       (zero-one #\- #f)
       day <- digit2 
       (return (list year month day))))

(define time 
  (seq hour <- digit2 
       (zero-one #\: #f)
       minute <- digit2 
       (zero-one #\: #f)
       seconds <- digit2 
       (return (list hour minute seconds))))

(define timezone
  (choice (seq #\Z (return 0))
          (seq #\z (return 0))
          (seq sign <- (zero-one (choice (seq #\+ (return +))
                                 (seq #\- (return -)))
                         +)
               hour <- digit2 
               (zero-one #\: #f)
               minute <- digit2
               (return (sign (offset hour minute))))))

(define iso8601 
  (seq d <- date 
       time+zone <- 
       (zero-one (seq (zero-one #\T #f)
                      t <- time 
                      zone <- (zero-one timezone 0)
                      (return (append t (list '#:tz zone))))
                 `(0 0 0 #:tz 0))
       (return (apply* build-date (append d time+zone)))))

(define read-iso8601 (make-reader iso8601)) 

(define (date->iso8601 d)
  (date->string d "~Y~m~dT~H~M~S~z"))

(provide/contract 
 (read-iso8601 Reader/c)
 (date->iso8601 (-> date? string?))
 )