-- | ISO 8601 Ordinal Date format
module Data.Time.Calendar.OrdinalDate where
import Data.Time.Calendar.Days
import Data.Time.Calendar.Private
-- | convert to ISO 8601 Ordinal Date format. First element of result is year (proleptic Gregoran calendar),-- second is the day of the year, with 1 for Jan 1, and 365 (or 366 in leap years) for Dec 31.toOrdinalDate :: Day -> (Integer,Int)
toOrdinalDate (ModifiedJulianDaymjd) = (year,yd) where
a = mjd+678575quadcent = diva146097b = moda146097cent = min (divb36524) 3c = b- (cent*36524)
quad = divc1461d = modc1461y = min (divd365) 3yd = fromInteger (d- (y*365) +1)
year = quadcent*400+cent*100+quad*4+y+1-- | convert from ISO 8601 Ordinal Date format.-- Invalid day numbers will be clipped to the correct range (1 to 365 or 366).fromOrdinalDate :: Integer -> Int -> DayfromOrdinalDateyearday = ModifiedJulianDaymjd where
y = year-1mjd = (fromIntegral (clip1 (if isLeapYearyear then 366 else 365) day)) + (365*y) + (divy4) - (divy100) + (divy400) -678576-- | convert from ISO 8601 Ordinal Date format.-- Invalid day numbers return NothingfromOrdinalDateValid :: Integer -> Int -> MaybeDayfromOrdinalDateValidyearday = do
day' <- clipValid1 (if isLeapYearyear then 366 else 365) day
let
y = year-1mjd = (fromIntegralday') + (365*y) + (divy4) - (divy100) + (divy400) -678576return (ModifiedJulianDaymjd)
-- | show in ISO 8601 Ordinal Date format (yyyy-ddd)showOrdinalDate :: Day -> StringshowOrdinalDatedate = (show4 (Just'0') y) ++"-"++ (show3 (Just'0') d) where
(y,d) = toOrdinalDatedate-- | Is this year a leap year according to the proleptic Gregorian calendar?isLeapYear :: Integer -> BoolisLeapYearyear = (modyear4==0) && ((modyear400==0) ||not (modyear100==0))
-- | Get the number of the Monday-starting week in the year and the day of the week.-- The first Monday is the first day of week 1, any earlier days in the year are week 0 (as \"%W\" in 'Data.Time.Format.formatTime').-- Monday is 1, Sunday is 7 (as \"%u\" in 'Data.Time.Format.formatTime').mondayStartWeek :: Day -> (Int,Int)
mondayStartWeekdate = (fromInteger ((divd7) - (divk7)),fromInteger (modd7) +1) where
yd = snd (toOrdinalDatedate)
d = (toModifiedJulianDaydate) +2k = d- (toIntegeryd)
-- | Get the number of the Sunday-starting week in the year and the day of the week.-- The first Sunday is the first day of week 1, any earlier days in the year are week 0 (as \"%U\" in 'Data.Time.Format.formatTime').-- Sunday is 0, Saturday is 6 (as \"%w\" in 'Data.Time.Format.formatTime').sundayStartWeek :: Day -> (Int,Int)
sundayStartWeekdate =(fromInteger ((divd7) - (divk7)),fromInteger (modd7)) where
yd = snd (toOrdinalDatedate)
d = (toModifiedJulianDaydate) +3k = d- (toIntegeryd)
-- | The inverse of 'mondayStartWeek'. Get a 'Day' given the year,-- the number of the Monday-starting week, and the day of the week.-- The first Monday is the first day of week 1, any earlier days in the year -- are week 0 (as \"%W\" in 'Data.Time.Format.formatTime').fromMondayStartWeek :: Integer-- ^ Year.
-> Int-- ^ Monday-starting week number.
-> Int-- ^ Day of week. -- Monday is 1, Sunday is 7 (as \"%u\" in 'Data.Time.Format.formatTime').
-> DayfromMondayStartWeekywd = ModifiedJulianDay (firstDay+yd)
where yd = firstMonday+7*toInteger (w-1) +toIntegerd-1-- first day of the yearfirstDay = toModifiedJulianDay (fromOrdinalDatey1)
-- 0-based year day of first monday of the yearfirstMonday = (5-firstDay) `mod`7fromMondayStartWeekValid :: Integer-- ^ Year.
-> Int-- ^ Monday-starting week number.
-> Int-- ^ Day of week. -- Monday is 1, Sunday is 7 (as \"%u\" in 'Data.Time.Format.formatTime').
-> MaybeDayfromMondayStartWeekValidyearwd = do
d' <- clipValid17d-- first day of the year
let firstDay = toModifiedJulianDay (fromOrdinalDateyear1)
-- 0-based year day of first monday of the year
let firstMonday = (5-firstDay) `mod`7
let yd = firstMonday+7*toInteger (w-1) +toIntegerd'yd' <- clipValid1 (if isLeapYearyear then 366 else 365) ydreturn (ModifiedJulianDay (firstDay-1+yd'))
-- | The inverse of 'sundayStartWeek'. Get a 'Day' given the year and-- the number of the day of a Sunday-starting week.-- The first Sunday is the first day of week 1, any earlier days in the -- year are week 0 (as \"%U\" in 'Data.Time.Format.formatTime').fromSundayStartWeek :: Integer-- ^ Year.
-> Int-- ^ Sunday-starting week number.
-> Int-- ^ Day of week-- Sunday is 0, Saturday is 6 (as \"%w\" in 'Data.Time.Format.formatTime').
-> DayfromSundayStartWeekywd = ModifiedJulianDay (firstDay+yd)
where yd = firstSunday+7*toInteger (w-1) +toIntegerd-- first day of the yearfirstDay = toModifiedJulianDay (fromOrdinalDatey1)
-- 0-based year day of first sunday of the yearfirstSunday = (4-firstDay) `mod`7fromSundayStartWeekValid :: Integer-- ^ Year.
-> Int-- ^ Monday-starting week number.
-> Int-- ^ Day of week. -- Monday is 1, Sunday is 7 (as \"%u\" in 'Data.Time.Format.formatTime').
-> MaybeDayfromSundayStartWeekValidyearwd = do
d' <- clipValid17d-- first day of the year
let firstDay = toModifiedJulianDay (fromOrdinalDateyear1)
-- 0-based year day of first sunday of the year
let firstMonday = (4-firstDay) `mod`7
let yd = firstMonday+7*toInteger (w-1) +toIntegerd'yd' <- clipValid1 (if isLeapYearyear then 366 else 365) ydreturn (ModifiedJulianDay (firstDay-1+yd'))