time.test 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. ;;;; time.test --- test suite for Guile's time functions -*- scheme -*-
  2. ;;;; Jim Blandy <jimb@red-bean.com> --- June 1999, 2004
  3. ;;;;
  4. ;;;; Copyright (C) 1999, 2004, 2006, 2007, 2009 Free Software Foundation, Inc.
  5. ;;;;
  6. ;;;; This program is free software; you can redistribute it and/or modify
  7. ;;;; it under the terms of the GNU General Public License as published by
  8. ;;;; the Free Software Foundation; either version 2, or (at your option)
  9. ;;;; any later version.
  10. ;;;;
  11. ;;;; This program is distributed in the hope that it will be useful,
  12. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. ;;;; GNU General Public License for more details.
  15. ;;;;
  16. ;;;; You should have received a copy of the GNU General Public License
  17. ;;;; along with this software; see the file COPYING. If not, write to
  18. ;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19. ;;;; Boston, MA 02110-1301 USA
  20. (define-module (test-suite test-time)
  21. #:use-module (test-suite lib)
  22. #:use-module (ice-9 threads))
  23. ;;;
  24. ;;; gmtime
  25. ;;;
  26. (with-test-prefix "gmtime"
  27. (for-each (lambda (t)
  28. (pass-if (list "in another thread after error" t)
  29. (or (provided? 'threads) (throw 'unsupported))
  30. (alarm 5)
  31. (false-if-exception (gmtime t))
  32. (join-thread (begin-thread (catch #t
  33. (lambda () (gmtime t))
  34. (lambda args #f))))
  35. (alarm 0)
  36. #t))
  37. ;; time values that might provoke an error from libc
  38. ;; on 32-bit glibc all values (which fit) are fine
  39. ;; on 64-bit glibc apparently 2^63 can overflow a 32-bit tm_year
  40. (list (1- (ash 1 31)) (1- (ash 1 63))
  41. -1 (- (ash 1 31)) (- (ash 1 63)))))
  42. ;;;
  43. ;;; internal-time-units-per-second
  44. ;;;
  45. (with-test-prefix "internal-time-units-per-second"
  46. ;; Check that sleep 1 gives about internal-time-units-per-second worth of
  47. ;; elapsed time from times:clock. This mainly ensures
  48. ;; internal-time-units-per-second correctly indicates CLK_TCK units.
  49. ;;
  50. (pass-if "versus times and sleep"
  51. (or (defined? 'times) (throw 'unsupported))
  52. (let ((old (times)))
  53. (sleep 1)
  54. (let* ((new (times))
  55. (elapsed (- (tms:clock new) (tms:clock old))))
  56. (<= (* 0.5 internal-time-units-per-second)
  57. elapsed
  58. (* 2 internal-time-units-per-second))))))
  59. ;;;
  60. ;;; localtime
  61. ;;;
  62. (with-test-prefix "localtime"
  63. ;; gmtoff is calculated with some explicit code, try to exercise that
  64. ;; here, looking at cases where the localtime and gmtime are within the same
  65. ;; day, or crossing midnight, or crossing new year
  66. (pass-if "gmtoff of EST+5 at GMT 10:00am on 10 Jan 2000"
  67. (let ((tm (gmtime 0)))
  68. (set-tm:hour tm 10)
  69. (set-tm:mday tm 10)
  70. (set-tm:mon tm 0)
  71. (set-tm:year tm 100)
  72. (let* ((t (car (mktime tm "GMT")))
  73. (tm (localtime t "EST+5")))
  74. (eqv? (* 5 3600) (tm:gmtoff tm)))))
  75. ;; crossing forward over day boundary
  76. (pass-if "gmtoff of EST+5 at GMT 3am on 10 Jan 2000"
  77. (let ((tm (gmtime 0)))
  78. (set-tm:hour tm 3)
  79. (set-tm:mday tm 10)
  80. (set-tm:mon tm 0)
  81. (set-tm:year tm 100)
  82. (let* ((t (car (mktime tm "GMT")))
  83. (tm (localtime t "EST+5")))
  84. (eqv? (* 5 3600) (tm:gmtoff tm)))))
  85. ;; crossing backward over day boundary
  86. (pass-if "gmtoff of AST-10 at GMT 10pm on 10 Jan 2000"
  87. (let ((tm (gmtime 0)))
  88. (set-tm:hour tm 22)
  89. (set-tm:mday tm 10)
  90. (set-tm:mon tm 0)
  91. (set-tm:year tm 100)
  92. (let* ((t (car (mktime tm "GMT")))
  93. (tm (localtime t "AST-10")))
  94. (eqv? (* -10 3600) (tm:gmtoff tm)))))
  95. ;; crossing forward over year boundary
  96. (pass-if "gmtoff of EST+5 at GMT 3am on 1 Jan 2000"
  97. (let ((tm (gmtime 0)))
  98. (set-tm:hour tm 3)
  99. (set-tm:mday tm 1)
  100. (set-tm:mon tm 0)
  101. (set-tm:year tm 100)
  102. (let* ((t (car (mktime tm "GMT")))
  103. (tm (localtime t "EST+5")))
  104. (eqv? (* 5 3600) (tm:gmtoff tm)))))
  105. ;; crossing backward over day boundary
  106. (pass-if "gmtoff of AST-10 at GMT 10pm on 31 Dec 2000"
  107. (let ((tm (gmtime 0)))
  108. (set-tm:hour tm 22)
  109. (set-tm:mday tm 31)
  110. (set-tm:mon tm 11)
  111. (set-tm:year tm 100)
  112. (let* ((t (car (mktime tm "GMT")))
  113. (tm (localtime t "AST-10")))
  114. (eqv? (* -10 3600) (tm:gmtoff tm))))))
  115. ;;;
  116. ;;; mktime
  117. ;;;
  118. (with-test-prefix "mktime"
  119. ;; gmtoff is calculated with some explicit code, try to exercise that
  120. ;; here, looking at cases where the mktime and gmtime are within the same
  121. ;; day, or crossing midnight, or crossing new year
  122. (pass-if "gmtoff of EST+5 at 10:00am on 10 Jan 2000"
  123. (let ((tm (gmtime 0)))
  124. (set-tm:hour tm 10)
  125. (set-tm:mday tm 10)
  126. (set-tm:mon tm 0)
  127. (set-tm:year tm 100)
  128. (let ((tm (cdr (mktime tm "EST+5"))))
  129. (eqv? (* 5 3600) (tm:gmtoff tm)))))
  130. ;; crossing forward over day boundary
  131. (pass-if "gmtoff of EST+5 at 10:00pm on 10 Jan 2000"
  132. (let ((tm (gmtime 0)))
  133. (set-tm:hour tm 22)
  134. (set-tm:mday tm 10)
  135. (set-tm:mon tm 0)
  136. (set-tm:year tm 100)
  137. (let ((tm (cdr (mktime tm "EST+5"))))
  138. (eqv? (* 5 3600) (tm:gmtoff tm)))))
  139. ;; crossing backward over day boundary
  140. (pass-if "gmtoff of AST-10 at 3:00am on 10 Jan 2000"
  141. (let ((tm (gmtime 0)))
  142. (set-tm:hour tm 3)
  143. (set-tm:mday tm 10)
  144. (set-tm:mon tm 0)
  145. (set-tm:year tm 100)
  146. (let ((tm (cdr (mktime tm "AST-10"))))
  147. (eqv? (* -10 3600) (tm:gmtoff tm)))))
  148. ;; crossing forward over year boundary
  149. (pass-if "gmtoff of EST+5 at 10:00pm on 31 Dec 2000"
  150. (let ((tm (gmtime 0)))
  151. (set-tm:hour tm 22)
  152. (set-tm:mday tm 31)
  153. (set-tm:mon tm 11)
  154. (set-tm:year tm 100)
  155. (let ((tm (cdr (mktime tm "EST+5"))))
  156. (eqv? (* 5 3600) (tm:gmtoff tm)))))
  157. ;; crossing backward over day boundary
  158. (pass-if "gmtoff of AST-10 at 3:00am on 1 Jan 2000"
  159. (let ((tm (gmtime 0)))
  160. (set-tm:hour tm 3)
  161. (set-tm:mday tm 1)
  162. (set-tm:mon tm 0)
  163. (set-tm:year tm 100)
  164. (let ((tm (cdr (mktime tm "AST-10"))))
  165. (eqv? (* -10 3600) (tm:gmtoff tm))))))
  166. ;;;
  167. ;;; strftime
  168. ;;;
  169. (with-test-prefix "strftime"
  170. ;; Note we must force isdst to get the ZOW zone name out of %Z on HP-UX.
  171. ;; If localtime is in daylight savings then it will decide there's no
  172. ;; daylight savings zone name for the fake ZOW, and come back empty.
  173. ;;
  174. ;; This test is disabled because on NetBSD %Z doesn't look at the tm_zone
  175. ;; field in struct tm passed by guile. That behaviour is reasonable
  176. ;; enough since that field is not in C99 so a C99 program won't know it
  177. ;; has to be set. For the details on that see
  178. ;;
  179. ;; http://www.netbsd.org/cgi-bin/query-pr-single.pl?number=21722
  180. ;;
  181. ;; Not sure what to do about this in guile, it'd be nice for %Z to look at
  182. ;; tm:zone everywhere.
  183. ;;
  184. ;;
  185. ;; (pass-if "strftime %Z doesn't return garbage"
  186. ;; (let ((t (localtime (current-time))))
  187. ;; (set-tm:zone t "ZOW")
  188. ;; (set-tm:isdst t 0)
  189. ;; (string=? (strftime "%Z" t)
  190. ;; "ZOW")))
  191. (with-test-prefix "C99 %z format"
  192. ;; C99 spec is empty string if no zone determinable
  193. ;;
  194. ;; On pre-C99 systems not sure what to expect if %z unsupported, probably
  195. ;; "%z" unchanged in C99 if timezone. On AIX and Tru64 5.1b, it returns
  196. ;; a string such as "GMT" or "EST", instead of "+0000" or "-0500". See
  197. ;; https://savannah.gnu.org/bugs/index.php?24130 for details.
  198. ;;
  199. (define have-strftime-%z
  200. (equal? (strftime "%z" (gmtime 0)) "+0000"))
  201. ;; %z here is quite possibly affected by the same tm:gmtoff vs current
  202. ;; zone as %Z above is, so in the following tests we make them the same.
  203. (pass-if "GMT"
  204. (or have-strftime-%z (throw 'unsupported))
  205. (putenv "TZ=GMT+0")
  206. (tzset)
  207. (let ((tm (localtime 86400)))
  208. (string=? "+0000" (strftime "%z" tm))))
  209. ;; prior to guile 1.6.9 and 1.8.1 this test failed, getting "+0500",
  210. ;; because we didn't adjust for tm:gmtoff being west of Greenwich versus
  211. ;; tm_gmtoff being east of Greenwich
  212. (pass-if "EST+5"
  213. (or have-strftime-%z (throw 'unsupported))
  214. (putenv "TZ=EST+5")
  215. (tzset)
  216. (let ((tm (localtime 86400)))
  217. (string=? "-0500" (strftime "%z" tm))))))
  218. ;;;
  219. ;;; strptime
  220. ;;;
  221. (with-test-prefix "strptime"
  222. (pass-if "in another thread after error"
  223. (or (defined? 'strptime) (throw 'unsupported))
  224. (or (provided? 'threads) (throw 'unsupported))
  225. (alarm 5)
  226. (false-if-exception
  227. (strptime "%a" "nosuchday"))
  228. (join-thread (begin-thread (strptime "%d" "1")))
  229. (alarm 0)
  230. #t)
  231. (with-test-prefix "GNU %s format"
  232. ;; "%s" to parse a count of seconds since 1970 is a GNU extension
  233. (define have-strptime-%s
  234. (false-if-exception (strptime "%s" "0")))
  235. (pass-if "gmtoff on GMT"
  236. (or have-strptime-%s (throw 'unsupported))
  237. (putenv "TZ=GMT+0")
  238. (tzset)
  239. (let ((tm (car (strptime "%s" "86400"))))
  240. (eqv? 0 (tm:gmtoff tm))))
  241. ;; prior to guile 1.6.9 and 1.8.1 we didn't pass tm_gmtoff back from
  242. ;; strptime
  243. (pass-if "gmtoff on EST+5"
  244. (or have-strptime-%s (throw 'unsupported))
  245. (putenv "TZ=EST+5")
  246. (tzset)
  247. (let ((tm (car (strptime "%s" "86400"))))
  248. (eqv? (* 5 3600) (tm:gmtoff tm))))))