1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
|
(in-package #:local-time.test)
(defsuite* (simple :in test))
(eval-when (:compile-toplevel :load-toplevel :execute)
(local-time::define-timezone eastern-tz
(merge-pathnames #p"US/Eastern" local-time::*default-timezone-repository-path*))
(local-time::define-timezone amsterdam-tz
(merge-pathnames #p"Europe/Amsterdam" local-time::*default-timezone-repository-path*)))
(deftest test/simple/make-timestamp ()
(let ((timestamp (make-timestamp :nsec 1 :sec 2 :day 3)))
(is (= (nsec-of timestamp) 1))
(is (= (sec-of timestamp) 2))
(is (= (day-of timestamp) 3))))
(deftest test/simple/read-binary-integer ()
(let ((tmp-file-path (merge-pathnames (uiop:temporary-directory) "local-time-test")))
(with-open-file (ouf tmp-file-path
:direction :output
:element-type 'unsigned-byte
:if-exists :supersede)
(dotimes (i 14)
(write-byte 200 ouf)))
(with-open-file (inf tmp-file-path :element-type 'unsigned-byte)
(is (eql (local-time::%read-binary-integer inf 1) 200))
(is (eql (local-time::%read-binary-integer inf 1 t) -56))
(is (eql (local-time::%read-binary-integer inf 2) 51400))
(is (eql (local-time::%read-binary-integer inf 2 t) -14136))
(is (eql (local-time::%read-binary-integer inf 4) 3368601800))
(is (eql (local-time::%read-binary-integer inf 4 t) -926365496)))))
(deftest test/simple/encode-timestamp ()
(macrolet ((entry ((&rest encode-timestamp-args)
day sec nsec)
`(let ((timestamp (encode-timestamp ,@encode-timestamp-args)))
(is (= (day-of timestamp) ,day))
(is (= (sec-of timestamp) ,sec))
(is (= (nsec-of timestamp) ,nsec)))))
(entry (0 0 0 0 1 3 2000 :offset 0)
0 0 0)
(entry (0 0 0 0 29 2 2000 :offset 0)
-1 0 0)
(entry (0 0 0 0 2 3 2000 :offset 0)
1 0 0)
(entry (0 0 0 0 1 1 2000 :offset 0)
-60 0 0)
(entry (0 0 0 0 1 3 2001 :offset 0)
365 0 0)))
(defmacro encode-decode-test (args &body body)
`(let ((timestamp (encode-timestamp ,@(subseq args 0 7) :offset 0)))
(is (equal '(,@args ,@(let ((stars nil))
(dotimes (n (- 7 (length args)))
(push '* stars))
stars))
(multiple-value-list
(decode-timestamp timestamp :timezone local-time:+utc-zone+))))
,@body))
(deftest test/simple/encode-decode-consistency/1 ()
(encode-decode-test (5 5 5 5 5 5 1990 6 nil 0 "UTC"))
(encode-decode-test (0 0 0 0 1 3 2001 4 nil 0 "UTC"))
(encode-decode-test (0 0 0 0 1 3 1998 0 nil 0 "UTC"))
(encode-decode-test (1 2 3 4 5 6 2008 4 nil 0 "UTC"))
(encode-decode-test (0 0 0 0 1 1 1 1 nil 0 "UTC")))
(deftest test/simple/encode-decode-consistency/random ()
(loop :repeat 1000 :do
(let ((timestamp (make-timestamp :day (- (random 65535) 36767)
:sec (random 86400)
:nsec (random 1000000000))))
(multiple-value-bind (ns ss mm hh day month year)
(decode-timestamp timestamp :timezone local-time:+utc-zone+)
(is (timestamp= timestamp
(encode-timestamp ns ss mm hh day month year :offset 0)))))))
;;;;;;
;;; TODO the rest is uncategorized, just simply converted from the old 5am suite
(deftest test/timestamp-conversions ()
(is (eql 0 (timestamp-to-unix
(encode-timestamp 0 0 0 0 1 1 1970 :offset 0))))
(is (equal (values 2 3 4 5 6 2008 3 * *)
(decode-universal-time
(timestamp-to-universal
(encode-timestamp 1 2 3 4 5 6 2008 :offset 0)) 0)))
(let ((now (now)))
(setf (nsec-of now) 0)
(is (timestamp= now
(unix-to-timestamp (timestamp-to-unix now)))))
(let ((now (get-universal-time)))
(is (equal now
(timestamp-to-universal (universal-to-timestamp now))))))
(deftest test/year-difference ()
(let ((a (parse-timestring "2006-01-01T00:00:00"))
(b (parse-timestring "2001-01-01T00:00:00")))
(is (= 5 (timestamp-whole-year-difference a b))))
(let ((a (parse-timestring "2006-01-01T00:00:00"))
(b (parse-timestring "2001-01-02T00:00:00")))
(is (= 4 (timestamp-whole-year-difference a b))))
(let* ((local-time::*default-timezone* amsterdam-tz)
(a (parse-timestring "1978-10-01")))
(is (= 0 (timestamp-whole-year-difference a a)))))
(deftest test/adjust-timestamp/day-of-week/basic ()
(let ((sunday (parse-timestring "2020-09-13T00:00:00"))
(saturday (parse-timestring "2020-09-19T00:00:00"))
(base (parse-timestring "2020-09-15T00:00:00")))
(loop for dow in '(:sunday :monday :tuesday)
do (let ((modified (adjust-timestamp base (timezone +utc-zone+) (offset :day-of-week dow))))
(is (and (timestamp>= modified sunday) (timestamp<= modified base)))))
(loop for dow in '(:wednesday :thursday :friday :saturday)
do (let ((modified (adjust-timestamp base (timezone +utc-zone+) (offset :day-of-week dow))))
(is (and (timestamp> modified base) (timestamp<= modified saturday)))))))
(deftest test/adjust-timestamp/bug1 ()
(let* ((timestamp (parse-timestring "2006-01-01T00:00:00Z"))
(modified-timestamp (adjust-timestamp timestamp (timezone +utc-zone+) (offset :year 1))))
(is (timestamp= (parse-timestring "2007-01-01T00:00:00Z") modified-timestamp))))
(deftest test/adjust-timestamp/bug2 ()
(let* ((timestamp (parse-timestring "2009-03-01T01:00:00.000000+00:00"))
(modified-timestamp (adjust-timestamp timestamp (timezone +utc-zone+) (offset :month 1))))
(is (timestamp= (parse-timestring "2009-04-01T01:00:00.000000+00:00") modified-timestamp))))
(deftest test/adjust-timestamp/bug3 ()
(let* ((timestamp (parse-timestring "2009-03-01T01:00:00.000000+00:00"))
(modified-timestamp (adjust-timestamp timestamp (timezone +utc-zone+) (offset :day-of-week :monday))))
(is (timestamp= (parse-timestring "2009-02-23T01:00:00.000000+00:00") modified-timestamp)))
(let* ((timestamp (parse-timestring "2009-03-04T01:00:00.000000+00:00"))
(modified-timestamp (adjust-timestamp timestamp (timezone +utc-zone+) (offset :day-of-week :monday))))
(is (timestamp= (parse-timestring "2009-03-02T01:00:00.000000+00:00") modified-timestamp))))
(deftest test/adjust-timestamp/bug4 ()
(let* ((timestamp (parse-timestring "2013-04-30T00:00:00.000000+00:00"))
(modified-timestamp (adjust-timestamp timestamp (timezone +utc-zone+) (offset :day-of-week :wednesday))))
(is (timestamp= (parse-timestring "2013-05-01T00:00:00.000000+00:00") modified-timestamp)))
(let* ((timestamp (parse-timestring "2013-12-31T00:00:00.000000+00:00"))
(modified-timestamp (adjust-timestamp timestamp (timezone +utc-zone+) (offset :day-of-week :wednesday))))
(is (timestamp= (parse-timestring "2014-01-01T00:00:00.000000+00:00") modified-timestamp))))
#+nil
(deftest test/adjust-days ()
(let ((sunday (parse-timestring "2006-12-17T01:02:03Z")))
(is (timestamp= (parse-timestring "2006-12-11T01:02:03Z")
(adjust-timestamp sunday (offset :day-of-week :monday))))
(is (timestamp= (parse-timestring "2006-12-20T01:02:03Z")
(adjust-timestamp sunday (offset :day 3))))))
(deftest test/decode-date ()
(loop
:for (total-day year month day) :in '((-1 2000 02 29)
(0 2000 03 01)
(1 2000 03 02)
(364 2001 02 28)
(365 2001 03 01)
(366 2001 03 02)
(#.(* 2 365) 2002 03 01)
(#.(* 4 365) 2004 02 29)
(#.(1+ (* 4 365)) 2004 03 01))
:do (multiple-value-bind (year* month* day*)
(local-time::%timestamp-decode-date total-day)
(is (= year year*))
(is (= month month*))
(is (= day day*)))))
(deftest test/timestamp-decoding-readers ()
(let ((*default-timezone* +utc-zone+))
(dolist (year '(1900 1975 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010))
(dolist (month '(1 2 3 4 5 6 7 8 9 10 11 12))
(dolist (day '(1 2 3 27 28 29 30 31))
(when (valid-date-tuple? year month day)
(let ((hour (random 24))
(min (random 60))
(sec (random 60))
(nsec (random 1000000000)))
(let ((time (encode-timestamp nsec sec min hour day month year :offset 0)))
(is (= (floor year 10) (timestamp-decade time)))
(is (= year (timestamp-year time)))
(is (= month (timestamp-month time)))
(is (= day (timestamp-day time)))
(is (= hour (timestamp-hour time)))
(is (= min (timestamp-minute time)))
(is (= sec (timestamp-second time)))
(is (= (floor nsec 1000000)
(timestamp-millisecond time)))
(is (= (floor nsec 1000)
(timestamp-microsecond time)))))))))))
(deftest test/timestamp-century ()
(let ((*default-timezone* +utc-zone+))
(dolist (year-data '((-101 -2)
(-100 -1)
(-1 -1)
(1 1)
(100 1)
(101 2)
(1999 20)
(2000 20)
(2001 21)))
(let ((time (encode-timestamp 0 0 0 0 1 1 (first year-data) :offset 0)))
(is (= (second year-data) (timestamp-century time)))))))
(deftest test/timestamp-millennium ()
(let ((*default-timezone* +utc-zone+))
(dolist (year-data '((-101 -1)
(-100 -1)
(-1 -1)
(1 1)
(100 1)
(101 1)
(1001 2)
(1999 2)
(2000 2)
(2001 3)))
(let ((time (encode-timestamp 0 0 0 0 1 1 (first year-data) :offset 0)))
(is (= (second year-data) (timestamp-millennium time)))))))
(defun valid-date-tuple? (year month day)
;; it works only on the gregorian calendar
(let ((month-days #(31 28 31 30 31 30 31 31 30 31 30 31)))
(and (<= 1 month 12)
(<= 1 day (+ (aref month-days (1- month))
(if (and (= month 2)
(zerop (mod year 4))
(not (zerop (mod year 100)))
(zerop (mod year 400)))
1
0))))))
(deftest test/encode-decode-timestamp ()
(let ((*default-timezone* +utc-zone+))
(loop for year :in '(1900 1975 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010) do
(loop for month :from 1 :to 12 do
(loop for day :in '(1 2 3 27 28 29 30 31) do
(when (valid-date-tuple? year month day)
(multiple-value-bind (nsec sec minute hour day* month* year* day-of-week)
(decode-timestamp (encode-timestamp 0 0 0 0 day month year :offset 0))
(declare (ignore nsec sec minute day-of-week))
(is (= hour 0))
(is (= year year*))
(is (= month month*))
(is (= day day*)))))))))
(deftest test/timestamp-maximize-part ()
(timestamp= (timestamp-maximize-part
(encode-timestamp 0 49 26 13 9 12 2010 :offset -18000)
:min)
(encode-timestamp 999999999 59 59 13 9 12 2010 :offset -18000)))
(deftest test/timestamp-minimize-part ()
(timestamp= (timestamp-minimize-part
(encode-timestamp 0 49 26 13 9 12 2010 :offset -18000)
:min)
(encode-timestamp 0 0 0 13 9 12 2010 :offset -18000)))
(deftest test/decode-iso-week ()
(dolist (*default-timezone* (list eastern-tz +utc-zone+ amsterdam-tz))
(dolist (testcase '((2005 01 01 2004 53 6)
(2005 01 02 2004 53 7)
(2005 12 31 2005 52 6)
(2007 01 01 2007 1 1)
(2007 12 30 2007 52 7)
(2007 12 31 2008 1 1)
(2008 01 01 2008 1 2)
(2008 12 28 2008 52 7)
(2008 12 29 2009 1 1)
(2008 12 30 2009 1 2)
(2008 12 31 2009 1 3)
(2009 01 01 2009 1 4)
(2009 12 31 2009 53 4)
(2010 01 01 2009 53 5)
(2010 01 02 2009 53 6)
(2010 01 03 2009 53 7)
(2016 01 04 2016 1 1)))
(destructuring-bind (year month day iso-year iso-week iso-dow)
testcase
(let ((ts (encode-timestamp 0 0 0 12 day month year)))
(is (equal (list iso-year iso-week iso-dow)
(multiple-value-list (local-time::%timestamp-decode-iso-week ts)))))))))
|