summaryrefslogtreecommitdiff
path: root/src/CosmicCalendar.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/CosmicCalendar.hs')
-rw-r--r--src/CosmicCalendar.hs140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/CosmicCalendar.hs b/src/CosmicCalendar.hs
new file mode 100644
index 0000000..db29c02
--- /dev/null
+++ b/src/CosmicCalendar.hs
@@ -0,0 +1,140 @@
1{-# OPTIONS_GHC
2 -Wall
3 -Wno-unused-imports
4 -Wno-unused-top-binds
5 -Wno-name-shadowing
6#-}
7{-# language NoImplicitPrelude #-}
8{-# language RecordWildCards #-}
9{-# language FlexibleContexts #-}
10{-# language TemplateHaskell #-}
11{-# language ViewPatterns #-}
12{-# language OverloadedStrings #-}
13{-# language QuasiQuotes #-}
14
15module CosmicCalendar where
16
17import Rebase.Prelude
18import qualified Rebase.Prelude as Prelude
19import Control.Lens hiding ((<|))
20import Data.Foldable (toList)
21import Data.Ratio
22import Text.Printf
23import Data.Time.Calendar.OrdinalDate
24import Data.Time.LocalTime
25import Control.Monad.RWS
26import Data.Time.Calendar.OrdinalDate
27import Data.Text.Format.Numbers
28import NeatInterpolation
29import qualified Data.Text as Text
30import Data.Text (Text, pack, unpack)
31
32import Rebase.Data.Map.Strict (Map)
33import qualified Rebase.Data.Map.Strict as Map
34
35-- 13.787±0.020 billion years. Source: https://en.wikipedia.org/wiki/Age_of_the_universe#cite_note-Planck_2018-2
36ageOfUniverseInYears :: Integer
37ageOfUniverseInYears = 13787 * 1000 * 1000
38
39-- The point of the cosmic calendar is to mentally visualize or model the scale
40-- of cosmic/geologic/evolutionary events using the existing internal mental
41-- model of the year. This internal mental model of the year is NOT a 365.2422
42-- day earth rotation, but a 365 day calendar year.
43--
44-- In order to make the math of the calendar work out, the functions that look
45-- up calendary entries (and take as input the LocalTime) must check for leap
46-- year, and subtract one day from the input if it is later than February.
47daysPerYear :: NominalDiffTime
48daysPerYear = 365 -- NOT 365.2422
49
50lengthOfDay :: NominalDiffTime
51lengthOfDay = 24 * 60 * 60
52
53lengthOfYear :: NominalDiffTime
54lengthOfYear = daysPerYear * lengthOfDay
55
56ageOfUniverse :: NominalDiffTime
57ageOfUniverse = fromIntegral ageOfUniverseInYears * lengthOfYear
58
59data CalendarEntry = CalendarEntry {
60 calBeginTime :: NominalDiffTime,
61 calEndTime :: Maybe NominalDiffTime,
62 calTitle :: Text,
63 calSubtitle :: Text,
64 calDescription :: Text,
65 calReferences :: Text
66} deriving (Show)
67
68-- TODO: Encode the input times like so:
69--
70-- data CosmicTime = YearsAgo Rational | YearsAfterBigBang Rational | YearsBCE Rational | YearsCE Rational
71--
72-- The absolute time values (YearsBCE and YearsCE) will be computed using the
73-- year at program start:
74
75currentYear :: Integer
76currentYear = unsafePerformIO $ getZonedTime <&> toGregorian . localDay . zonedTimeToLocalTime <&> view _1
77
78years :: Rational -> NominalDiffTime
79years = (* lengthOfYear) . fromRational
80
81yearsAgo :: Rational -> NominalDiffTime
82yearsAgo (fromRational -> n) = lengthOfYear * (1 - (n / fromIntegral ageOfUniverseInYears))
83
84afterBigBang :: NominalDiffTime -> NominalDiffTime
85afterBigBang = (/ ageOfUniverse) . (* lengthOfYear)
86
87thousandYears :: Rational -> NominalDiffTime
88thousandYears = years . (* 1000)
89
90millionYears :: Rational -> NominalDiffTime
91millionYears = thousandYearsAgo . (* 1000)
92
93billionYears :: Rational -> NominalDiffTime
94billionYears = millionYearsAgo . (* 1000)
95
96thousandYearsAgo :: Rational -> NominalDiffTime
97thousandYearsAgo = yearsAgo . (* 1000)
98
99millionYearsAgo :: Rational -> NominalDiffTime
100millionYearsAgo = thousandYearsAgo . (* 1000)
101
102billionYearsAgo :: Rational -> NominalDiffTime
103billionYearsAgo = millionYearsAgo . (* 1000)
104
105yearStart :: LocalTime -> LocalTime
106yearStart (LocalTime d _) = LocalTime d' t'
107 where
108 d' = fromGregorian y 1 1
109 t' = TimeOfDay 0 0 0
110 (y, _, _) = toGregorian d
111
112localTimeToYearElapsed :: LocalTime -> NominalDiffTime
113localTimeToYearElapsed t = t `diffLocalTime` yearStart t
114
115getPreviousCalendarEntry :: Calendar -> LocalTime -> Maybe CalendarEntry
116getPreviousCalendarEntry cal (localTimeToYearElapsed -> t) = snd <$> Map.lookupLT t cal
117
118getCurrentCalendarEntry :: Calendar -> LocalTime -> Maybe CalendarEntry
119getCurrentCalendarEntry cal (localTimeToYearElapsed -> t) = snd <$> Map.lookupLE t cal
120
121type Calendar = Map NominalDiffTime CalendarEntry
122
123getNextCalendarEntry :: Calendar -> LocalTime -> Maybe CalendarEntry
124getNextCalendarEntry cal (localTimeToYearElapsed -> t) = snd <$> Map.lookupGT t cal
125
126buildCalendar :: [CalendarEntry] -> Map NominalDiffTime CalendarEntry
127buildCalendar ls = Map.fromList $ map (\x -> (calBeginTime x, x)) $ map unwrap ls
128
129unwrap :: CalendarEntry -> CalendarEntry
130unwrap x@CalendarEntry{..} = x { calDescription = unwrapText calDescription }
131 where
132 unwrapText :: Text -> Text
133 unwrapText = pack . unlines . map unwords . foldr process [] . lines . unpack
134 process line [] = [[line]]
135 process line ((x:xs):ys) | shouldMerge line x = (line:x:xs):ys
136 process line rest = [line]:rest
137 shouldMerge :: String -> String -> Bool
138 shouldMerge "" _ = False
139 shouldMerge _ "" = False
140 shouldMerge _ _ = True