More Time Utilities (14/365)

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.

This entry was posted in Uncategorized and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s