1
1
{-# LANGUAGE FlexibleContexts #-}
2
2
3
- {- |
4
- Module : Text.Megaparsec.Time
5
- Description : Various parsers for types related to time.
6
- Copyright : (c) drlkf, 2024
7
- License : GPL-3
8
-
9
- Stability : experimental
10
- -}
11
-
12
- module Text.Megaparsec.Time
13
- ( DayResult
14
-
15
- , dateParser
16
- , dayParser
17
- , durationParser
18
- , gregorianDayParser
19
- , hoursParser
20
- , minutesParser
21
- , secondsParser
22
- , timeParser
23
- ) where
24
-
25
- import Control.Applicative (optional , (<|>) )
26
- import Control.Monad (replicateM )
27
- import Control.Monad.Combinators (choice , some )
28
- import Data.Char (toLower )
29
- import Data.Functor (($>) )
30
- import Data.Maybe (fromMaybe )
31
- import Data.Time (Day , DayOfWeek (.. ),
32
- NominalDiffTime , TimeOfDay (.. ),
33
- defaultTimeLocale ,
34
- makeTimeOfDayValid , parseTimeM ,
35
- secondsToNominalDiffTime )
36
- import Text.Megaparsec (Parsec , takeRest , try )
37
- import Text.Megaparsec.Char (char , digitChar , space , space1 ,
38
- string' )
39
- import Text.Megaparsec.Utils (posNumParser )
40
- import Text.Printf (printf )
3
+ -- |
4
+ -- Module : Text.Megaparsec.Time
5
+ -- Description : Various parsers for types related to time.
6
+ -- Copyright : (c) drlkf, 2024
7
+ -- License : GPL-3
8
+
9
+ -- Stability : experimental
10
+ module Text.Megaparsec.Time (
11
+ DayResult ,
12
+ dateParser ,
13
+ dayParser ,
14
+ durationParser ,
15
+ gregorianDayParser ,
16
+ hoursParser ,
17
+ minutesParser ,
18
+ secondsParser ,
19
+ timeParser ,
20
+ ) where
21
+
22
+ import Control.Applicative (optional , (<|>) )
23
+ import Control.Monad (replicateM )
24
+ import Control.Monad.Combinators (choice , some )
25
+ import Data.Char (toLower )
26
+ import Data.Functor (($>) )
27
+ import Data.Maybe (fromMaybe )
28
+ import Data.Time (
29
+ Day ,
30
+ DayOfWeek (.. ),
31
+ NominalDiffTime ,
32
+ TimeOfDay (.. ),
33
+ defaultTimeLocale ,
34
+ makeTimeOfDayValid ,
35
+ parseTimeM ,
36
+ secondsToNominalDiffTime ,
37
+ )
38
+ import Text.Megaparsec (Parsec , takeRest , try )
39
+ import Text.Megaparsec.Char (
40
+ char ,
41
+ digitChar ,
42
+ space ,
43
+ space1 ,
44
+ string' ,
45
+ )
46
+ import Text.Megaparsec.Utils (posNumParser )
47
+ import Text.Printf (printf )
41
48
42
49
-- | Representation of a parser result with either a number of days relative to
43
50
-- the current day, or a 'DayOfWeek'.
@@ -58,48 +65,54 @@ dateParser = (,) <$> optional (try (dayParser <* space1)) <*> timeParser
58
65
dayParser
59
66
:: Ord e
60
67
=> Parsec e String DayResult
61
- dayParser = choice
62
- [ Right <$> longDay
63
- , Right <$> shortDay
64
- , Left <$> (string' " yesterday" $> - 1 )
65
- , Left <$> (string' " tomorrow" $> 1 )
66
- , Right <$> absoluteDay
67
- , Left <$> relativeDay
68
- ] where shortDay = choice $ map (ciString (fmap toLower . take 3 . show )) weekDays
69
- longDay = choice $ map (ciString (fmap toLower . show )) weekDays
70
- ciString f d = try (string' (f d)) $> d
71
- weekDays = [Monday .. Friday ]
72
- sign = (char ' -' $> negate ) <|> (char ' +' $> id )
73
- absoluteDay = toEnum . read <$> some digitChar
74
- relativeDay = ($) <$> sign <*> (read <$> some digitChar)
68
+ dayParser =
69
+ choice
70
+ [ Right <$> longDay
71
+ , Right <$> shortDay
72
+ , Left <$> (string' " yesterday" $> - 1 )
73
+ , Left <$> (string' " tomorrow" $> 1 )
74
+ , Right <$> absoluteDay
75
+ , Left <$> relativeDay
76
+ ]
77
+ where
78
+ shortDay = choice $ map (ciString (fmap toLower . take 3 . show )) weekDays
79
+ longDay = choice $ map (ciString (fmap toLower . show )) weekDays
80
+ ciString f d = try (string' (f d)) $> d
81
+ weekDays = [Monday .. Friday ]
82
+ sign = (char ' -' $> negate ) <|> (char ' +' $> id )
83
+ absoluteDay = toEnum . read <$> some digitChar
84
+ relativeDay = ($) <$> sign <*> (read <$> some digitChar)
75
85
76
86
-- | Parse a 'NominalDiffTime' using strings like @1h23m45s@, with all
77
87
-- components being optional as long as one is present.
78
88
durationParser
79
89
:: Ord e
80
90
=> Parsec e String NominalDiffTime
81
91
durationParser = try hours <|> try minutes <|> secondsParser
82
- where hours = do
83
- h <- hoursParser <* space
84
- m <- fromMaybe zero <$> optional (try minutes)
85
- s <- fromMaybe zero <$> optional secondsParser
92
+ where
93
+ hours = do
94
+ h <- hoursParser <* space
95
+ m <- fromMaybe zero <$> optional (try minutes)
96
+ s <- fromMaybe zero <$> optional secondsParser
86
97
87
- return (h + m + s)
98
+ return (h + m + s)
88
99
89
- minutes = do
90
- m <- minutesParser <* space
91
- s <- fromMaybe zero <$> optional secondsParser
100
+ minutes = do
101
+ m <- minutesParser <* space
102
+ s <- fromMaybe zero <$> optional secondsParser
92
103
93
- return (m + s)
104
+ return (m + s)
94
105
95
106
-- | Parse a Gregorian 'Day' from a @%d\/%m\/%Y@ format.
96
107
gregorianDayParser
97
108
:: Ord e
98
109
=> Parsec e String Day
99
110
gregorianDayParser = do
100
111
s <- takeRest
101
- parseTimeM False defaultTimeLocale " %F" s <|>
102
- parseTimeM False defaultTimeLocale " %d/%m/%Y" s
112
+
113
+ let parseTime = flip (parseTimeM False defaultTimeLocale) s
114
+
115
+ parseTime " %F" <|> parseTime " %d/%m/%Y"
103
116
104
117
-- | Parse a 'NominalDiffTime' from a number of hours from a string like @1h@.
105
118
hoursParser
0 commit comments