packages feed

haslo-0.1: Haslo/CalcCalendar.hs

---------------------------------------------------------
--
-- Module        : CalcCalendar
-- Copyright     : Bartosz Wójcik (2010)
-- License       : BSD3
--
-- Maintainer    : bartek@sudety.it
-- Stability     : Unstable
-- Portability   : portable
--
-- Bank calendar of Haskell Loan.
---------------------------------------------------------
-- | Provides data types and basic functions operating on dates
--   in specific calendars.
module Haslo.CalcCalendar 
                    (module Data.Time
                    ,module Data.Time.Calendar.OrdinalDate
                    ,CalendarType (..)
                    ,diffLoanCalendar
                    ,addMonth
                    ,addMonths
                    ,addYears
                    ,setDay
                    ,setOrdinalDay
                    ,Freq (..)
                    ,freqPerYear
                    ,addPeriods
                    )
where

import Data.Time
--import Data.Time.Calendar.Julian
import Data.Time.Calendar.OrdinalDate
import Text.PrettyShow

-- | Bank calendar is usually different than real one.
data CalendarType = Y360                 -- ^ year has 360 days, each month 30 days
                  | Y360Specific         -- ^ year has 360 days, each month 30 days (specific version,
                                         --   where diff 15.02 31.01 = 14 [not 15 as expected!])
                  | RealCalendar         -- ^ each month has real number of days
                  deriving (Eq, Show, Enum)

-- | Number of days between two dates in different calendars
diffLoanCalendar :: Day -> Day -> CalendarType -> Int
diffLoanCalendar d1 d2 Y360 = fromIntegral (360 * (yd1 - yd2)) + 30 * (md1 - md2) + min 30 dd1 - min 30 dd2
                 where (yd1,md1,dd1) = toGregorian  d1
                       (yd2,md2,dd2) = toGregorian  d2
diffLoanCalendar d1 d2 Y360Specific = fromIntegral (360 * (yd1 - yd2)) + 30 * (md1 - md2) + dd1 - dd2
                 where (yd1,md1,dd1) = toGregorian  d1
                       (yd2,md2,dd2) = toGregorian  d2
diffLoanCalendar d1 d2 RealCalendar = fromIntegral $ diffDays d1 d2
--diffLoanCalendar _ _ cal  = error $ "Calendar " ++ show cal ++ " is not yet defined"

addMonth date | m == 12   = fromGregorian (y+1) 1 d
              | otherwise = fromGregorian y (m+1) d
    where (y,m,d) = toGregorian date

addMonths :: Integer -> Day -> Day
addMonths n date = fromGregorian (y + ((n+m-1) `div` 12)) (fromIntegral (n+m-1) `mod` 12 + 1) d
    where (y,m',d) = toGregorian date
          m = fromIntegral m'

addYears :: Integer -> Day -> Day
addYears n date = fromGregorian (y+n) m d
    where (y,m,d) = toGregorian date

setDay n date = fromGregorian y m n
    where (y,m,d) = toGregorian date

setOrdinalDay n date = fromOrdinalDate  y n
    where (y,d) = toOrdinalDate date

-- | Frequency.
data Freq = Daily
          | Monthly
          | Yearly
          deriving (Eq, Ord, Show, Enum)
          
instance PrettyShow Freq where
   showWithLen n = showWithLen n . show

freqPerYear Daily   = 365
freqPerYear Monthly = 12
freqPerYear Yearly  = 1

-- | Increases a date by given number of given units.
addPeriods :: Freq -> Integer -> Day -> Day
addPeriods Daily   = addDays
addPeriods Monthly = addMonths
addPeriods Yearly  = addYears