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