2008-11-11 15:34:05 +03:00
|
|
|
{-|
|
|
|
|
|
2008-11-27 07:31:01 +03:00
|
|
|
For date and time values, we use the standard Day and UTCTime types.
|
|
|
|
|
2008-11-27 03:35:00 +03:00
|
|
|
A 'SmartDate' is a date which may be partially-specified or relative.
|
|
|
|
Eg 2008/12/31, but also 2008/12, 12/31, tomorrow, last week, next year.
|
|
|
|
We represent these as a triple of strings like ("2008","12",""),
|
|
|
|
("","","tomorrow"), ("","last","week").
|
2008-11-11 15:34:05 +03:00
|
|
|
|
2008-11-27 07:31:01 +03:00
|
|
|
A 'DateSpan' is the span of time between two specific calendar dates, or
|
2008-12-04 02:20:38 +03:00
|
|
|
an open-ended span where one or both dates are unspecified. (A date span
|
|
|
|
with both ends unspecified matches all dates.)
|
|
|
|
|
|
|
|
An 'Interval' is ledger's "reporting interval" - weekly, monthly,
|
|
|
|
quarterly, etc.
|
2008-11-27 07:31:01 +03:00
|
|
|
|
2008-11-11 15:34:05 +03:00
|
|
|
-}
|
|
|
|
|
2008-11-22 15:18:19 +03:00
|
|
|
module Ledger.Dates
|
|
|
|
where
|
2008-11-11 15:34:05 +03:00
|
|
|
|
|
|
|
import Data.Time.Clock
|
|
|
|
import Data.Time.Format
|
|
|
|
import Data.Time.Calendar
|
2008-11-27 04:49:13 +03:00
|
|
|
import Data.Time.Calendar.MonthDay
|
|
|
|
import Data.Time.Calendar.OrdinalDate
|
|
|
|
import Data.Time.Calendar.WeekDate
|
2008-11-11 15:34:05 +03:00
|
|
|
import Data.Time.LocalTime
|
|
|
|
import System.Locale (defaultTimeLocale)
|
|
|
|
import Text.Printf
|
|
|
|
import Data.Maybe
|
2008-11-27 03:35:00 +03:00
|
|
|
import Text.ParserCombinators.Parsec
|
|
|
|
import Text.ParserCombinators.Parsec.Char
|
|
|
|
import Text.ParserCombinators.Parsec.Combinator
|
|
|
|
import Ledger.Types
|
|
|
|
import Ledger.Utils
|
2008-11-11 15:34:05 +03:00
|
|
|
|
|
|
|
|
2008-11-27 07:01:07 +03:00
|
|
|
showDate :: Day -> String
|
|
|
|
showDate d = formatTime defaultTimeLocale "%Y/%m/%d" d
|
2008-11-11 15:34:05 +03:00
|
|
|
|
2008-11-27 07:01:07 +03:00
|
|
|
mkUTCTime :: Day -> TimeOfDay -> UTCTime
|
|
|
|
mkUTCTime day tod = localTimeToUTC utc (LocalTime day tod)
|
2008-11-11 15:34:05 +03:00
|
|
|
|
2008-11-27 07:01:07 +03:00
|
|
|
today :: IO Day
|
2008-11-26 00:30:21 +03:00
|
|
|
today = do
|
|
|
|
t <- getZonedTime
|
2008-11-27 07:01:07 +03:00
|
|
|
return $ localDay (zonedTimeToLocalTime t)
|
2008-11-27 03:35:00 +03:00
|
|
|
|
2008-11-27 07:01:07 +03:00
|
|
|
now :: IO UTCTime
|
|
|
|
now = getCurrentTime
|
2008-11-27 03:35:00 +03:00
|
|
|
|
2008-11-27 07:01:07 +03:00
|
|
|
elapsedSeconds :: Fractional a => UTCTime -> UTCTime -> a
|
|
|
|
elapsedSeconds t1 t2 = realToFrac $ diffUTCTime t1 t2
|
2008-11-27 03:35:00 +03:00
|
|
|
|
2008-11-27 07:01:07 +03:00
|
|
|
dayToUTC :: Day -> UTCTime
|
|
|
|
dayToUTC d = localTimeToUTC utc (LocalTime d midnight)
|
2008-11-27 03:35:00 +03:00
|
|
|
|
2008-12-04 02:20:38 +03:00
|
|
|
-- | Split a DateSpan into one or more consecutive spans at the specified interval.
|
|
|
|
splitSpan :: Interval -> DateSpan -> [DateSpan]
|
|
|
|
splitSpan i (DateSpan Nothing Nothing) = [DateSpan Nothing Nothing]
|
|
|
|
splitSpan NoInterval s = [s]
|
|
|
|
splitSpan Daily s = splitspan start next s where (start,next) = (startofday,nextday)
|
|
|
|
splitSpan Weekly s = splitspan start next s where (start,next) = (startofweek,nextweek)
|
|
|
|
splitSpan Monthly s = splitspan start next s where (start,next) = (startofmonth,nextmonth)
|
|
|
|
splitSpan Quarterly s = splitspan start next s where (start,next) = (startofquarter,nextquarter)
|
|
|
|
splitSpan Yearly s = splitspan start next s where (start,next) = (startofyear,nextyear)
|
|
|
|
|
|
|
|
splitspan _ _ (DateSpan Nothing Nothing) = []
|
|
|
|
splitspan startof next (DateSpan Nothing (Just e)) = [DateSpan (Just $ startof e) (Just $ next $ startof e)]
|
|
|
|
splitspan startof next (DateSpan (Just b) Nothing) = [DateSpan (Just $ startof b) (Just $ next $ startof b)]
|
|
|
|
splitspan startof next (DateSpan (Just b) (Just e))
|
|
|
|
| b >= e = []
|
|
|
|
| otherwise = [DateSpan (Just $ startof b) (Just $ next $ startof b)]
|
|
|
|
++ splitspan startof next (DateSpan (Just $ next $ startof b) (Just e))
|
|
|
|
|
|
|
|
-- | Parse a period expression to an Interval and overall DateSpan using
|
|
|
|
-- the provided reference date.
|
|
|
|
parsePeriodExpr :: Day -> String -> (Interval, DateSpan)
|
|
|
|
parsePeriodExpr refdate expr = (interval,span)
|
|
|
|
where (interval,span) = fromparse $ parsewith (periodexpr refdate) expr
|
2008-11-27 22:42:03 +03:00
|
|
|
|
2008-12-04 02:20:38 +03:00
|
|
|
-- | Convert a single smart date string to a date span using the provided
|
|
|
|
-- reference date.
|
2008-11-27 09:29:29 +03:00
|
|
|
spanFromSmartDateString :: Day -> String -> DateSpan
|
2008-11-27 22:42:03 +03:00
|
|
|
spanFromSmartDateString refdate s = spanFromSmartDate refdate sdate
|
2008-11-27 09:29:29 +03:00
|
|
|
where
|
|
|
|
sdate = fromparse $ parsewith smartdate s
|
2008-11-27 22:42:03 +03:00
|
|
|
|
|
|
|
spanFromSmartDate :: Day -> SmartDate -> DateSpan
|
|
|
|
spanFromSmartDate refdate sdate = DateSpan (Just b) (Just e)
|
|
|
|
where
|
2008-11-27 09:29:29 +03:00
|
|
|
(ry,rm,rd) = toGregorian refdate
|
|
|
|
(b,e) = span sdate
|
|
|
|
span :: SmartDate -> (Day,Day)
|
|
|
|
span ("","","today") = (refdate, nextday refdate)
|
|
|
|
span ("","this","day") = (refdate, nextday refdate)
|
|
|
|
span ("","","yesterday") = (prevday refdate, refdate)
|
|
|
|
span ("","last","day") = (prevday refdate, refdate)
|
|
|
|
span ("","","tomorrow") = (nextday refdate, addDays 2 refdate)
|
|
|
|
span ("","next","day") = (nextday refdate, addDays 2 refdate)
|
|
|
|
span ("","last","week") = (prevweek refdate, thisweek refdate)
|
|
|
|
span ("","this","week") = (thisweek refdate, nextweek refdate)
|
|
|
|
span ("","next","week") = (nextweek refdate, startofweek $ addDays 14 refdate)
|
|
|
|
span ("","last","month") = (prevmonth refdate, thismonth refdate)
|
|
|
|
span ("","this","month") = (thismonth refdate, nextmonth refdate)
|
|
|
|
span ("","next","month") = (nextmonth refdate, startofmonth $ addGregorianMonthsClip 2 refdate)
|
|
|
|
span ("","last","quarter") = (prevquarter refdate, thisquarter refdate)
|
|
|
|
span ("","this","quarter") = (thisquarter refdate, nextquarter refdate)
|
|
|
|
span ("","next","quarter") = (nextquarter refdate, startofquarter $ addGregorianMonthsClip 6 refdate)
|
|
|
|
span ("","last","year") = (prevyear refdate, thisyear refdate)
|
|
|
|
span ("","this","year") = (thisyear refdate, nextyear refdate)
|
|
|
|
span ("","next","year") = (nextyear refdate, startofyear $ addGregorianYearsClip 2 refdate)
|
|
|
|
span ("","",d) = (day, nextday day) where day = fromGregorian ry rm (read d)
|
|
|
|
span ("",m,"") = (startofmonth day, nextmonth day) where day = fromGregorian ry (read m) 1
|
|
|
|
span ("",m,d) = (day, nextday day) where day = fromGregorian ry (read m) (read d)
|
|
|
|
span (y,"","") = (startofyear day, nextyear day) where day = fromGregorian (read y) 1 1
|
|
|
|
span (y,m,"") = (startofmonth day, nextmonth day) where day = fromGregorian (read y) (read m) 1
|
|
|
|
span (y,m,d) = (day, nextday day) where day = fromGregorian (read y) (read m) (read d)
|
|
|
|
|
|
|
|
-- | Convert a smart date string to an explicit yyyy/mm/dd string using
|
2008-11-27 09:48:46 +03:00
|
|
|
-- the provided reference date.
|
2008-11-27 07:01:07 +03:00
|
|
|
fixSmartDateStr :: Day -> String -> String
|
2008-11-27 03:35:00 +03:00
|
|
|
fixSmartDateStr t s = printf "%04d/%02d/%02d" y m d
|
|
|
|
where
|
2008-11-27 07:01:07 +03:00
|
|
|
(y,m,d) = toGregorian $ fixSmartDate t sdate
|
|
|
|
sdate = fromparse $ parsewith smartdate $ map toLower s
|
2008-11-27 03:35:00 +03:00
|
|
|
|
2008-11-27 09:48:46 +03:00
|
|
|
-- | Convert a SmartDate to an absolute date using the provided reference date.
|
2008-11-27 07:01:07 +03:00
|
|
|
fixSmartDate :: Day -> SmartDate -> Day
|
|
|
|
fixSmartDate refdate sdate = fix sdate
|
2008-11-27 03:35:00 +03:00
|
|
|
where
|
2008-11-27 07:01:07 +03:00
|
|
|
fix :: SmartDate -> Day
|
|
|
|
fix ("","","today") = fromGregorian ry rm rd
|
|
|
|
fix ("","this","day") = fromGregorian ry rm rd
|
|
|
|
fix ("","","yesterday") = prevday refdate
|
|
|
|
fix ("","last","day") = prevday refdate
|
|
|
|
fix ("","","tomorrow") = nextday refdate
|
|
|
|
fix ("","next","day") = nextday refdate
|
|
|
|
fix ("","last","week") = prevweek refdate
|
|
|
|
fix ("","this","week") = thisweek refdate
|
|
|
|
fix ("","next","week") = nextweek refdate
|
|
|
|
fix ("","last","month") = prevmonth refdate
|
|
|
|
fix ("","this","month") = thismonth refdate
|
|
|
|
fix ("","next","month") = nextmonth refdate
|
|
|
|
fix ("","last","quarter") = prevquarter refdate
|
|
|
|
fix ("","this","quarter") = thisquarter refdate
|
|
|
|
fix ("","next","quarter") = nextquarter refdate
|
|
|
|
fix ("","last","year") = prevyear refdate
|
|
|
|
fix ("","this","year") = thisyear refdate
|
|
|
|
fix ("","next","year") = nextyear refdate
|
|
|
|
fix ("","",d) = fromGregorian ry rm (read d)
|
2008-11-27 09:29:29 +03:00
|
|
|
fix ("",m,"") = fromGregorian ry (read m) 1
|
2008-11-27 07:01:07 +03:00
|
|
|
fix ("",m,d) = fromGregorian ry (read m) (read d)
|
2008-11-27 09:29:29 +03:00
|
|
|
fix (y,"","") = fromGregorian (read y) 1 1
|
|
|
|
fix (y,m,"") = fromGregorian (read y) (read m) 1
|
2008-11-27 07:01:07 +03:00
|
|
|
fix (y,m,d) = fromGregorian (read y) (read m) (read d)
|
|
|
|
(ry,rm,rd) = toGregorian refdate
|
2008-11-27 03:35:00 +03:00
|
|
|
|
2008-11-27 05:49:22 +03:00
|
|
|
prevday :: Day -> Day
|
|
|
|
prevday = addDays (-1)
|
|
|
|
nextday = addDays 1
|
2008-12-04 02:20:38 +03:00
|
|
|
startofday = id
|
2008-11-27 04:49:13 +03:00
|
|
|
|
2008-11-27 05:49:22 +03:00
|
|
|
thisweek = startofweek
|
|
|
|
prevweek = startofweek . addDays (-7)
|
|
|
|
nextweek = startofweek . addDays 7
|
|
|
|
startofweek day = fromMondayStartWeek y w 1
|
2008-11-27 04:49:13 +03:00
|
|
|
where
|
2008-11-27 05:49:22 +03:00
|
|
|
(y,_,_) = toGregorian day
|
2008-11-27 04:49:13 +03:00
|
|
|
(w,_) = mondayStartWeek day
|
|
|
|
|
2008-11-27 05:49:22 +03:00
|
|
|
thismonth = startofmonth
|
|
|
|
prevmonth = startofmonth . addGregorianMonthsClip (-1)
|
|
|
|
nextmonth = startofmonth . addGregorianMonthsClip 1
|
|
|
|
startofmonth day = fromGregorian y m 1 where (y,m,_) = toGregorian day
|
|
|
|
|
|
|
|
thisquarter = startofquarter
|
|
|
|
prevquarter = startofquarter . addGregorianMonthsClip (-3)
|
|
|
|
nextquarter = startofquarter . addGregorianMonthsClip 3
|
|
|
|
startofquarter day = fromGregorian y (firstmonthofquarter m) 1
|
|
|
|
where
|
|
|
|
(y,m,_) = toGregorian day
|
|
|
|
firstmonthofquarter m = ((m-1) `div` 3) * 3 + 1
|
|
|
|
|
|
|
|
thisyear = startofyear
|
|
|
|
prevyear = startofyear . addGregorianYearsClip (-1)
|
|
|
|
nextyear = startofyear . addGregorianYearsClip 1
|
|
|
|
startofyear day = fromGregorian y 1 1 where (y,_,_) = toGregorian day
|
2008-11-27 03:35:00 +03:00
|
|
|
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
-- parsing
|
|
|
|
|
2008-11-11 15:34:05 +03:00
|
|
|
-- | Parse a date-time string to a time type, or raise an error.
|
2008-11-27 07:01:07 +03:00
|
|
|
parsedatetime :: String -> UTCTime
|
|
|
|
parsedatetime s =
|
2008-11-11 15:34:05 +03:00
|
|
|
parsetimewith "%Y/%m/%d %H:%M:%S" s $
|
|
|
|
error $ printf "could not parse timestamp \"%s\"" s
|
|
|
|
|
|
|
|
-- | Parse a date string to a time type, or raise an error.
|
2008-11-27 07:01:07 +03:00
|
|
|
parsedate :: String -> Day
|
|
|
|
parsedate s =
|
2008-11-11 15:34:05 +03:00
|
|
|
parsetimewith "%Y/%m/%d" s $
|
|
|
|
error $ printf "could not parse date \"%s\"" s
|
|
|
|
|
|
|
|
-- | Parse a time string to a time type using the provided pattern, or
|
|
|
|
-- return the default.
|
|
|
|
parsetimewith :: ParseTime t => String -> String -> t -> t
|
|
|
|
parsetimewith pat s def = fromMaybe def $ parseTime defaultTimeLocale pat s
|
|
|
|
|
2008-11-27 03:35:00 +03:00
|
|
|
{-|
|
|
|
|
Parse a date in any of the formats allowed in ledger's period expressions,
|
|
|
|
and maybe some others:
|
|
|
|
|
|
|
|
> 2004
|
|
|
|
> 2004/10
|
|
|
|
> 2004/10/1
|
|
|
|
> 10/1
|
|
|
|
> 21
|
|
|
|
> october, oct
|
|
|
|
> yesterday, today, tomorrow
|
|
|
|
> (not yet) this/next/last week/day/month/quarter/year
|
|
|
|
|
|
|
|
Returns a SmartDate, to be converted to a full date later (see fixSmartDate).
|
|
|
|
Assumes any text in the parse stream has been lowercased.
|
|
|
|
-}
|
|
|
|
smartdate :: Parser SmartDate
|
|
|
|
smartdate = do
|
2008-11-27 04:49:13 +03:00
|
|
|
let dateparsers = [ymd, ym, md, y, d, month, mon, today', yesterday, tomorrow,
|
|
|
|
lastthisnextthing
|
2008-11-27 03:35:00 +03:00
|
|
|
]
|
|
|
|
(y,m,d) <- choice $ map try dateparsers
|
|
|
|
return $ (y,m,d)
|
|
|
|
|
|
|
|
datesepchar = oneOf "/-."
|
|
|
|
|
|
|
|
ymd :: Parser SmartDate
|
|
|
|
ymd = do
|
|
|
|
y <- many1 digit
|
|
|
|
datesepchar
|
|
|
|
m <- many1 digit
|
|
|
|
guard (read m <= 12)
|
|
|
|
datesepchar
|
|
|
|
d <- many1 digit
|
|
|
|
guard (read d <= 31)
|
|
|
|
return (y,m,d)
|
|
|
|
|
|
|
|
ym :: Parser SmartDate
|
|
|
|
ym = do
|
|
|
|
y <- many1 digit
|
|
|
|
guard (read y > 12)
|
|
|
|
datesepchar
|
|
|
|
m <- many1 digit
|
|
|
|
guard (read m <= 12)
|
2008-11-27 09:29:29 +03:00
|
|
|
return (y,m,"")
|
2008-11-27 03:35:00 +03:00
|
|
|
|
|
|
|
y :: Parser SmartDate
|
|
|
|
y = do
|
|
|
|
y <- many1 digit
|
|
|
|
guard (read y >= 1000)
|
2008-11-27 09:29:29 +03:00
|
|
|
return (y,"","")
|
2008-11-27 03:35:00 +03:00
|
|
|
|
|
|
|
d :: Parser SmartDate
|
|
|
|
d = do
|
|
|
|
d <- many1 digit
|
|
|
|
guard (read d <= 31)
|
|
|
|
return ("","",d)
|
|
|
|
|
|
|
|
md :: Parser SmartDate
|
|
|
|
md = do
|
|
|
|
m <- many1 digit
|
|
|
|
guard (read m <= 12)
|
|
|
|
datesepchar
|
|
|
|
d <- many1 digit
|
|
|
|
guard (read d <= 31)
|
|
|
|
return ("",m,d)
|
|
|
|
|
|
|
|
months = ["january","february","march","april","may","june",
|
|
|
|
"july","august","september","october","november","december"]
|
|
|
|
|
2008-11-27 09:29:29 +03:00
|
|
|
mons = ["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"]
|
|
|
|
|
|
|
|
monthIndex s = maybe 0 (+1) $ (map toLower s) `elemIndex` months
|
|
|
|
monIndex s = maybe 0 (+1) $ (map toLower s) `elemIndex` mons
|
2008-11-27 03:35:00 +03:00
|
|
|
|
|
|
|
month :: Parser SmartDate
|
|
|
|
month = do
|
2008-11-27 09:29:29 +03:00
|
|
|
m <- choice $ map (try . string) months
|
|
|
|
let i = monthIndex m
|
|
|
|
return $ ("",show i,"")
|
2008-11-27 03:35:00 +03:00
|
|
|
|
|
|
|
mon :: Parser SmartDate
|
|
|
|
mon = do
|
2008-11-27 09:29:29 +03:00
|
|
|
m <- choice $ map (try . string) mons
|
|
|
|
let i = monIndex m
|
|
|
|
return ("",show i,"")
|
2008-11-27 03:35:00 +03:00
|
|
|
|
|
|
|
today',yesterday,tomorrow :: Parser SmartDate
|
|
|
|
today' = string "today" >> return ("","","today")
|
|
|
|
yesterday = string "yesterday" >> return ("","","yesterday")
|
|
|
|
tomorrow = string "tomorrow" >> return ("","","tomorrow")
|
|
|
|
|
|
|
|
lastthisnextthing :: Parser SmartDate
|
|
|
|
lastthisnextthing = do
|
|
|
|
r <- choice [
|
|
|
|
string "last"
|
|
|
|
,string "this"
|
|
|
|
,string "next"
|
|
|
|
]
|
2008-11-27 04:49:13 +03:00
|
|
|
--many1 spacenonewline
|
2008-11-27 05:49:22 +03:00
|
|
|
many spacenonewline -- allow the space to be omitted for easier scripting
|
2008-11-27 03:35:00 +03:00
|
|
|
p <- choice [
|
|
|
|
string "day"
|
|
|
|
,string "week"
|
|
|
|
,string "month"
|
|
|
|
,string "quarter"
|
|
|
|
,string "year"
|
|
|
|
]
|
|
|
|
return ("",r,p)
|
2008-11-22 15:18:19 +03:00
|
|
|
|
2008-12-04 02:20:38 +03:00
|
|
|
periodexpr :: Day -> Parser (Interval, DateSpan)
|
|
|
|
periodexpr rdate = choice $ map try [
|
|
|
|
intervalanddateperiodexpr rdate,
|
|
|
|
intervalperiodexpr,
|
|
|
|
dateperiodexpr rdate,
|
|
|
|
(return $ (NoInterval,DateSpan Nothing Nothing))
|
|
|
|
]
|
2008-11-27 22:42:03 +03:00
|
|
|
|
2008-12-04 02:20:38 +03:00
|
|
|
intervalanddateperiodexpr :: Day -> Parser (Interval, DateSpan)
|
|
|
|
intervalanddateperiodexpr rdate = do
|
2008-11-27 22:42:03 +03:00
|
|
|
many spacenonewline
|
2008-12-04 02:20:38 +03:00
|
|
|
i <- periodexprinterval
|
2008-11-27 22:42:03 +03:00
|
|
|
many spacenonewline
|
2008-12-04 02:20:38 +03:00
|
|
|
s <- periodexprdatespan rdate
|
|
|
|
return (i,s)
|
|
|
|
|
|
|
|
intervalperiodexpr :: Parser (Interval, DateSpan)
|
|
|
|
intervalperiodexpr = do
|
|
|
|
many spacenonewline
|
|
|
|
i <- periodexprinterval
|
|
|
|
return (i, DateSpan Nothing Nothing)
|
|
|
|
|
|
|
|
dateperiodexpr :: Day -> Parser (Interval, DateSpan)
|
|
|
|
dateperiodexpr rdate = do
|
2008-11-27 22:42:03 +03:00
|
|
|
many spacenonewline
|
2008-12-04 02:20:38 +03:00
|
|
|
s <- periodexprdatespan rdate
|
|
|
|
return (NoInterval, s)
|
|
|
|
|
|
|
|
periodexprinterval :: Parser Interval
|
|
|
|
periodexprinterval =
|
|
|
|
choice $ map try [
|
|
|
|
tryinterval "day" "daily" Daily,
|
|
|
|
tryinterval "week" "weekly" Weekly,
|
|
|
|
tryinterval "month" "monthly" Monthly,
|
|
|
|
tryinterval "quarter" "quarterly" Quarterly,
|
|
|
|
tryinterval "year" "yearly" Yearly
|
|
|
|
]
|
|
|
|
where
|
|
|
|
tryinterval s1 s2 v =
|
|
|
|
choice [try (string $ "every "++s1), try (string s2)] >> return v
|
|
|
|
|
|
|
|
periodexprdatespan :: Day -> Parser DateSpan
|
|
|
|
periodexprdatespan rdate = choice $ map try [
|
|
|
|
doubledatespan rdate,
|
|
|
|
fromdatespan rdate,
|
|
|
|
todatespan rdate,
|
|
|
|
justdatespan rdate
|
|
|
|
]
|
|
|
|
|
|
|
|
doubledatespan :: Day -> Parser DateSpan
|
|
|
|
doubledatespan rdate = do
|
|
|
|
optional (string "from" >> many spacenonewline)
|
|
|
|
b <- smartdate
|
|
|
|
many spacenonewline
|
|
|
|
optional (string "to" >> many spacenonewline)
|
2008-11-27 22:42:03 +03:00
|
|
|
e <- smartdate
|
2008-12-04 02:20:38 +03:00
|
|
|
return $ DateSpan (Just $ fixSmartDate rdate b) (Just $ fixSmartDate rdate e)
|
2008-11-27 22:42:03 +03:00
|
|
|
|
2008-12-04 02:20:38 +03:00
|
|
|
fromdatespan :: Day -> Parser DateSpan
|
|
|
|
fromdatespan rdate = do
|
|
|
|
string "from" >> many spacenonewline
|
|
|
|
b <- smartdate
|
|
|
|
return $ DateSpan (Just $ fixSmartDate rdate b) Nothing
|
|
|
|
|
|
|
|
todatespan :: Day -> Parser DateSpan
|
|
|
|
todatespan rdate = do
|
|
|
|
string "to" >> many spacenonewline
|
|
|
|
e <- smartdate
|
|
|
|
return $ DateSpan Nothing (Just $ fixSmartDate rdate e)
|
2008-11-27 22:42:03 +03:00
|
|
|
|
2008-12-04 02:20:38 +03:00
|
|
|
justdatespan :: Day -> Parser DateSpan
|
|
|
|
justdatespan rdate = do
|
|
|
|
optional (string "in" >> many spacenonewline)
|
|
|
|
d <- smartdate
|
|
|
|
return $ spanFromSmartDate rdate d
|