isodate.lisp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. ;;;; isodate.lisp
  2. (defpackage #:iso-date
  3. (:use :cl
  4. :esrap)
  5. (:export #:parse-date
  6. #:print-date
  7. #:date-stamp))
  8. (in-package #:iso-date)
  9. ;;; "isodate" goes here. Hacks and glory await!
  10. (define-condition month-error (error)
  11. ((month :initarg :month)))
  12. (define-condition date-error (error)
  13. ((month :initarg :month)
  14. (date :initarg :date)))
  15. (define-condition hour-error (error)
  16. ((hour :initarg :hour)))
  17. (define-condition minute-error (error)
  18. ((minute :initarg :minute)))
  19. (define-condition second-error (error)
  20. ((second :initarg :second)))
  21. (defrule year
  22. (and (or "1" "2" "3" "4" "5" "6" "7" "8" "9" "0")
  23. (or "1" "2" "3" "4" "5" "6" "7" "8" "9" "0")
  24. (or "1" "2" "3" "4" "5" "6" "7" "8" "9" "0")
  25. (or "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"))
  26. (:text t)
  27. (:lambda (text)
  28. (parse-integer text)))
  29. (defrule month
  30. (and (or "0" "1")
  31. (or "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"))
  32. (:text t)
  33. (:lambda (text)
  34. (parse-integer text)))
  35. (defrule day
  36. (and (or "0" "1" "2" "3")
  37. (or "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"))
  38. (:text t)
  39. (:lambda (text)
  40. (parse-integer text)))
  41. (defrule hour
  42. (and (or "0" "1" "2")
  43. (or "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"))
  44. (:text t)
  45. (:lambda (text)
  46. (parse-integer text)))
  47. (defrule minute
  48. (and (or "0" "1" "2" "3" "4" "5")
  49. (or "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"))
  50. (:text t)
  51. (:lambda (text)
  52. (parse-integer text)))
  53. (defrule second
  54. (and (or "0" "1" "2" "3" "4" "5")
  55. (or "1" "2" "3" "4" "5" "6" "7" "8" "9" "0"))
  56. (:text t)
  57. (:lambda (text)
  58. (parse-integer text)))
  59. (defun leap-year-p (year)
  60. (or (= (mod year 4) 0)
  61. (= (mod year 100) 0)
  62. (= (mod year 400) 0)))
  63. (defrule whole-date
  64. (and year (? (and "-" month (? (and "-" day)))))
  65. (:destructure (year (d month (dd day)))
  66. (declare (ignore d dd)
  67. (ignorable year month day))
  68. (assert (or (null month)
  69. (<= month 12))
  70. (month)
  71. 'month-error :month month)
  72. (assert (or (null day)
  73. (and (leap-year-p year)
  74. (= month 2)
  75. (= day 29))
  76. (and (= month 1)
  77. (<= day 31))
  78. (and (= month 2)
  79. (<= day 28))
  80. (and (= month 3)
  81. (<= day 31))
  82. (and (= month 4)
  83. (<= day 30))
  84. (and (= month 5)
  85. (<= day 31))
  86. (and (= month 6)
  87. (<= day 30))
  88. (and (= month 7)
  89. (<= day 31))
  90. (and (= month 8)
  91. (<= day 31))
  92. (and (= month 9)
  93. (<= day 30))
  94. (and (= month 10)
  95. (<= day 31))
  96. (and (= month 11)
  97. (<= day 30))
  98. (and (= month 12)
  99. (<= day 31)))
  100. (day year month)
  101. 'date-error :year year :month month :day day)
  102. (let ((month (if (null month) 0 month))
  103. (day (if (null day) 0 day)))
  104. (list year month day))))
  105. (defrule whole-time
  106. (and hour ":" minute ":" second)
  107. (:destructure (hour c minute cc second)
  108. (declare (ignore c cc))
  109. (assert (<= hour 24)
  110. (hour)
  111. 'hour-error :hour hour)
  112. (assert (<= minute 59)
  113. (minute)
  114. 'minute-error :minute minute)
  115. (assert (<= second 59)
  116. (second)
  117. 'second-error :second second)
  118. (list hour minute second)))
  119. (defrule whole
  120. (and whole-date (? (and "T" whole-time)))
  121. (:lambda (list)
  122. (let ((year (first (first list)))
  123. (month (second (first list)))
  124. (day (third (first list)))
  125. (hour (first (second (second list))))
  126. (minute (second (second (second list))))
  127. (second (third (second (second list)))))
  128. (let ((hour (if (null hour) 0 hour))
  129. (minute (if (null minute) 0 minute))
  130. (second (if (null second) 0 second)))
  131. (encode-universal-time second minute hour day month year)))))
  132. (defun parse-date (date)
  133. (declare (string date))
  134. (let ((date (parse 'whole date)))
  135. (multiple-value-bind (second minute hour date month year day daylight-p zone) (decode-universal-time date)
  136. (declare (ignorable day daylight-p zone))
  137. (values date
  138. (list second minute hour date month year)))))
  139. (defun print-date (date)
  140. (declare (integer date))
  141. (multiple-value-bind (second minute hour date month year day daylight-p zone) (decode-universal-time date)
  142. (declare (ignorable day daylight-p zone))
  143. (format nil "~4,'0d-~2,'0d-~2,'0dT~2,'0d:~2,'0d:~2,'0d"
  144. year month date
  145. hour minute second)))
  146. (defun date-stamp ()
  147. (values (print-date (get-universal-time))
  148. (get-universal-time)))