ref: smartdate: Improve ergonomics of SmartDate constructors.
This commit is contained in:
parent
97e57c2cb5
commit
bffb6c8c82
@ -390,16 +390,16 @@ spanFromSmartDate refdate sdate = DateSpan (Just b) (Just e)
|
|||||||
(ry,rm,_) = toGregorian refdate
|
(ry,rm,_) = toGregorian refdate
|
||||||
(b,e) = span sdate
|
(b,e) = span sdate
|
||||||
span :: SmartDate -> (Day,Day)
|
span :: SmartDate -> (Day,Day)
|
||||||
span (SmartRelative n Day) = (addDays n refdate, addDays (n+1) refdate)
|
span (SmartCompleteDate day) = (day, nextday day)
|
||||||
span (SmartRelative n Week) = let d = thisweek refdate in (addDays (7*n) d, addDays (7*n+7) d)
|
span (SmartAssumeStart y Nothing) = (startofyear day, nextyear day) where day = fromGregorian y 1 1
|
||||||
span (SmartRelative n Month) = let d = thismonth refdate in (addGregorianMonthsClip n d, addGregorianMonthsClip (n+1) d)
|
span (SmartAssumeStart y (Just m)) = (startofmonth day, nextmonth day) where day = fromGregorian y m 1
|
||||||
span (SmartRelative n Quarter) = let d = thisquarter refdate in (addGregorianMonthsClip (3*n) d, addGregorianMonthsClip (3*n+3) d)
|
span (SmartFromReference m d) = (day, nextday day) where day = fromGregorian ry (fromMaybe rm m) d
|
||||||
span (SmartRelative n Year) = let d = thisyear refdate in (addGregorianYearsClip n d, addGregorianYearsClip (n+1) d)
|
span (SmartMonth m) = (startofmonth day, nextmonth day) where day = fromGregorian ry m 1
|
||||||
span (SmartAssumeStart y Nothing) = (startofyear day, nextyear day) where day = fromGregorian y 1 1
|
span (SmartRelative n Day) = (addDays n refdate, addDays (n+1) refdate)
|
||||||
span (SmartAssumeStart y (Just (m, Nothing))) = (startofmonth day, nextmonth day) where day = fromGregorian y m 1
|
span (SmartRelative n Week) = (addDays (7*n) d, addDays (7*n+7) d) where d = thisweek refdate
|
||||||
span (SmartAssumeStart y (Just (m, Just d))) = (day, nextday day) where day = fromGregorian y m d
|
span (SmartRelative n Month) = (addGregorianMonthsClip n d, addGregorianMonthsClip (n+1) d) where d = thismonth refdate
|
||||||
span (SmartFromReference m d) = (day, nextday day) where day = fromGregorian ry (fromMaybe rm m) d
|
span (SmartRelative n Quarter) = (addGregorianMonthsClip (3*n) d, addGregorianMonthsClip (3*n+3) d) where d = thisquarter refdate
|
||||||
span (SmartMonth m) = (startofmonth day, nextmonth day) where day = fromGregorian ry m 1
|
span (SmartRelative n Year) = (addGregorianYearsClip n d, addGregorianYearsClip (n+1) d) where d = thisyear refdate
|
||||||
|
|
||||||
-- showDay :: Day -> String
|
-- showDay :: Day -> String
|
||||||
-- showDay day = printf "%04d/%02d/%02d" y m d where (y,m,d) = toGregorian day
|
-- showDay day = printf "%04d/%02d/%02d" y m d where (y,m,d) = toGregorian day
|
||||||
@ -508,14 +508,15 @@ fixSmartDate :: Day -> SmartDate -> Day
|
|||||||
fixSmartDate refdate = fix
|
fixSmartDate refdate = fix
|
||||||
where
|
where
|
||||||
fix :: SmartDate -> Day
|
fix :: SmartDate -> Day
|
||||||
|
fix (SmartCompleteDate d) = d
|
||||||
|
fix (SmartAssumeStart y m) = fromGregorian y (fromMaybe 1 m) 1
|
||||||
|
fix (SmartFromReference m d) = fromGregorian ry (fromMaybe rm m) d
|
||||||
|
fix (SmartMonth m) = fromGregorian ry m 1
|
||||||
fix (SmartRelative n Day) = addDays n refdate
|
fix (SmartRelative n Day) = addDays n refdate
|
||||||
fix (SmartRelative n Week) = addDays (7*n) $ thisweek refdate
|
fix (SmartRelative n Week) = addDays (7*n) $ thisweek refdate
|
||||||
fix (SmartRelative n Month) = addGregorianMonthsClip n $ thismonth refdate
|
fix (SmartRelative n Month) = addGregorianMonthsClip n $ thismonth refdate
|
||||||
fix (SmartRelative n Quarter) = addGregorianMonthsClip (3*n) $ thisquarter refdate
|
fix (SmartRelative n Quarter) = addGregorianMonthsClip (3*n) $ thisquarter refdate
|
||||||
fix (SmartRelative n Year) = addGregorianYearsClip n $ thisyear refdate
|
fix (SmartRelative n Year) = addGregorianYearsClip n $ thisyear refdate
|
||||||
fix (SmartAssumeStart y md) = fromGregorian y (maybe 1 fst md) (fromMaybe 1 $ snd =<< md)
|
|
||||||
fix (SmartFromReference m d) = fromGregorian ry (fromMaybe rm m) d
|
|
||||||
fix (SmartMonth m) = fromGregorian ry m 1
|
|
||||||
(ry, rm, _) = toGregorian refdate
|
(ry, rm, _) = toGregorian refdate
|
||||||
|
|
||||||
prevday :: Day -> Day
|
prevday :: Day -> Day
|
||||||
@ -725,11 +726,11 @@ Eg:
|
|||||||
YYYYMMDD is parsed as year-month-date if those parts are valid
|
YYYYMMDD is parsed as year-month-date if those parts are valid
|
||||||
(>=4 digits, 1-12, and 1-31 respectively):
|
(>=4 digits, 1-12, and 1-31 respectively):
|
||||||
>>> parsewith (smartdate <* eof) "20181201"
|
>>> parsewith (smartdate <* eof) "20181201"
|
||||||
Right (SmartAssumeStart 2018 (Just (12,Just 1)))
|
Right (SmartCompleteDate 2018-12-01)
|
||||||
|
|
||||||
YYYYMM is parsed as year-month-01 if year and month are valid:
|
YYYYMM is parsed as year-month-01 if year and month are valid:
|
||||||
>>> parsewith (smartdate <* eof) "201804"
|
>>> parsewith (smartdate <* eof) "201804"
|
||||||
Right (SmartAssumeStart 2018 (Just (4,Nothing)))
|
Right (SmartAssumeStart 2018 (Just 4))
|
||||||
|
|
||||||
With an invalid month, it's parsed as a year:
|
With an invalid month, it's parsed as a year:
|
||||||
>>> parsewith (smartdate <* eof) "201813"
|
>>> parsewith (smartdate <* eof) "201813"
|
||||||
@ -788,31 +789,39 @@ validDay n = n >= 1 && n <= 31
|
|||||||
failIfInvalidDate :: Fail.MonadFail m => SmartDate -> m SmartDate
|
failIfInvalidDate :: Fail.MonadFail m => SmartDate -> m SmartDate
|
||||||
failIfInvalidDate s = unless isValid (Fail.fail $ "bad smart date: " ++ show s) $> s
|
failIfInvalidDate s = unless isValid (Fail.fail $ "bad smart date: " ++ show s) $> s
|
||||||
where isValid = case s of
|
where isValid = case s of
|
||||||
SmartAssumeStart y (Just (m, md)) -> isJust $ fromGregorianValid y m (fromMaybe 1 md)
|
SmartAssumeStart _ (Just m) -> validMonth m
|
||||||
SmartFromReference mm d -> isJust $ fromGregorianValid 2004 (fromMaybe 1 mm) d
|
SmartFromReference mm d -> isJust $ fromGregorianValid 2004 (fromMaybe 1 mm) d
|
||||||
SmartMonth m -> validMonth m
|
SmartMonth m -> validMonth m
|
||||||
_ -> True
|
_ -> True
|
||||||
|
|
||||||
|
showBadDate :: Integer -> Int -> Int -> String
|
||||||
|
showBadDate y m d = "bad smart date: " ++ show y ++ "-" ++ show m ++ "-" ++ show d
|
||||||
|
|
||||||
yyyymmdd :: TextParser m SmartDate
|
yyyymmdd :: TextParser m SmartDate
|
||||||
yyyymmdd = do
|
yyyymmdd = do
|
||||||
y <- read <$> count 4 digitChar
|
y <- read <$> count 4 digitChar
|
||||||
m <- read <$> count 2 digitChar
|
m <- read <$> count 2 digitChar
|
||||||
d <- optional $ read <$> count 2 digitChar
|
md <- optional $ read <$> count 2 digitChar
|
||||||
let date = SmartAssumeStart y $ Just (m, d)
|
case md of
|
||||||
failIfInvalidDate date
|
Nothing -> failIfInvalidDate $ SmartAssumeStart y (Just m)
|
||||||
|
Just d -> maybe (Fail.fail $ showBadDate y m d) (return . SmartCompleteDate) $
|
||||||
|
fromGregorianValid y m d
|
||||||
|
|
||||||
ymd :: TextParser m SmartDate
|
ymd :: TextParser m SmartDate
|
||||||
ymd = do
|
ymd = do
|
||||||
y <- yearp
|
y <- yearp
|
||||||
fmap (SmartAssumeStart y) . optional . try $ do
|
emd <- optional . try $ do
|
||||||
sep <- datesepchar
|
sep <- datesepchar
|
||||||
m <- decimal
|
m <- decimal
|
||||||
unless (validMonth m) $ Fail.fail ("Bad month " <> show m)
|
unless (validMonth m) $ Fail.fail ("Bad month " <> show m)
|
||||||
fmap (m,) . optional . try $ do
|
option (Left m) . try $ Right <$> do
|
||||||
_ <- char sep
|
_ <- char sep
|
||||||
d <- decimal
|
d <- decimal
|
||||||
failIfInvalidDate $ SmartAssumeStart y (Just (m, Just d))
|
maybe (Fail.fail $ showBadDate y m d) return $ fromGregorianValid y m d
|
||||||
return d
|
return $ case emd of
|
||||||
|
Nothing -> SmartAssumeStart y Nothing
|
||||||
|
Just (Left m) -> SmartAssumeStart y (Just m)
|
||||||
|
Just (Right day) -> SmartCompleteDate day
|
||||||
|
|
||||||
md :: TextParser m (Month, MonthDay)
|
md :: TextParser m (Month, MonthDay)
|
||||||
md = do
|
md = do
|
||||||
|
|||||||
@ -81,7 +81,8 @@ type WeekDay = Int -- 1-7
|
|||||||
-- (last|this|next) (day|week|month|quarter|year), where "this" means the period
|
-- (last|this|next) (day|week|month|quarter|year), where "this" means the period
|
||||||
-- containing the reference date.
|
-- containing the reference date.
|
||||||
data SmartDate
|
data SmartDate
|
||||||
= SmartAssumeStart Year (Maybe (Month, Maybe MonthDay))
|
= SmartCompleteDate Day
|
||||||
|
| SmartAssumeStart Year (Maybe Month)
|
||||||
| SmartFromReference (Maybe Month) MonthDay
|
| SmartFromReference (Maybe Month) MonthDay
|
||||||
| SmartMonth Month
|
| SmartMonth Month
|
||||||
| SmartRelative Integer SmartInterval
|
| SmartRelative Integer SmartInterval
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user