module Data.HodaTime.Calendar.Gregorian
(
calendarDate
,fromNthDay
,fromWeekDate
,Month(..)
,DayOfWeek(..)
,Gregorian
)
where
import Data.HodaTime.Calendar.Gregorian.Internal hiding (fromWeekDate)
import Data.HodaTime.CalendarDateTime.Internal (CalendarDate(..), DayNth, DayOfMonth, Year, WeekNumber)
import qualified Data.HodaTime.Calendar.Gregorian.Internal as GI
import Control.Monad (guard)
calendarDate :: DayOfMonth -> Month Gregorian -> Year -> Maybe (CalendarDate Gregorian)
calendarDate d m y = do
guard $ y > minDate
guard $ d > 0 && d <= maxDaysInMonth m y
let days = fromIntegral $ yearMonthDayToDays y m d
return $ CalendarDate days (fromIntegral d) (fromIntegral . fromEnum $ m) (fromIntegral y)
fromNthDay :: DayNth -> DayOfWeek Gregorian -> Month Gregorian -> Year -> Maybe (CalendarDate Gregorian)
fromNthDay nth dow m y = do
guard $ adjustment < fromIntegral mdim
return $ CalendarDate (fromIntegral days) (fromIntegral d) (fromIntegral . fromEnum $ m) (fromIntegral y)
where
mdim = maxDaysInMonth m y
somDays = yearMonthDayToDays y m 1
eomDays = yearMonthDayToDays y m mdim
startDow = dayOfWeekFromDays days'
targetDow = fromEnum dow
adjustment = 7 * multiple + adjust startDow targetDow
(days', multiple, adjust, d, days) = frontOrBack (fromEnum nth)
frontOrBack nth'
| nth' < 5 = (somDays, nth', weekdayDistance, adjustment + 1, somDays + adjustment)
| otherwise = (eomDays, nth' - 5, flip weekdayDistance, mdim - adjustment, eomDays - adjustment)
fromWeekDate :: WeekNumber -> DayOfWeek Gregorian -> Year -> Maybe (CalendarDate Gregorian)
fromWeekDate = GI.fromWeekDate 1 Sunday
weekdayDistance :: (Ord a, Num a) => a -> a -> a
weekdayDistance s e = e' - s
where
e' = if e >= s then e else e + 7