0 | module IotaTime.Pattern.LocalTime
3 | import Data.String.Parser
4 | import IotaTime.Locale
5 | import IotaTime.LocalTime
6 | import IotaTime.Internal.Text
7 | import IotaTime.Pattern
13 | record TimeFieldsRep where
14 | constructor MkTimeFields
15 | parsedHour : Integer
16 | parsedMinute : Integer
17 | parsedSecond : Integer
18 | parsedNanosecond : Integer
23 | TimeFields = TimeFieldsRep
29 | timeFields : (hour : Integer) -> (minute : Integer) -> (second : Integer) ->
30 | (nanosecond : Integer) -> TimeFields
31 | timeFields = MkTimeFields
33 | initialTimeFields : TimeFields
34 | initialTimeFields = timeFields 0 0 0 0
36 | finishTime : TimeFields -> Either PatternError LocalTime
37 | finishTime fields = case refineLocalTime
38 | fields.parsedHour fields.parsedMinute fields.parsedSecond fields.parsedNanosecond of
39 | Left _ => Left (InvalidValue "invalid local time")
40 | Right value => Right value
42 | setHour : Integer -> TimeFields -> TimeFields
43 | setHour value fields = { parsedHour := value } fields
45 | setMinute : Integer -> TimeFields -> TimeFields
46 | setMinute value fields = { parsedMinute := value } fields
48 | setSecond : Integer -> TimeFields -> TimeFields
49 | setSecond value fields = { parsedSecond := value } fields
51 | setNanosecond : Integer -> TimeFields -> TimeFields
52 | setNanosecond value fields = { parsedNanosecond := value } fields
54 | timeHour : LocalTime -> Integer
55 | timeHour = hourValue . hour
57 | timeMinute : LocalTime -> Integer
58 | timeMinute = minuteValue . minute
60 | timeSecond : LocalTime -> Integer
61 | timeSecond = secondValue . second
63 | timeNanosecond : LocalTime -> Integer
64 | timeNanosecond = nanosecondValue . nanosecond
66 | timeField : (LocalTime -> Integer) -> (Integer -> TimeFields -> TimeFields) ->
67 | (width : Nat) -> (maximumWidth : Nat) ->
68 | (minimum : Integer) -> (maximum : Integer) ->
69 | Pattern TimeFields LocalTime
70 | timeField getter setter width maximumWidth minimum maximum = MkPattern
73 | (numberUpdatePart setter width maximumWidth minimum maximum)
74 | (zeroPadInteger width . getter)
78 | phour : Nat -> Pattern TimeFields LocalTime
79 | phour width = timeField timeHour setHour width 2 0 23
83 | pHH : Pattern TimeFields LocalTime
86 | setTwelveHour : Integer -> TimeFields -> TimeFields
87 | setTwelveHour value fields =
88 | { parsedHour := 12 * (fields.parsedHour `div` 12) + value `mod` 12 } fields
90 | formatTwelveHour : LocalTime -> Integer
91 | formatTwelveHour value =
92 | let folded = timeHour value `mod` 12
93 | in if folded == 0 then 12 else folded
97 | phh : Pattern TimeFields LocalTime
101 | (numberUpdatePart setTwelveHour 2 2 1 12)
102 | (zeroPadInteger 2 . formatTwelveHour)
106 | phhSpace : Pattern TimeFields LocalTime
107 | phhSpace = MkPattern
110 | (spaceNumberUpdatePart setTwelveHour 2 1 12)
111 | (padIntegerWith ' ' 2 . formatTwelveHour)
115 | pminute : Nat -> Pattern TimeFields LocalTime
116 | pminute width = timeField timeMinute setMinute width 2 0 59
120 | pmm : Pattern TimeFields LocalTime
125 | psecond : Nat -> Pattern TimeFields LocalTime
126 | psecond width = timeField timeSecond setSecond width 2 0 59
130 | pss : Pattern TimeFields LocalTime
133 | pow10 : Nat -> Integer
135 | pow10 (S exponent) = 10 * pow10 exponent
139 | isValidFractionWidth : Nat -> Bool
140 | isValidFractionWidth width = width >= 1 && width <= 9
146 | pfrac : (width : Nat) -> {auto 0 valid : So (isValidFractionWidth width)} ->
147 | Pattern TimeFields LocalTime
149 | let scale = pow10 (9 `minus` width)
150 | maximum = pow10 width - 1
154 | (numberUpdatePart (\value => setNanosecond (value * scale))
155 | width width 0 maximum)
156 | (zeroPadInteger width . (`div` scale) . timeNanosecond)
158 | setPeriod : Bool -> TimeFields -> TimeFields
159 | setPeriod isPm fields =
160 | { parsedHour := fields.parsedHour `mod` 12 + if isPm then 12 else 0 } fields
162 | periodPattern : String -> String -> Pattern TimeFields LocalTime
163 | periodPattern am pm = MkPattern
166 | (namedUpdatePart [(pm, True), (am, False)] setPeriod)
167 | (\value => if timeHour value >= 12 then pm else am)
171 | pPeriod : (String, String) -> Pattern TimeFields LocalTime
172 | pPeriod (am, pm) = periodPattern am pm
176 | pp : Pattern TimeFields LocalTime
177 | pp = periodPattern "A" "P"
181 | ppp : Pattern TimeFields LocalTime
182 | ppp = periodPattern "AM" "PM"
186 | ppp' : Locale -> Pattern TimeFields LocalTime
187 | ppp' locale = periodPattern (amName locale) (pmName locale)
191 | pt : Pattern TimeFields LocalTime
192 | pt = (pHH <% char ':') <+> pmm
196 | pT : Pattern TimeFields LocalTime
197 | pT = ((pHH <% char ':') <+> (pmm <% char ':')) <+> pss
201 | pr : Pattern TimeFields LocalTime
202 | pr = (pT <% char '.') <+> pfrac 9