File: Converter.hs

package info (click to toggle)
haskell-http-date 0.0.11-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 92 kB
  • sloc: haskell: 349; makefile: 2
file content (132 lines) | stat: -rw-r--r-- 3,823 bytes parent folder | download | duplicates (2)
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
{-# LANGUAGE BangPatterns #-}
module Network.HTTP.Date.Converter ( epochTimeToHTTPDate
                                   , httpDateToUTC
                                   , utcToHTTPDate
                                   ) where

import Data.Time
import Data.Time.Calendar.WeekDate
import Data.Word
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.Storable
import Network.HTTP.Date.Types
import System.IO.Unsafe (unsafeDupablePerformIO, unsafePerformIO)
import System.Posix.Types

{-|
  Translating 'EpochTime' to 'HTTPDate'.
-}
epochTimeToHTTPDate :: EpochTime -> HTTPDate
epochTimeToHTTPDate x = defaultHTTPDate {
    hdYear   = y
  , hdMonth  = m
  , hdDay    = d
  , hdHour   = h
  , hdMinute = n
  , hdSecond = s
  , hdWkday  = w
  }
  where
    w64 :: Word64
    w64 = fromIntegral $ fromEnum x
    (days',secs') = w64 `quotRem` 86400
    days = fromIntegral days'
    secs = fromIntegral secs'
    -- 1970/1/1 is Thu (4)
    w = (days + 3) `rem` 7 + 1
    (y,m,d) = toYYMMDD days
    (h,n,s) = toHHMMSS secs

-- | Translating 'HTTPDate' to 'UTCTime'.
--
--   Since 0.0.7.
httpDateToUTC :: HTTPDate -> UTCTime
httpDateToUTC x = UTCTime (fromGregorian y m d) (secondsToDiffTime s)
  where
    y = fromIntegral $ hdYear x
    m = hdMonth x
    d = hdDay x
    s = fromIntegral $ (hdHour   x `rem` 24) * 3600
                     + (hdMinute x `rem` 60) * 60
                     + (hdSecond x `rem` 60)

-- | Translating 'UTCTime' to 'HTTPDate'.
--
--   Since 0.0.7.
utcToHTTPDate :: UTCTime -> HTTPDate
utcToHTTPDate x = defaultHTTPDate {
    hdYear   = fromIntegral y
  , hdMonth  = m
  , hdDay    = d
  , hdHour   = h
  , hdMinute = n
  , hdSecond = truncate s
  , hdWkday  = fromEnum (w :: Int)
  }
  where
    (y, m, d) = toGregorian day
    (h, n, s) = ((todHour tod), (todMin tod), (todSec tod))
    (_, _, w) = toWeekDate day
    day       = localDay time
    tod       = localTimeOfDay time
    time      = utcToLocalTime utc x

toYYMMDD :: Int -> (Int,Int,Int)
toYYMMDD x = (yy, mm, dd)
  where
    (y,d) = x `quotRem` 365
    cy = 1970 + y
    cy' = cy - 1
    leap = cy' `quot` 4 - cy' `quot` 100 + cy' `quot` 400 - 477
    (yy,days) = adjust cy d leap
    (mm,dd) = findMonth days
    adjust !ty td aj
      | td >= aj        = (ty, td - aj)
      | isLeap (ty - 1) = if td + 366 >= aj
                          then (ty - 1, td + 366 - aj)
                          else adjust (ty - 1) (td + 366) aj
      | otherwise       = if td + 365 >= aj
                          then (ty - 1, td + 365 - aj)
                          else adjust (ty - 1) (td + 365) aj
    isLeap year = year `rem` 4 == 0
              && (year `rem` 400 == 0 ||
                  year `rem` 100 /= 0)
    (mnths, daysArr) = if isLeap yy
      then (leapMonth, leapDayInMonth)
      else (normalMonth, normalDayInMonth)
    findMonth n = unsafeDupablePerformIO $ (,) <$> (peekElemOff mnths n) <*> (peekElemOff daysArr n)

----------------------------------------------------------------

normalMonthDays :: [Int]
normalMonthDays = [31,28,31,30,31,30,31,31,30,31,30,31]

leapMonthDays :: [Int]
leapMonthDays   = [31,29,31,30,31,30,31,31,30,31,30,31]

mkPtrInt :: [Int] -> Ptr Int
mkPtrInt = unsafePerformIO . newArray . concat . zipWith (flip replicate) [1..]

mkPtrInt2 :: [Int] -> Ptr Int
mkPtrInt2 = unsafePerformIO . newArray . concatMap (enumFromTo 1)

normalMonth :: Ptr Int
normalMonth = mkPtrInt normalMonthDays

normalDayInMonth :: Ptr Int
normalDayInMonth = mkPtrInt2 normalMonthDays

leapMonth :: Ptr Int
leapMonth = mkPtrInt leapMonthDays

leapDayInMonth :: Ptr Int
leapDayInMonth = mkPtrInt2 leapMonthDays

----------------------------------------------------------------

toHHMMSS :: Int -> (Int,Int,Int)
toHHMMSS x = (hh,mm,ss)
  where
    (hhmm,ss) = x `quotRem` 60
    (hh,mm) = hhmm `quotRem` 60