git.iko.soy/typeable/extra-time
on master help sign in
Merge pull request #3 from typeable/wip/yuras/holidays

Add time accounting for holidays

commit113c91bef78c5a548dfe915ed96d863e40039ec2 authorYuras <shumovichy@gmail.com> dateTue 20 Dec 2022, 11:36 (4 years ago) parent537af3ece26acb
2 files changed+43
extra-time.cabal+2 src/Data/Time/Holidays.hs+41
extra-time.cabal+2
@@ -27,6 +27,7 @@ library
2727 -- | from ghc
2828 base >= 4.7 && < 5 ,
2929 binary ,
30+ containers ,
3031 deepseq ,
3132 mtl >= 2.2 ,
3233 text ,
@@ -46,6 +47,7 @@ library
4647 exposed-modules:
4748 Data.Time.Extra
4849 Data.Time.Fmt
50+ Data.Time.Holidays
4951 Data.Time.LocalTime.Short
5052 Data.Time.Utils
5153 other-modules:
src/Data/Time/Holidays.hsnew file+41
@@ -0,0 +1,41 @@
1+module Data.Time.Holidays
2+ ( addTimeExcludingHolidays
3+ ) where
4+
5+import Data.Proxy
6+import qualified Data.Set as S
7+import Data.Time
8+import Data.Time.Calendar.OrdinalDate
9+import Data.Time.LocalTime.TimeZone.Series
10+
11+
12+addTimeExcludingHolidays
13+ :: S.Set Day
14+ -> TimeZoneSeries
15+ -> DiffTime
16+ -> UTCTime
17+ -> UTCTime
18+addTimeExcludingHolidays hDays tz dTime =
19+ addLocalTime' dTime . utcToLocalTime' tz
20+ where
21+ shouldSkip day = weekday `elem` [6, 7] || day `S.member` hDays
22+ where (_, weekday) = mondayStartWeek day
23+ dayPicoseconds =
24+ diffTimeToPicoseconds . secondsToDiffTime $ 60 * 60 * 24
25+ addLocalTime' :: DiffTime -> LocalTime -> UTCTime
26+ addLocalTime' dTime' (LocalTime lDay' lTime') =
27+ let
28+ actualDays = filter (not . shouldSkip) [lDay'..]
29+ -- Jumps to nearest day if `now` is a holiday
30+ lTime = if shouldSkip lDay'
31+ then midnight
32+ else lTime'
33+ -- At this point the head of `actualDays` and `lTime`
34+ -- is the day from which we should be counting
35+ (dDays, dPicoSeconds) =
36+ (diffTimeToPicoseconds $ dTime' + (timeOfDayToTime lTime))
37+ `divMod` dayPicoseconds
38+ resultDay = head . drop (fromIntegral dDays) $ actualDays
39+ resultTime =
40+ timeToTimeOfDay . picosecondsToDiffTime $ dPicoSeconds
41+ in localTimeToUTC' tz $ LocalTime resultDay resultTime