[project @ 1998-12-02 13:17:09 by simonm]
[ghc-hetmet.git] / ghc / lib / std / Time.lhs
1 %
2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-97
3 %
4 \section[Time]{Haskell 1.4 Time of Day Library}
5
6 The {\em Time} library provides standard functionality for
7 clock times, including timezone information (i.e, the functionality of
8 "time.h",  adapted to the Haskell environment), It follows RFC 1129 in
9 its use of Coordinated Universal Time (UTC).
10
11 \begin{code}
12 {-# OPTIONS -#include "cbits/timezone.h" -#include "cbits/stgio.h"  #-}
13 module Time 
14        (
15         Month(..),
16         Day(..),
17
18         ClockTime(..), -- non-standard, lib. report gives this as abstract
19         getClockTime, 
20
21         TimeDiff(TimeDiff),
22         diffClockTimes,
23         addToClockTime,
24         timeDiffToString, -- non-standard
25         formatTimeDiff,   -- non-standard
26
27         CalendarTime(CalendarTime),
28         toCalendarTime, 
29         toUTCTime, 
30         toClockTime,
31         calendarTimeToString, 
32         formatCalendarTime
33
34        ) where
35
36 #ifdef __HUGS__
37 import PreludeBuiltin
38 #else
39 import PrelBase
40 import PrelIOBase
41 import PrelHandle
42 import PrelArr
43 import PrelST
44 import PrelAddr
45 import PrelPack         ( unpackCString )
46 #endif
47
48 import Ix
49 import Char             ( intToDigit )
50 import Locale
51
52 \end{code}
53
54 One way to partition and give name to chunks of a year and a week:
55
56 \begin{code}
57 data Month
58  = January   | February | March    | April
59  | May       | June     | July     | August
60  | September | October  | November | December
61  deriving (Eq, Ord, Enum, Bounded, Ix, Read, Show)
62
63 data Day 
64  = Sunday  | Monday | Tuesday | Wednesday
65  | Thursday | Friday | Saturday
66  deriving (Eq, Ord, Enum, Bounded, Ix, Read, Show)
67
68 \end{code}
69
70 @ClockTime@ is an abstract type, used for the internal clock time.
71 Clock times may be compared, converted to strings, or converted to an
72 external calendar time @CalendarTime@.
73
74 \begin{code}
75 #ifdef __HUGS__
76 -- I believe Int64 is more than big enough.
77 -- In fact, I think one of Int32 or Word32 would do. - ADR
78 data ClockTime = TOD Int64 Int64 deriving (Eq, Ord)
79 #else
80 data ClockTime = TOD Integer Integer deriving (Eq, Ord)
81 #endif
82 \end{code}
83
84 When a @ClockTime@ is shown, it is converted to a string of the form
85 @"Mon Nov 28 21:45:41 GMT 1994"@.
86
87 For now, we are restricted to roughly:
88 Fri Dec 13 20:45:52 1901 through Tue Jan 19 03:14:07 2038, because
89 we use the C library routines based on 32 bit integers.
90
91 \begin{code}
92 #ifdef __HUGS__
93 #warning Show ClockTime is bogus
94 instance Show ClockTime
95 #else
96 instance Show ClockTime where
97     showsPrec p (TOD sec@(J# a# s# d#) nsec) = 
98       showString $ unsafePerformIO $ do
99             buf <- allocChars 38 -- exactly enough for error message
100             str <- _ccall_ showTime (I# s#) d# buf
101             return (unpackCString str)
102
103     showList = showList__ (showsPrec 0)
104 #endif
105 \end{code}
106
107
108 @CalendarTime@ is a user-readable and manipulable
109 representation of the internal $ClockTime$ type.  The
110 numeric fields have the following ranges.
111
112 \begin{verbatim}
113 Value         Range             Comments
114 -----         -----             --------
115
116 year    -maxInt .. maxInt       [Pre-Gregorian dates are inaccurate]
117 mon           0 .. 11           [Jan = 0, Dec = 11]
118 day           1 .. 31
119 hour          0 .. 23
120 min           0 .. 59
121 sec           0 .. 61           [Allows for two leap seconds]
122 picosec       0 .. (10^12)-1    [This could be over-precise?]
123 wday          0 .. 6            [Sunday = 0, Saturday = 6]
124 yday          0 .. 365          [364 in non-Leap years]
125 tz       -43200 .. 43200        [Variation from UTC in seconds]
126 \end{verbatim}
127
128 The {\em tzname} field is the name of the time zone.  The {\em isdst}
129 field indicates whether Daylight Savings Time would be in effect.
130
131 \begin{code}
132 data CalendarTime 
133  = CalendarTime  {
134      ctYear    :: Int,
135      ctMonth   :: Int,
136      ctDay     :: Int,
137      ctHour    :: Int,
138      ctMin     :: Int,
139      ctSec     :: Int,
140 #ifdef __HUGS__
141      ctPicosec :: Int64,
142 #else
143      ctPicosec :: Integer,
144 #endif
145      ctWDay    :: Day,
146      ctYDay    :: Int,
147      ctTZName  :: String,
148      ctTZ      :: Int,
149      ctIsDST   :: Bool
150  }
151  deriving (Eq,Ord,Read,Show)
152
153 \end{code}
154
155 The @TimeDiff@ type records the difference between two clock times in
156 a user-readable way.
157
158 \begin{code}
159 data TimeDiff
160  = TimeDiff {
161      tdYear    :: Int,
162      tdMonth   :: Int,
163      tdDay     :: Int,
164      tdHour    :: Int,
165      tdMin     :: Int,
166      tdSec     :: Int,
167 #ifdef __HUGS__
168      tdPicosec :: Int64   -- not standard
169 #else
170      tdPicosec :: Integer -- not standard
171 #endif
172    }
173    deriving (Eq,Ord,Read,Show)
174 \end{code}
175
176 @getClockTime@ returns the current time in its internal representation.
177
178 \begin{code}
179 #ifdef __HUGS__
180 getClockTime :: IO ClockTime
181 getClockTime = do
182     i1 <- malloc1
183     i2 <- malloc1
184     rc <- prim_getClockTime i1 i2
185     if rc == 0 
186         then do
187             sec  <- cvtUnsigned i1
188             nsec <- cvtUnsigned i2
189             return (TOD sec (nsec * 1000))
190         else
191             constructErrorAndFail "getClockTime"
192   where
193     malloc1 = primNewByteArray sizeof_int64
194     cvtUnsigned arr = primReadInt64Array arr 0
195 #else
196 getClockTime :: IO ClockTime
197 getClockTime = do
198     i1 <- malloc1
199     i2 <- malloc1
200     rc <- _ccall_ getClockTime i1 i2
201     if rc == 0 
202         then do
203             sec  <- cvtUnsigned i1
204             nsec <- cvtUnsigned i2
205             return (TOD sec (nsec * 1000))
206         else
207             constructErrorAndFail "getClockTime"
208   where
209     malloc1 = IO $ \ s# ->
210         case newIntArray# 1# s# of 
211           (# s2#, barr# #) -> 
212                 (# s2#, MutableByteArray bottom barr# #)
213
214     --  The C routine fills in an unsigned word.  We don't have 
215     --  `unsigned2Integer#,' so we freeze the data bits and use them 
216     --  for an MP_INT structure.  Note that zero is still handled specially,
217     --  although (J# 1# 1# (ptr to 0#)) is probably acceptable to gmp.
218
219     cvtUnsigned (MutableByteArray _ arr#) = IO $ \ s# ->
220         case readIntArray# arr# 0# s# of 
221           (# s2#, r# #) ->
222             if r# ==# 0# 
223                 then (# s2#, 0 #)
224                 else case unsafeFreezeByteArray# arr# s2# of
225                         (# s3#, frozen# #) -> 
226                                 (# s3#, J# 1# 1# frozen# #)
227 #endif
228 \end{code}
229
230 @addToClockTime@ {\em d} {\em t} adds a time difference {\em d} and a
231 clock time {\em t} to yield a new clock time.  The difference {\em d}
232 may be either positive or negative.  @[diffClockTimes@ {\em t1} {\em
233 t2} returns the difference between two clock times {\em t1} and {\em
234 t2} as a @TimeDiff@.
235
236
237 \begin{code}
238 #ifdef __HUGS__
239 addToClockTime  :: TimeDiff  -> ClockTime -> ClockTime
240 addToClockTime (TimeDiff year mon day hour min sec psec) 
241                (TOD c_sec c_psec) = unsafePerformIO $ do
242     res <- allocWords sizeof_int64
243     rc <- prim_toClockSec year mon day hour min sec 0 res 
244     if rc /= 0
245      then do
246             diff_sec <- primReadInt64Array res 0
247             let diff_psec = psec
248             return (TOD (c_sec + diff_sec) (c_psec + diff_psec))
249      else
250           error "Time.addToClockTime: can't perform conversion of TimeDiff"
251 #else
252 addToClockTime  :: TimeDiff  -> ClockTime -> ClockTime
253 addToClockTime (TimeDiff year mon day hour min sec psec) 
254                (TOD c_sec c_psec) = unsafePerformIO $ do
255     res <- allocWords (``sizeof(time_t)'')
256     ptr <- _ccall_ toClockSec year mon day hour min sec 0 res 
257     let (A# ptr#) = ptr
258     if ptr /= (``0''::Addr)
259      then let
260             diff_sec  = (int2Integer (indexIntOffAddr# ptr# 0#))
261             diff_psec = psec
262           in
263           return (TOD (c_sec + diff_sec) (c_psec + diff_psec))
264      else
265           error "Time.addToClockTime: can't perform conversion of TimeDiff"
266 #endif
267
268 diffClockTimes  :: ClockTime -> ClockTime -> TimeDiff
269 diffClockTimes tod_a tod_b =
270   let
271    CalendarTime year_a mon_a day_a hour_a min_a sec_a psec_a _ _ _ _ _ = toUTCTime tod_a
272    CalendarTime year_b mon_b day_b hour_b min_b sec_b psec_b _ _ _ _ _ = toUTCTime tod_b
273   in
274   TimeDiff (year_a - year_b) 
275            (mon_a  - mon_b) 
276            (day_a  - day_b)
277            (hour_a - hour_b)
278            (min_a  - min_b)
279            (sec_a  - sec_b)
280            (psec_a - psec_b)
281 \end{code}
282
283 @toCalendarTime@ {\em t} converts {\em t} to a local time, modified by
284 the current timezone and daylight savings time settings.  @toUTCTime@
285 {\em t} converts {\em t} into UTC time.  @toClockTime@ {\em l}
286 converts {\em l} into the corresponding internal @ClockTime@.  The
287 {\em wday}, {\em yday}, {\em tzname}, and {\em isdst} fields are
288 ignored.
289
290 \begin{code}
291 #ifdef __HUGS__
292 toCalendarTime :: ClockTime -> IO CalendarTime
293 toCalendarTime (TOD sec psec) = do
294     res    <- allocWords sizeof_int64
295     zoneNm <- allocChars 32
296     prim_SETZONE res zoneNm
297     rc <- prim_toLocalTime sec res
298     if rc /= 0
299      then constructErrorAndFail "Time.toCalendarTime: out of range"
300      else do
301        sec   <-  get_tm_sec   res
302        min   <-  get_tm_min   res
303        hour  <-  get_tm_hour  res
304        mday  <-  get_tm_mday  res
305        mon   <-  get_tm_mon   res
306        year  <-  get_tm_year  res
307        wday  <-  get_tm_wday  res
308        yday  <-  get_tm_yday  res
309        isdst <-  get_tm_isdst res
310        zone  <-  prim_ZONE    res
311        tz    <-  prim_GMTOFF  res
312        tzname <- primUnpackCString zone
313        return (CalendarTime (1900+year) mon mday hour min sec psec 
314                             (toEnum wday) yday tzname tz (isdst /= 0))
315
316 toUTCTime :: ClockTime -> CalendarTime
317 toUTCTime  (TOD sec psec) = unsafePerformIO $ do
318        res    <- allocWords sizeof_int64
319        zoneNm <- allocChars 32
320        prim_SETZONE res zoneNm
321        rc <- prim_toUTCTime sec res
322        if rc /= 0
323         then error "Time.toUTCTime: out of range"
324         else do
325             sec   <- get_tm_sec  res
326             min   <- get_tm_min  res
327             hour  <- get_tm_hour res
328             mday  <- get_tm_mday res
329             mon   <- get_tm_mon  res
330             year  <- get_tm_year res
331             wday  <- get_tm_wday res
332             yday  <- get_tm_yday res
333             return (CalendarTime (1900+year) mon mday hour min sec psec 
334                           (toEnum wday) yday "UTC" 0 False)
335
336 toClockTime :: CalendarTime -> ClockTime
337 toClockTime (CalendarTime year mon mday hour min sec psec wday yday tzname tz isdst) =
338     if psec < 0 || psec > 999999999999 then
339         error "Time.toClockTime: picoseconds out of range"
340     else if tz < -43200 || tz > 43200 then
341         error "Time.toClockTime: timezone offset out of range"
342     else
343         unsafePerformIO ( do
344             res <- allocWords sizeof_int64
345             rc <- prim_toClockSec year mon mday hour min sec isDst res
346             if rc /= 0
347              then do
348                tm <- primReadInt64Array res 0
349                return (TOD tm psec)
350              else error "Time.toClockTime: can't perform conversion"
351         )
352     where
353      isDst = if isdst then (1::Int) else 0
354 #else
355 toCalendarTime :: ClockTime -> IO CalendarTime
356 toCalendarTime (TOD sec@(J# a# s# d#) psec) = do
357     res    <- allocWords (``sizeof(struct tm)''::Int)
358     zoneNm <- allocChars 32
359     _casm_ ``SETZONE((struct tm *)%0,(char *)%1); '' res zoneNm
360     tm     <- _ccall_ toLocalTime (I# s#) d# res
361     if tm == (``NULL''::Addr) 
362      then constructErrorAndFail "Time.toCalendarTime: out of range"
363      else do
364        sec   <-  _casm_ ``%r = ((struct tm *)%0)->tm_sec;'' tm
365        min   <-  _casm_ ``%r = ((struct tm *)%0)->tm_min;'' tm
366        hour  <-  _casm_ ``%r = ((struct tm *)%0)->tm_hour;'' tm
367        mday  <-  _casm_ ``%r = ((struct tm *)%0)->tm_mday;'' tm
368        mon   <-  _casm_ ``%r = ((struct tm *)%0)->tm_mon;'' tm
369        year  <-  _casm_ ``%r = ((struct tm *)%0)->tm_year;'' tm
370        wday  <-  _casm_ ``%r = ((struct tm *)%0)->tm_wday;'' tm
371        yday  <-  _casm_ ``%r = ((struct tm *)%0)->tm_yday;'' tm
372        isdst <-  _casm_ ``%r = ((struct tm *)%0)->tm_isdst;'' tm
373        zone  <-  _ccall_ ZONE tm
374        tz    <-  _ccall_ GMTOFF tm
375        let tzname = unpackCString zone
376        return (CalendarTime (1900+year) mon mday hour min sec psec 
377                             (toEnum wday) yday tzname tz (isdst /= 0))
378
379 toUTCTime :: ClockTime -> CalendarTime
380 toUTCTime  (TOD sec@(J# a# s# d#) psec) = unsafePerformIO $ do
381        res    <- allocWords (``sizeof(struct tm)''::Int)
382        zoneNm <- allocChars 32
383        _casm_ ``SETZONE((struct tm *)%0,(char *)%1); '' res zoneNm
384        tm     <-  _ccall_ toUTCTime (I# s#) d# res
385        if tm == (``NULL''::Addr) 
386         then error "Time.toUTCTime: out of range"
387         else do
388             sec   <- _casm_ ``%r = ((struct tm *)%0)->tm_sec;'' tm
389             min   <- _casm_ ``%r = ((struct tm *)%0)->tm_min;'' tm
390             hour  <- _casm_ ``%r = ((struct tm *)%0)->tm_hour;'' tm
391             mday  <- _casm_ ``%r = ((struct tm *)%0)->tm_mday;'' tm
392             mon   <- _casm_ ``%r = ((struct tm *)%0)->tm_mon;'' tm
393             year  <- _casm_ ``%r = ((struct tm *)%0)->tm_year;'' tm
394             wday  <- _casm_ ``%r = ((struct tm *)%0)->tm_wday;'' tm
395             yday  <- _casm_ ``%r = ((struct tm *)%0)->tm_yday;'' tm
396             return (CalendarTime (1900+year) mon mday hour min sec psec 
397                           (toEnum wday) yday "UTC" 0 False)
398
399 toClockTime :: CalendarTime -> ClockTime
400 toClockTime (CalendarTime year mon mday hour min sec psec wday yday tzname tz isdst) =
401     if psec < 0 || psec > 999999999999 then
402         error "Time.toClockTime: picoseconds out of range"
403     else if tz < -43200 || tz > 43200 then
404         error "Time.toClockTime: timezone offset out of range"
405     else
406         unsafePerformIO ( do
407             res <- allocWords (``sizeof(time_t)'')
408             ptr <- _ccall_ toClockSec year mon mday hour min sec isDst res
409             let (A# ptr#) = ptr
410             if ptr /= ``NULL''
411              then return (TOD (int2Integer (indexIntOffAddr# ptr# 0#)) psec)
412              else error "Time.toClockTime: can't perform conversion"
413         )
414     where
415      isDst = if isdst then (1::Int) else 0
416 #endif
417
418 bottom :: (Int,Int)
419 bottom = error "Time.bottom"
420
421
422 -- (copied from PosixUtil, for now)
423 -- Allocate a mutable array of characters with no indices.
424
425 #ifdef __HUGS__
426 allocChars :: Int -> IO (PrimMutableByteArray RealWorld)
427 allocChars size = primNewByteArray size
428
429 -- Allocate a mutable array of words with no indices
430
431 allocWords :: Int -> IO (PrimMutableByteArray RealWorld)
432 allocWords size = primNewByteArray size
433 #else
434 allocChars :: Int -> IO (MutableByteArray RealWorld ())
435 allocChars (I# size#) = IO $ \ s# ->
436     case newCharArray# size# s# of 
437       (# s2#, barr# #) -> 
438         (# s2#, MutableByteArray bot barr# #)
439   where
440     bot = error "Time.allocChars"
441
442 -- Allocate a mutable array of words with no indices
443
444 allocWords :: Int -> IO (MutableByteArray RealWorld ())
445 allocWords (I# size#) = IO $ \ s# ->
446     case newIntArray# size# s# of 
447       (# s2#, barr# #) -> 
448         (# s2#, MutableByteArray bot barr# #)
449   where
450     bot = error "Time.allocWords"
451 #endif
452 \end{code}
453
454 \begin{code}
455 calendarTimeToString  :: CalendarTime -> String
456 calendarTimeToString  =  formatCalendarTime defaultTimeLocale "%c"
457
458 formatCalendarTime :: TimeLocale -> String -> CalendarTime -> String
459 formatCalendarTime l fmt ct@(CalendarTime year mon day hour min sec sdec 
460                                            wday yday tzname _ _) =
461         doFmt fmt
462   where doFmt ('%':c:cs) = decode c ++ doFmt cs
463         doFmt (c:cs) = c : doFmt cs
464         doFmt "" = ""
465
466         decode 'A' = fst (wDays l  !! fromEnum wday)
467         decode 'a' = snd (wDays l  !! fromEnum wday)
468         decode 'B' = fst (months l !! fromEnum mon)
469         decode 'b' = snd (months l !! fromEnum mon)
470         decode 'h' = snd (months l !! fromEnum mon)
471         decode 'C' = show2 (year `quot` 100)
472         decode 'c' = doFmt (dateTimeFmt l)
473         decode 'D' = doFmt "%m/%d/%y"
474         decode 'd' = show2 day
475         decode 'e' = show2' day
476         decode 'H' = show2 hour
477         decode 'I' = show2 (to12 hour)
478         decode 'j' = show3 yday
479         decode 'k' = show2' hour
480         decode 'l' = show2' (to12 hour)
481         decode 'M' = show2 min
482         decode 'm' = show2 (fromEnum mon+1)
483         decode 'n' = "\n"
484         decode 'p' = (if hour < 12 then fst else snd) (amPm l)
485         decode 'R' = doFmt "%H:%M"
486         decode 'r' = doFmt (time12Fmt l)
487         decode 'T' = doFmt "%H:%M:%S"
488         decode 't' = "\t"
489         decode 'S' = show2 sec
490         decode 's' = show2 sec -- Implementation-dependent, sez the lib doc..
491         decode 'U' = show2 ((yday + 7 - fromEnum wday) `div` 7)
492         decode 'u' = show (let n = fromEnum wday in 
493                            if n == 0 then 7 else n)
494         decode 'V' = 
495             let (week, days) = 
496                    (yday + 7 - if fromEnum wday > 0 then 
497                                fromEnum wday - 1 else 6) `divMod` 7
498             in  show2 (if days >= 4 then
499                           week+1 
500                        else if week == 0 then 53 else week)
501
502         decode 'W' = 
503             show2 ((yday + 7 - if fromEnum wday > 0 then 
504                                fromEnum wday - 1 else 6) `div` 7)
505         decode 'w' = show (fromEnum wday)
506         decode 'X' = doFmt (timeFmt l)
507         decode 'x' = doFmt (dateFmt l)
508         decode 'Y' = show year
509         decode 'y' = show2 (year `rem` 100)
510         decode 'Z' = tzname
511         decode '%' = "%"
512         decode c   = [c]
513
514 show2, show2', show3 :: Int -> String
515 show2 x = [intToDigit (x `quot` 10), intToDigit (x `rem` 10)]
516
517 show2' x = if x < 10 then [ ' ', intToDigit x] else show2 x
518
519 show3 x = intToDigit (x `quot` 100) : show2 (x `rem` 100)
520
521 to12 h = let h' = h `mod` 12 in if h == 0 then 12 else h
522 \end{code}
523
524 \begin{code}
525 timeDiffToString :: TimeDiff -> String
526 timeDiffToString = formatTimeDiff defaultTimeLocale "%c"
527
528 formatTimeDiff :: TimeLocale -> String -> TimeDiff -> String
529 formatTimeDiff l fmt ct@(TimeDiff year month day hour min sec psec)
530  = doFmt fmt
531   where 
532    doFmt ""         = ""
533    doFmt ('%':c:cs) = decode c ++ doFmt cs
534    doFmt (c:cs)     = c : doFmt cs
535
536    decode spec =
537     case spec of
538       'B' -> fst (months l !! fromEnum month)
539       'b' -> snd (months l !! fromEnum month)
540       'h' -> snd (months l !! fromEnum month)
541       'C' -> show2 (year `quot` 100)
542       'D' -> doFmt "%m/%d/%y"
543       'd' -> show2 day
544       'e' -> show2' day
545       'H' -> show2 hour
546       'I' -> show2 (to12 hour)
547       'k' -> show2' hour
548       'l' -> show2' (to12 hour)
549       'M' -> show2 min
550       'm' -> show2 (fromEnum month + 1)
551       'n' -> "\n"
552       'p' -> (if hour < 12 then fst else snd) (amPm l)
553       'R' -> doFmt "%H:%M"
554       'r' -> doFmt (time12Fmt l)
555       'T' -> doFmt "%H:%M:%S"
556       't' -> "\t"
557       'S' -> show2 sec
558       's' -> show2 sec -- Implementation-dependent, sez the lib doc..
559       'X' -> doFmt (timeFmt l)
560       'x' -> doFmt (dateFmt l)
561       'Y' -> show year
562       'y' -> show2 (year `rem` 100)
563       '%' -> "%"
564       c   -> [c]
565
566 \end{code}
567
568 \begin{code}
569 #ifdef __HUGS__
570 foreign import stdcall "libHS_cbits.so" "get_tm_sec"   get_tm_sec   :: Bytes -> IO Int
571 foreign import stdcall "libHS_cbits.so" "get_tm_min"   get_tm_min   :: Bytes -> IO Int
572 foreign import stdcall "libHS_cbits.so" "get_tm_hour"  get_tm_hour  :: Bytes -> IO Int
573 foreign import stdcall "libHS_cbits.so" "get_tm_mday"  get_tm_mday  :: Bytes -> IO Int
574 foreign import stdcall "libHS_cbits.so" "get_tm_mon"   get_tm_mon   :: Bytes -> IO Int
575 foreign import stdcall "libHS_cbits.so" "get_tm_year"  get_tm_year  :: Bytes -> IO Int
576 foreign import stdcall "libHS_cbits.so" "get_tm_wday"  get_tm_wday  :: Bytes -> IO Int
577 foreign import stdcall "libHS_cbits.so" "get_tm_yday"  get_tm_yday  :: Bytes -> IO Int
578 foreign import stdcall "libHS_cbits.so" "get_tm_isdst" get_tm_isdst :: Bytes -> IO Int
579
580 foreign import stdcall "libHS_cbits.so" "prim_ZONE"    prim_ZONE    :: Bytes -> IO Addr
581 foreign import stdcall "libHS_cbits.so" "prim_GMTOFF"  prim_GMTOFF  :: Bytes -> IO Int
582
583 foreign import stdcall "libHS_cbits.so" "prim_SETZONE" prim_SETZONE :: Bytes -> Bytes -> IO Int
584
585 foreign import stdcall "libHS_cbits.so" "sizeof_word"      sizeof_word      :: Int
586 foreign import stdcall "libHS_cbits.so" "sizeof_struct_tm" sizeof_struct_tm :: Int
587 foreign import stdcall "libHS_cbits.so" "sizeof_time_t"    sizeof_time_t    :: Int
588
589 -- believed to be at least 1 bit (the sign bit!) bigger than sizeof_time_t
590 sizeof_int64 :: Int
591 sizeof_int64 = 8
592
593 foreign import stdcall "libHS_cbits.so" "prim_getClockTime" prim_getClockTime :: Bytes -> Bytes -> IO Int
594 foreign import stdcall "libHS_cbits.so" "prim_toClockSec"   prim_toClockSec   :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Bytes -> IO Int
595 foreign import stdcall "libHS_cbits.so" "prim_toLocalTime"  prim_toLocalTime  :: Int64 -> Bytes -> IO Int
596 foreign import stdcall "libHS_cbits.so" "prim_toUTCTime"    prim_toUTCTime    :: Int64 -> Bytes -> IO Int
597 #endif
598 \end{code}