@@ -9,16 +9,18 @@ module Data.Date
99 , diff
1010 , isLeapYear
1111 , lastDayOfMonth
12+ , adjust
1213 , module Data.Date.Component
1314 ) where
1415
1516import Prelude
1617
1718import Data.Date.Component (Day , Month (..), Weekday (..), Year )
18- import Data.Enum (toEnum , fromEnum )
19+ import Data.Enum (class Enum , toEnum , fromEnum , succ , pred )
1920import Data.Function.Uncurried (Fn3 , runFn3 , Fn4 , runFn4 , Fn6 , runFn6 )
20- import Data.Maybe (Maybe (..), fromJust )
21- import Data.Time.Duration (class Duration , Milliseconds , toDuration )
21+ import Data.Int (fromNumber )
22+ import Data.Maybe (Maybe (..), fromJust , fromMaybe , isNothing )
23+ import Data.Time.Duration (class Duration , Days (..), Milliseconds , toDuration )
2224import Partial.Unsafe (unsafePartial )
2325
2426-- | A date value in the Gregorian calendar.
@@ -51,6 +53,24 @@ instance boundedDate :: Bounded Date where
5153instance showDate :: Show Date where
5254 show (Date y m d) = " (Date " <> show y <> " " <> show m <> " " <> show d <> " )"
5355
56+ instance enumDate :: Enum Date where
57+ succ (Date y m d) = Date <$> y' <*> pure m' <*> d'
58+ where
59+ d' = if isNothing sd then toEnum 1 else sd
60+ m' = if isNothing sd then fromMaybe January sm else m
61+ y' = if isNothing sd && isNothing sm then succ y else Just y
62+ sd = let v = succ d in if v > Just l then Nothing else v
63+ sm = succ m
64+ l = lastDayOfMonth y m
65+ pred (Date y m d) = Date <$> y' <*> pure m' <*> d'
66+ where
67+ d' = if isNothing pd then Just l else pd
68+ m' = if isNothing pd then fromMaybe December pm else m
69+ y' = if isNothing pd && isNothing pm then pred y else Just y
70+ pd = pred d
71+ pm = pred m
72+ l = lastDayOfMonth y m'
73+
5474-- | The year component of a date value.
5575year :: Date -> Year
5676year (Date y _ _) = y
@@ -69,6 +89,26 @@ weekday = unsafePartial \(Date y m d) ->
6989 let n = runFn3 calcWeekday y (fromEnum m) d
7090 in if n == 0 then fromJust (toEnum 7 ) else fromJust (toEnum n)
7191
92+ -- | Adjusts a date with a Duration in days. The number of days must
93+ -- | already be an integer and fall within the valid range of values
94+ -- | for the Int type.
95+ adjust :: Days -> Date -> Maybe Date
96+ adjust (Days n) date = fromNumber n >>= flip adj date
97+ where
98+ adj 0 dt = Just dt
99+ adj i (Date y m d) = adj i' =<< dt'
100+ where
101+ i' | low = j
102+ | hi = j - fromEnum l - 1
103+ | otherwise = 0
104+ dt' | low = pred =<< Date y m <$> toEnum 1
105+ | hi = succ (Date y m l)
106+ | otherwise = Date y m <$> toEnum j
107+ j = i + fromEnum d
108+ low = j < 1
109+ hi = j > fromEnum l
110+ l = lastDayOfMonth y (if low then fromMaybe December (pred m) else m)
111+
72112-- | Calculates the difference between two dates, returning the result as a
73113-- | duration.
74114diff :: forall d . Duration d => Date -> Date -> d
0 commit comments