/Data/Time/LocalTime/TimeZone.hs

http://github.com/takano-akio/time · Haskell · 99 lines · 63 code · 18 blank · 18 comment · 2 complexity · 1b328d2f5b8108407d73500a1d6620d0 MD5 · raw file

  1. {-# OPTIONS -fno-warn-unused-imports #-}
  2. {-# LANGUAGE ForeignFunctionInterface #-}
  3. #include "HsConfigure.h"
  4. -- #hide
  5. module Data.Time.LocalTime.TimeZone
  6. (
  7. -- * Time zones
  8. TimeZone(..),timeZoneOffsetString,timeZoneOffsetString',minutesToTimeZone,hoursToTimeZone,utc,
  9. -- getting the locale time zone
  10. getTimeZone,getCurrentTimeZone
  11. ) where
  12. --import System.Time.Calendar.Format
  13. import Data.Time.Calendar.Private
  14. import Data.Time.Clock
  15. import Data.Time.Clock.POSIX
  16. import Foreign
  17. import Foreign.C
  18. import Control.DeepSeq
  19. import Data.Typeable
  20. #if LANGUAGE_Rank2Types
  21. import Data.Data
  22. #endif
  23. -- | A TimeZone is a whole number of minutes offset from UTC, together with a name and a \"just for summer\" flag.
  24. data TimeZone = TimeZone {
  25. -- | The number of minutes offset from UTC. Positive means local time will be later in the day than UTC.
  26. timeZoneMinutes :: Int,
  27. -- | Is this time zone just persisting for the summer?
  28. timeZoneSummerOnly :: Bool,
  29. -- | The name of the zone, typically a three- or four-letter acronym.
  30. timeZoneName :: String
  31. } deriving (Eq,Ord
  32. #if LANGUAGE_DeriveDataTypeable
  33. #if LANGUAGE_Rank2Types
  34. ,Data
  35. #endif
  36. #endif
  37. )
  38. instance NFData TimeZone where
  39. rnf (TimeZone m so n) = m `deepseq` so `deepseq` n `deepseq` ()
  40. instance Typeable TimeZone where
  41. typeOf _ = mkTyConApp (mkTyCon "Data.Time.LocalTime.TimeZone.TimeZone") []
  42. -- | Create a nameless non-summer timezone for this number of minutes
  43. minutesToTimeZone :: Int -> TimeZone
  44. minutesToTimeZone m = TimeZone m False ""
  45. -- | Create a nameless non-summer timezone for this number of hours
  46. hoursToTimeZone :: Int -> TimeZone
  47. hoursToTimeZone i = minutesToTimeZone (60 * i)
  48. showT :: NumericPadOption -> Int -> String
  49. showT opt t = show4 opt ((div t 60) * 100 + (mod t 60))
  50. -- | Text representing the offset of this timezone, such as \"-0800\" or \"+0400\" (like %z in formatTime), with arbitrary padding
  51. timeZoneOffsetString' :: NumericPadOption -> TimeZone -> String
  52. timeZoneOffsetString' opt (TimeZone t _ _) | t < 0 = '-':(showT opt (negate t))
  53. timeZoneOffsetString' opt (TimeZone t _ _) = '+':(showT opt t)
  54. -- | Text representing the offset of this timezone, such as \"-0800\" or \"+0400\" (like %z in formatTime)
  55. timeZoneOffsetString :: TimeZone -> String
  56. timeZoneOffsetString = timeZoneOffsetString' (Just '0')
  57. instance Show TimeZone where
  58. show zone@(TimeZone _ _ "") = timeZoneOffsetString zone
  59. show (TimeZone _ _ name) = name
  60. -- | The UTC time zone
  61. utc :: TimeZone
  62. utc = TimeZone 0 False "UTC"
  63. {-# CFILES cbits/HsTime.c #-}
  64. foreign import ccall unsafe "HsTime.h get_current_timezone_seconds" get_current_timezone_seconds :: CTime -> Ptr CInt -> Ptr CString -> IO CLong
  65. posixToCTime :: POSIXTime -> CTime
  66. posixToCTime = fromInteger . floor
  67. -- | Get the local time-zone for a given time (varying as per summertime adjustments)
  68. getTimeZone :: UTCTime -> IO TimeZone
  69. getTimeZone time = with 0 (\pdst -> with nullPtr (\pcname -> do
  70. secs <- get_current_timezone_seconds (posixToCTime (utcTimeToPOSIXSeconds time)) pdst pcname
  71. case secs of
  72. 0x80000000 -> fail "localtime_r failed"
  73. _ -> do
  74. dst <- peek pdst
  75. cname <- peek pcname
  76. name <- peekCString cname
  77. return (TimeZone (div (fromIntegral secs) 60) (dst == 1) name)
  78. ))
  79. -- | Get the current time-zone
  80. getCurrentTimeZone :: IO TimeZone
  81. getCurrentTimeZone = getCurrentTime >>= getTimeZone