lib: Period, a richer period type
This commit is contained in:
		
							parent
							
								
									b7071dee84
								
							
						
					
					
						commit
						94537f30d4
					
				| @ -15,6 +15,7 @@ module Hledger.Data ( | |||||||
|                module Hledger.Data.Dates, |                module Hledger.Data.Dates, | ||||||
|                module Hledger.Data.Journal, |                module Hledger.Data.Journal, | ||||||
|                module Hledger.Data.Ledger, |                module Hledger.Data.Ledger, | ||||||
|  |                module Hledger.Data.Period, | ||||||
|                module Hledger.Data.Posting, |                module Hledger.Data.Posting, | ||||||
|                module Hledger.Data.RawOptions, |                module Hledger.Data.RawOptions, | ||||||
|                module Hledger.Data.StringFormat, |                module Hledger.Data.StringFormat, | ||||||
| @ -33,6 +34,7 @@ import Hledger.Data.Commodity | |||||||
| import Hledger.Data.Dates | import Hledger.Data.Dates | ||||||
| import Hledger.Data.Journal | import Hledger.Data.Journal | ||||||
| import Hledger.Data.Ledger | import Hledger.Data.Ledger | ||||||
|  | import Hledger.Data.Period | ||||||
| import Hledger.Data.Posting | import Hledger.Data.Posting | ||||||
| import Hledger.Data.RawOptions | import Hledger.Data.RawOptions | ||||||
| import Hledger.Data.StringFormat | import Hledger.Data.StringFormat | ||||||
|  | |||||||
							
								
								
									
										118
									
								
								hledger-lib/Hledger/Data/Period.hs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								hledger-lib/Hledger/Data/Period.hs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | |||||||
|  | {-| | ||||||
|  | 
 | ||||||
|  | Manipulating the time periods typically used for reports | ||||||
|  | using Period, a richer abstraction than DateSpan. | ||||||
|  | See also Types and Dates. | ||||||
|  | 
 | ||||||
|  | -} | ||||||
|  | 
 | ||||||
|  | module Hledger.Data.Period | ||||||
|  | where | ||||||
|  | 
 | ||||||
|  | import Data.Time.Calendar | ||||||
|  | import Data.Time.Calendar.WeekDate | ||||||
|  | 
 | ||||||
|  | import Hledger.Data.Types | ||||||
|  | import Hledger.Data.Dates () -- DateSpan Show instance | ||||||
|  | 
 | ||||||
|  | -- | Convert Periods to DateSpans. | ||||||
|  | -- | ||||||
|  | -- >>> periodAsDateSpan (MonthPeriod 2000 1) == DateSpan (Just $ fromGregorian 2000 1 1) (Just $ fromGregorian 2000 2 1) | ||||||
|  | -- True | ||||||
|  | periodAsDateSpan :: Period -> DateSpan | ||||||
|  | periodAsDateSpan (DayPeriod d) = DateSpan (Just d) (Just $ addDays 1 d) | ||||||
|  | periodAsDateSpan (WeekPeriod b) = DateSpan (Just b) (Just $ addDays 7 b) | ||||||
|  | periodAsDateSpan (MonthPeriod y m) = DateSpan (Just $ fromGregorian y m 1) (Just $ fromGregorian y' m' 1) | ||||||
|  |   where | ||||||
|  |     (y',m') | m==12     = (y+1,1) | ||||||
|  |             | otherwise = (y,m+1) | ||||||
|  | periodAsDateSpan (QuarterPeriod y q) = DateSpan (Just $ fromGregorian y m 1) (Just $ fromGregorian y' m' 1) | ||||||
|  |   where | ||||||
|  |     (y', q') | q==4      = (y+1,1) | ||||||
|  |              | otherwise = (y,q+1) | ||||||
|  |     quarterAsMonth q = (q-1) * 3 + 1 | ||||||
|  |     m  = quarterAsMonth q | ||||||
|  |     m' = quarterAsMonth q' | ||||||
|  | periodAsDateSpan (YearPeriod y) = DateSpan (Just $ fromGregorian y 1 1) (Just $ fromGregorian (y+1) 1 1) | ||||||
|  | periodAsDateSpan (PeriodBetween b e) = DateSpan (Just b) (Just e) | ||||||
|  | periodAsDateSpan (PeriodFrom b) = DateSpan (Just b) Nothing | ||||||
|  | periodAsDateSpan (PeriodTo e) = DateSpan Nothing (Just e) | ||||||
|  | periodAsDateSpan (PeriodAll) = DateSpan Nothing Nothing | ||||||
|  | 
 | ||||||
|  | -- | Convert DateSpans to Periods. | ||||||
|  | -- | ||||||
|  | -- >>> dateSpanAsPeriod $ DateSpan (Just $ fromGregorian 2000 1 1) (Just $ fromGregorian 2000 2 1) | ||||||
|  | -- MonthPeriod 2000 1 | ||||||
|  | dateSpanAsPeriod :: DateSpan -> Period | ||||||
|  | dateSpanAsPeriod (DateSpan (Just b) (Just e)) = simplifyPeriod $ PeriodBetween b e | ||||||
|  | dateSpanAsPeriod (DateSpan (Just b) Nothing) = PeriodFrom b | ||||||
|  | dateSpanAsPeriod (DateSpan Nothing (Just e)) = PeriodTo e | ||||||
|  | dateSpanAsPeriod (DateSpan Nothing Nothing) = PeriodAll | ||||||
|  | 
 | ||||||
|  | -- | Convert PeriodBetweens to a more abstract period where possible. | ||||||
|  | -- | ||||||
|  | -- >>> simplifyPeriod $ PeriodBetween (fromGregorian 1 1 1) (fromGregorian 2 1 1) | ||||||
|  | -- YearPeriod 1 | ||||||
|  | -- >>> simplifyPeriod $ PeriodBetween (fromGregorian 2000 10 1) (fromGregorian 2001 1 1) | ||||||
|  | -- QuarterPeriod 2000 4 | ||||||
|  | -- >>> simplifyPeriod $ PeriodBetween (fromGregorian 2000 2 1) (fromGregorian 2000 3 1) | ||||||
|  | -- MonthPeriod 2000 2 | ||||||
|  | -- >>> simplifyPeriod $ PeriodBetween (fromGregorian 2016 7 25) (fromGregorian 2016 8 1) | ||||||
|  | -- WeekPeriod 2016-07-25 | ||||||
|  | -- >>> simplifyPeriod $ PeriodBetween (fromGregorian 2000 1 1) (fromGregorian 2000 1 2) | ||||||
|  | -- DayPeriod 2000-01-01 | ||||||
|  | -- >>> simplifyPeriod $ PeriodBetween (fromGregorian 2000 2 28) (fromGregorian 2000 3 1) | ||||||
|  | -- PeriodBetween 2000-02-28 2000-03-01 | ||||||
|  | -- >>> simplifyPeriod $ PeriodBetween (fromGregorian 2000 2 29) (fromGregorian 2000 3 1) | ||||||
|  | -- DayPeriod 2000-02-29 | ||||||
|  | -- >>> simplifyPeriod $ PeriodBetween (fromGregorian 2000 12 31) (fromGregorian 2001 1 1) | ||||||
|  | -- DayPeriod 2000-12-31 | ||||||
|  | -- | ||||||
|  | simplifyPeriod :: Period -> Period | ||||||
|  | simplifyPeriod (PeriodBetween b e) = | ||||||
|  |   case (toGregorian b, toGregorian e) of | ||||||
|  |     -- a year | ||||||
|  |     ((by,1,1), (ey,1,1))   | by+1==ey           -> YearPeriod by | ||||||
|  |     -- a half-year | ||||||
|  |     -- ((by,1,1), (ey,7,1))   | by==ey             -> | ||||||
|  |     -- ((by,7,1), (ey,1,1))   | by+1==ey           -> | ||||||
|  |     -- a quarter | ||||||
|  |     ((by,1,1), (ey,4,1))   | by==ey             -> QuarterPeriod by 1 | ||||||
|  |     ((by,4,1), (ey,7,1))   | by==ey             -> QuarterPeriod by 2 | ||||||
|  |     ((by,7,1), (ey,10,1))  | by==ey             -> QuarterPeriod by 3 | ||||||
|  |     ((by,10,1), (ey,1,1))  | by+1==ey           -> QuarterPeriod by 4 | ||||||
|  |     -- a month | ||||||
|  |     ((by,bm,1), (ey,em,1)) | by==ey && bm+1==em -> MonthPeriod by bm | ||||||
|  |     ((by,12,1), (ey,1,1))  | by+1==ey           -> MonthPeriod by 12 | ||||||
|  |     -- a week (two successive mondays), | ||||||
|  |     -- YYYYwN ("week N of year YYYY") | ||||||
|  |     -- _ | let ((by,bw,bd), (ey,ew,ed)) = (toWeekDate from, toWeekDate to) in by==ey && fw+1==tw && bd==1 && ed==1 -> | ||||||
|  |     -- a week starting on a monday | ||||||
|  |     _ | let ((by,bw,bd), (ey,ew,ed)) = (toWeekDate b, toWeekDate (addDays (-1) e)) | ||||||
|  |         in by==ey && bw==ew && bd==1 && ed==7   -> WeekPeriod b | ||||||
|  |     -- a day | ||||||
|  |     ((by,bm,bd), (ey,em,ed)) | | ||||||
|  |         (by==ey && bm==em && bd+1==ed) || | ||||||
|  |         (by+1==ey && bm==12 && em==1 && bd==31 && ed==1) || -- crossing a year boundary | ||||||
|  |         (by==ey && bm+1==em && isLastDayOfMonth by bm bd && ed==1) -- crossing a month boundary | ||||||
|  |          -> DayPeriod b | ||||||
|  |     _ -> PeriodBetween b e | ||||||
|  | simplifyPeriod p = p | ||||||
|  | 
 | ||||||
|  | isLastDayOfMonth y m d = | ||||||
|  |   case m of | ||||||
|  |     1 -> d==31 | ||||||
|  |     2 | isLeapYear y -> d==29 | ||||||
|  |       | otherwise    -> d==28 | ||||||
|  |     3 -> d==31 | ||||||
|  |     4 -> d==30 | ||||||
|  |     5 -> d==31 | ||||||
|  |     6 -> d==30 | ||||||
|  |     7 -> d==31 | ||||||
|  |     8 -> d==31 | ||||||
|  |     9 -> d==30 | ||||||
|  |     10 -> d==31 | ||||||
|  |     11 -> d==30 | ||||||
|  |     12 -> d==31 | ||||||
|  |     _ -> False | ||||||
|  | 
 | ||||||
| @ -45,11 +45,57 @@ data DateSpan = DateSpan (Maybe Day) (Maybe Day) deriving (Eq,Ord,Data,Generic,T | |||||||
| 
 | 
 | ||||||
| instance NFData DateSpan | instance NFData DateSpan | ||||||
| 
 | 
 | ||||||
| data Interval = NoInterval | -- synonyms for various date-related scalars | ||||||
|               | Days Int | Weeks Int | Months Int | Quarters Int | Years Int | type Year = Integer | ||||||
|               | DayOfMonth Int | DayOfWeek Int | type Month = Int     -- 1-12 | ||||||
|               -- WeekOfYear Int | MonthOfYear Int | QuarterOfYear Int | type Quarter = Int   -- 1-4 | ||||||
|                 deriving (Eq,Show,Ord,Data,Generic,Typeable) | type YearWeek = Int  -- 1-52 | ||||||
|  | type MonthWeek = Int -- 1-5 | ||||||
|  | type YearDay = Int   -- 1-366 | ||||||
|  | type MonthDay = Int  -- 1-31 | ||||||
|  | type WeekDay = Int   -- 1-7 | ||||||
|  | 
 | ||||||
|  | -- Typical report periods (spans of time), both finite and open-ended. | ||||||
|  | -- A richer abstraction than DateSpan. | ||||||
|  | data Period = | ||||||
|  |     DayPeriod Day | ||||||
|  |   | WeekPeriod Day | ||||||
|  |   | MonthPeriod Year Month | ||||||
|  |   | QuarterPeriod Year Quarter | ||||||
|  |   | YearPeriod Year | ||||||
|  |   | PeriodBetween Day Day | ||||||
|  |   | PeriodFrom Day | ||||||
|  |   | PeriodTo Day | ||||||
|  |   | PeriodAll | ||||||
|  |   deriving (Eq,Ord,Show,Data,Generic,Typeable) | ||||||
|  | 
 | ||||||
|  | instance Default Period where def = PeriodAll | ||||||
|  | 
 | ||||||
|  | ---- Typical report period/subperiod durations, from a day to a year. | ||||||
|  | --data Duration = | ||||||
|  | --    DayLong | ||||||
|  | --   WeekLong | ||||||
|  | --   MonthLong | ||||||
|  | --   QuarterLong | ||||||
|  | --   YearLong | ||||||
|  | --  deriving (Eq,Ord,Show,Data,Generic,Typeable) | ||||||
|  | 
 | ||||||
|  | -- Ways in which a period can be divided into subperiods. | ||||||
|  | data Interval = | ||||||
|  |     NoInterval | ||||||
|  |   | Days Int | ||||||
|  |   | Weeks Int | ||||||
|  |   | Months Int | ||||||
|  |   | Quarters Int | ||||||
|  |   | Years Int | ||||||
|  |   | DayOfMonth Int | ||||||
|  |   | DayOfWeek Int | ||||||
|  |   -- WeekOfYear Int | ||||||
|  |   -- MonthOfYear Int | ||||||
|  |   -- QuarterOfYear Int | ||||||
|  |   deriving (Eq,Show,Ord,Data,Generic,Typeable) | ||||||
|  | 
 | ||||||
|  | instance Default Interval where def = NoInterval | ||||||
| 
 | 
 | ||||||
| instance NFData Interval | instance NFData Interval | ||||||
| 
 | 
 | ||||||
| @ -223,8 +269,6 @@ data MarketPrice = MarketPrice { | |||||||
| 
 | 
 | ||||||
| instance NFData MarketPrice | instance NFData MarketPrice | ||||||
| 
 | 
 | ||||||
| type Year = Integer |  | ||||||
| 
 |  | ||||||
| -- | A Journal, containing transactions and various other things. | -- | A Journal, containing transactions and various other things. | ||||||
| -- The basic data model for hledger. | -- The basic data model for hledger. | ||||||
| -- | -- | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user