In the previous post I introduced a basic date-time type and said that I’ll provide a DSL to do much more with it. Here is a date-time matching DSL I will support.
data Match = DowMatch (UArray Int Bool)
| MonthMatch (UArray Int Bool)
| DayMatch (UArray Int Bool)
| TodMatch (Int,Int)
| DTMatch (DT,DT)
| Not Match
| Or Match Match
| And Match Match
| Never
| Always
deriving (Show)
The actual implementation and tests are here. I’ll just show what you can do with it. First off, you can check if a date matches a spec.
ghci> :l DateTime.hs
ghci> let Right dt = toDT 2016 09 22 10 12 0
ghci> Always `match` dt
True
ghci> Never `match` dt
False
ghci> dowMatch [Tuesday,Thursday] `match` dt
True
ghci> dowMatch [Monday .. Wednesday] `match` dt
False
ghci> todMatch [((3,10,0),(11,0,0))] `match` dt
True
ghci> dayMatch [1..10] `match` dt
False
ghci> monthMatch [7..11] `match` dt
True
We can also use the logical combinators.
ghci> dowMatch [Tuesday,Thursday] `And` monthMatch [7..11] `match` dt
True
ghci> Not (dowMatch [Thursday]) `And` monthMatch [7..11] `match` dt
False
The module also provides extracting matched ranges within a provided date range.
ghci> let Right dt2 = toDT 2016 10 16 12 0 0
ghci> mapM_ print $ split (dowMatch [Monday]) dt dt2
(False,308880,(2016-09-22 10:12:00,2016-09-25 23:59:59))
(True,86400,(2016-09-26 00:00:00,2016-09-26 23:59:59))
(False,518400,(2016-09-27 00:00:00,2016-10-02 23:59:59))
(True,86400,(2016-10-03 00:00:00,2016-10-03 23:59:59))
(False,518400,(2016-10-04 00:00:00,2016-10-09 23:59:59))
(True,86400,(2016-10-10 00:00:00,2016-10-10 23:59:59))
(False,475201,(2016-10-11 00:00:00,2016-10-16 12:00:00))
ghci> mapM_ print $ split (dowMatch [Monday] `And` todMatch [((3,10,0),(4,30,0)), ((18,0,0),(19,0,0))]) dt dt2
(False,320280,(2016-09-22 10:12:00,2016-09-26 03:09:59))
(True,4801,(2016-09-26 03:10:00,2016-09-26 04:30:00))
(False,48599,(2016-09-26 04:30:01,2016-09-26 17:59:59))
(True,3601,(2016-09-26 18:00:00,2016-09-26 19:00:00))
(False,547799,(2016-09-26 19:00:01,2016-10-03 03:09:59))
(True,4801,(2016-10-03 03:10:00,2016-10-03 04:30:00))
(False,48599,(2016-10-03 04:30:01,2016-10-03 17:59:59))
(True,3601,(2016-10-03 18:00:00,2016-10-03 19:00:00))
(False,547799,(2016-10-03 19:00:01,2016-10-10 03:09:59))
(True,4801,(2016-10-10 03:10:00,2016-10-10 04:30:00))
(False,48599,(2016-10-10 04:30:01,2016-10-10 17:59:59))
(True,3601,(2016-10-10 18:00:00,2016-10-10 19:00:00))
(False,493200,(2016-10-10 19:00:01,2016-10-16 12:00:00))
The test file does a QuickCheck using the Arbitrary
instance (although I can now use the generic-random package!) and compares match
and split
against a brute-force implementation using the tick
function to compute a match at every second.