-
Notifications
You must be signed in to change notification settings - Fork 70
Expand file tree
/
Copy pathPrinter.hs
More file actions
159 lines (128 loc) · 5.75 KB
/
Copy pathPrinter.hs
File metadata and controls
159 lines (128 loc) · 5.75 KB
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
{-# LANGUAGE BangPatterns, ViewPatterns #-}
------------------------------------------------------------------------------
-- Module: Database.PostgreSQL.Simple.Time.Internal.Printer
-- Copyright: (c) 2012-2015 Leon P Smith
-- License: BSD3
-- Maintainer: Leon P Smith <leon@melding-monads.com>
-- Stability: experimental
------------------------------------------------------------------------------
module Database.PostgreSQL.Simple.Time.Internal.Printer
(
day
, timeOfDay
, timeZone
, utcTime
, localTime
, zonedTime
, nominalDiffTime
, interval
) where
import Control.Arrow ((>>>))
import Data.ByteString.Builder (Builder, integerDec)
import Data.ByteString.Builder.Prim
( liftFixedToBounded, (>$<), (>*<)
, BoundedPrim, primBounded, condB, emptyB, FixedPrim, char8, int32Dec, int64Dec, primFixed)
import Data.Char ( chr )
import Data.Int ( Int32, Int64 )
import Data.Time
( UTCTime(..), ZonedTime(..), LocalTime(..), NominalDiffTime
, Day, toGregorian, TimeOfDay(..), timeToTimeOfDay
, TimeZone, timeZoneMinutes )
import Database.PostgreSQL.Simple.Compat ((<>), fromPico)
import Database.PostgreSQL.Simple.Time.Interval (Interval(..))
import Unsafe.Coerce (unsafeCoerce)
liftB :: FixedPrim a -> BoundedPrim a
liftB = liftFixedToBounded
digit :: FixedPrim Int
digit = (\x -> chr (x + 48)) >$< char8
digits2 :: FixedPrim Int
digits2 = (`quotRem` 10) >$< (digit >*< digit)
digits3 :: FixedPrim Int
digits3 = (`quotRem` 10) >$< (digits2 >*< digit)
digits4 :: FixedPrim Int
digits4 = (`quotRem` 10) >$< (digits3 >*< digit)
frac :: BoundedPrim Int64
frac = condB (== 0) emptyB ((,) '.' >$< (liftB char8 >*< trunc12))
where
trunc12 :: BoundedPrim Int64
trunc12 = (`quotRem` 1000000) >$<
condB (\(_,y) -> y == 0)
(fst >$< trunc6)
(liftB digits6 >*< trunc6)
digitB = liftB digit
digits6 = (fromIntegral >>> (`quotRem` 10)) >$< (digits5 >*< digit)
digits5 = (`quotRem` 10) >$< (digits4 >*< digit)
trunc6 = (fromIntegral >>> (`quotRem` 100000)) >$< (digitB >*< trunc5)
trunc5 = condB (== 0) emptyB ((`quotRem` 10000) >$< (digitB >*< trunc4))
trunc4 = condB (== 0) emptyB ((`quotRem` 1000) >$< (digitB >*< trunc3))
trunc3 = condB (== 0) emptyB ((`quotRem` 100) >$< (digitB >*< trunc2))
trunc2 = condB (== 0) emptyB ((`quotRem` 10) >$< (digitB >*< trunc1))
trunc1 = condB (== 0) emptyB digitB
year :: BoundedPrim Int32
year = condB (> 10000) int32Dec (checkBCE >$< liftB digits4)
where
checkBCE :: Int32 -> Int
checkBCE y
| y > 0 = fromIntegral y
| otherwise = error msg
msg = "Database.PostgreSQL.Simple.Time.Printer.year: years BCE not supported"
day :: BoundedPrim Day
day = toYMD >$< (year >*< liftB (char8 >*< digits2 >*< char8 >*< digits2))
where
toYMD (toGregorian -> (fromIntegral -> !y, !m,!d)) = (y,('-',(m,('-',d))))
timeOfDay :: BoundedPrim TimeOfDay
timeOfDay = f >$< (hh_mm_ >*< ss)
where
f (TimeOfDay h m s) = ((h,(':',(m,':'))),s)
hh_mm_ = liftB (digits2 >*< char8 >*< digits2 >*< char8)
ss = (\s -> fromIntegral (fromPico s) `quotRem` 1000000000000) >$<
(liftB (fromIntegral >$< digits2) >*< frac)
timeZone :: BoundedPrim TimeZone
timeZone = timeZoneMinutes >$< tz
where
tz = condB (>= 0) ((,) '+' >$< tzh) ((,) '-' . negate >$< tzh)
tzh = liftB char8 >*< ((`quotRem` 60) >$< (liftB digits2 >*< tzm))
tzm = condB (==0) emptyB ((,) ':' >$< liftB (char8 >*< digits2))
utcTime :: BoundedPrim UTCTime
utcTime = f >$< (day >*< liftB char8 >*< timeOfDay >*< liftB char8)
where f (UTCTime d (timeToTimeOfDay -> tod)) = (d,(' ',(tod,'Z')))
localTime :: BoundedPrim LocalTime
localTime = f >$< (day >*< liftB char8 >*< timeOfDay)
where f (LocalTime d tod) = (d, (' ', tod))
zonedTime :: BoundedPrim ZonedTime
zonedTime = f >$< (localTime >*< timeZone)
where f (ZonedTime lt tz) = (lt, tz)
nominalDiffTime :: NominalDiffTime -> Builder
nominalDiffTime xy = integerDec x <> primBounded frac (abs (fromIntegral y))
where
(x,y) = fromPico (unsafeCoerce xy) `quotRem` 1000000000000
interval :: Interval -> Builder
interval x = boundedPrefix <> integerDec afterSeconds <> fixedSuffix
where
(hours, afterHours) = intervalMicroseconds x `quotRem` 3600000000
(minutes, afterMinutes) = afterHours `quotRem` 60000000
(seconds, afterSeconds) = afterMinutes `quotRem` 1000000
boundedPrefix = primBounded
(int32Dec >*<
liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*<
int32Dec >*<
liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*<
int64Dec >*<
liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*<
int64Dec >*<
liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*<
int64Dec >*<
liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8 >*< liftB char8)
(intervalMonths x,
(' ', ('m', ('o', ('n', ('s', (' ',
(intervalDays x,
(' ', ('d', ('a', ('y', ('s', (' ',
(fromIntegral hours,
(' ', ('h', ('o', ('u', ('r', ('s', (' ',
(fromIntegral minutes,
(' ', ('m', ('i', ('n', ('s', (' ',
(fromIntegral seconds,
(' ', ('s', ('e', ('c', ('s', ' ')))))))))))))))))))))))))))))))))))
fixedSuffix = primFixed (char8 >*< char8 >*< char8 >*< char8 >*< char8 >*< char8 >*< char8 >*< char8 >*<
char8 >*< char8 >*< char8 >*< char8 >*< char8)
(' ', ('m', ('i', ('c', ('r', ('o', ('s', ('e', ('c', ('o', ('n', ('d', 's'))))))))))))