0 | module Data.Regex.DateAndTime
13 | show (D y m d) = show y ++ "-" ++ show m ++ "-" ++ show d
25 | show (T h m s ms) = show h ++ ":" ++ show m ++ ":" ++ show s ++ "." ++ show ms
28 | record DateTime where
35 | show (DT d t) = show d ++ "T" ++ show t
37 | int : Char -> Integer
38 | int c = cast c - cast '0'
40 | hourConv : Either (Char, Char) Char -> Integer
41 | hourConv (Left (t, d)) = 10 * int t + int d
42 | hourConv (Right d) = 20 + int d
44 | yearConv : (Integer, Integer, Integer, Integer) -> Integer
45 | yearConv (th, h, t, d) = 1000 * th + 100 * h + 10 * t + d
47 | dayConv : Either (Bool, Char) (Char, Char) -> Integer
48 | dayConv (Left (_, d)) = int d
49 | dayConv (Right (t, d)) = 10 * int t + int d
51 | monthConv : Either (Bool, Char) Char -> Integer
52 | monthConv (Left (_, c)) = int c
53 | monthConv (Right c) = 10 + int c
57 | hour = hourConv `map` r "(([01][0-9])|(2[0-4]))!"
61 | mOrS = (\case(t, d) => 10 * int t + int d) `map` r ":([0-5][0-9])!"
63 | milis : TyRE Integer
64 | milis = (\case (h, t, d) => 100 * h + 10 * t + d) `map` match '.' *> digit <*> (digit <*> digit)
68 | year = yearConv `map` repTimes 4 digit
72 | day = dayConv `map` r "((0?[1-9])|([12][0-9]))!"
75 | month : TyRE Integer
76 | month = monthConv `map` r "((0?[1-9])|(1[0-2]))!"
82 | let thirtieth := map ((withSnd 30) . monthConv)
83 | (r "(30/((0?[13456789])|(1[012])))!")
84 | thirtyfirst := map ((withSnd 31) . monthConv)
85 | (r "(31/((0?[13578])|(1[02])))!")
86 | in map (\case ((d, m), y) => D y m d) $
87 | ((((day <* match '/') <*> month) `or` thirtieth) `or` thirtyfirst)
88 | <*> (match '/' *> year) where
89 | withSnd : Integer -> (Integer -> (Integer, Integer))
90 | withSnd fst snd = (fst, snd)
97 | time = conv `map` hour <*> (mOrS <*> option mOrS) where
98 | conv : (Integer, Integer, Maybe Integer) -> Time
99 | conv (h, m, Just s) = T h m s 0
100 | conv (h, m, Nothing) = T h m 0 0
110 | iso : TyRE DateTime
112 | let thirtieth := ((withFst 30) . monthConv) `map` r "(((0?[13456789])|(1[012]))\\-30)!"
113 | thirtyfirst := ((withFst 31) . monthConv) `map` r "(((0?[13578])|(1[02]))\\-31)!"
114 | date := map (\case (y, m, d) => D y m d) $
115 | (year <* match '-') <*>
116 | ((((month <* match '-') <*> day) `or` thirtieth) `or` thirtyfirst)
117 | time := convTime `map` hour <*> (mOrS <*> option (mOrS <*> option milis))
118 | timeZone := match 'Z' <|> ((match '+' <|> match '-') <*> (hour <*> mOrS))
119 | in conv `map` (date <*> option (convTimeWithZone `map` (match 'T' *> time <*> option timeZone))) where
120 | withFst : Integer -> (Integer -> (Integer, Integer))
121 | withFst snd fst = (fst, snd)
123 | convTime : (Integer, Integer, Maybe (Integer, Maybe Integer)) -> Time
124 | convTime (h, m, Just (s, Just ms)) = T h m s ms
125 | convTime (h, m, Just (s, _)) = T h m s 0
126 | convTime (h, m, _) = T h m 0 0
128 | convTimeWithZone : (Time, Maybe (Either () ((Either () ()), Integer, Integer))) -> (Time, Maybe Bool)
129 | convTimeWithZone (T hr min sec milis, Just (Right (Right _, h, m))) =
130 | let totMin := min + m
131 | (minutes, plusHour) := if totMin > 59 then (totMin - 60, 1) else (totMin, 0)
132 | totHr := hr + h + plusHour
133 | (hours, plusDay) := if totHr > 23 then (totHr - 24, Just True) else (totHr, Nothing)
134 | in (T hours minutes sec milis, plusDay)
135 | convTimeWithZone (T hr min sec milis, Just (Right (Left _, h, m))) =
136 | let totMin := min - m
137 | (minutes, minHour) := if totMin < 0 then (totMin + 60, 1) else (totMin, 0)
138 | totHr := hr - h - minHour
139 | (hours, minDay) := if totHr < 0 then (totHr + 24, Just False) else (totHr, Nothing)
140 | in (T hours minutes sec milis, minDay)
141 | convTimeWithZone (time, _) = (time, Nothing)
143 | conv : (Date, Maybe (Time, Maybe Bool)) -> DateTime
144 | conv (D y m d, Just (time, Just True)) =
146 | if (d == 30 && (m == 4 || m == 6 || m == 9 || m == 11))
147 | || (d == 31 && (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10))
149 | ( (d == 29 && mod y 4 == 0 && mod y 100 /= 0)
150 | || (d == 28 && (mod y 4 /= 0 || mod y 100 == 0))))
152 | else if (d == 31 && m == 12) then D 1 1 (y + 1) else D (d + 1) m y
154 | conv (D y m d, Just (time, Just False)) =
157 | then if m == 1 then D (y - 1) 12 31
159 | if (m == 5 || m == 7 || m == 10 || m == 12)
160 | then D y (m - 1) 31
162 | if (m == 2 || m == 4 || m == 6 || m == 8 || m == 9 || m == 11)
163 | then D y (m - 1) 30
165 | if (mod y 4 == 0 && mod y 100 /= 0)
166 | then D y (m - 1) 29
167 | else D y (m - 1) 28
171 | conv (date, Just (time, _)) = DT date time
172 | conv (date, _) = DT date (T 0 0 0 0)