-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathMakeLeapSecondTable.hs
107 lines (95 loc) · 4.37 KB
/
MakeLeapSecondTable.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
{- |
Use this applicaton to generate the 'Data.Time.Clock.AnnouncedLeapSeconds'
module. Compile and pipe an EOP file from Celestrak through the binary,
e.g.:
curl http://www.celestrak.com/SpaceData/eop19620101.txt | ./MakeLeapSecondTable > Data/Time/Clock/AnnouncedLeapSeconds.hs
-}
import Astro.Celestrak
import Data.List (intercalate)
import Data.Time (Day)
import Data.Time.Format (formatTime)
import System.Locale (defaultTimeLocale)
-- | Converts an 'EOPList' into a minimal list of (day, leapsecond) pairs
-- in reverse chronological order.
eopToLS :: EOPList a -> [(Day, Integer)]
eopToLS = reverse . keepInitial . fmap (fmap deltaAT)
-- | Keeps the first pair with a given snd value while dropping the
-- following pairs with the same snd value.
keepInitial :: Eq a => [(b,a)] -> [(b,a)]
keepInitial (x:xs) = x : keepInitial (dropWhile (sndEq x) xs) where sndEq (_,x) (_,y) = x == y
keepInitial [] = []
{-
The above and this function are candidates for moving to "Astro.Celestrak":
-- | Converts an 'EOPList' to a light weight 'LeapSecondTable' (its internal
-- data is a short list as opposed to a huge array for the 'LeapSecondTable'
-- provided by "Astro.Celestrak".
eopToLST :: EOPList a -> LeapSecondTable
eopToLST eops d = snd $ headDef (undefined,0) $ dropWhile ((>d).fst) $ eopToLS eops
-}
-- | Convert a day/leapsecond pair into a compilable string.
lsToString :: (Day, Integer) -> String
lsToString (d,s) = formatTime defaultTimeLocale fmt d
where fmt = "(fromGregorian %Y %m %d, " ++ show s ++ ")"
-- | Shows a list in compilable format using the passed function to display
-- the elements of the list.
showL :: (a -> String) -> [a] -> String
showL showf xs = intercalate "\n : " (map showf xs) ++ "\n : []"
-- | Compilable leapsecond module.
showModule :: EOPList a -> String
showModule eops = unlines
[ "-- This file was automatically generated."
, ""
, "{- |"
, " Copyright : Copyright (C) 2009-2015 Bjorn Buckwalter"
, " License : BSD3"
, ""
, " Maintainer : [email protected]"
, " Stability : stable"
, " Portability: full"
, ""
, "Provides a static 'Data.Time.Clock.TAI.LeapSecondTable' \\\"containing\\\""
, "the leap seconds announced at library release time. This version"
, "will become invalidated when/if the International Earth Rotation"
, "and Reference Systems Service (IERS) announces a new leap second at"
, "<http://hpiers.obspm.fr/eoppc/bul/bulc/bulletinc.dat>."
, "At that time a new version of the library will be released, against"
, "which any code wishing to remain up to date should be recompiled."
, ""
, "This module is intended to provide a quick-and-dirty leap second solution"
, "for one-off analyses concerned only with the past and present (i.e. up"
, "until the next as of yet unannounced leap second), or for applications"
, "which can afford to be recompiled against an updated library as often"
, "as every six months."
, "-}"
, ""
, "module Data.Time.Clock.AnnouncedLeapSeconds (lst) where"
, ""
, "import Data.Maybe (listToMaybe)"
, "import Data.Time (Day, fromGregorian)"
, "import Data.Time.Clock.TAI (LeapSecondTable)"
, ""
, "-- | List of all leap seconds up to 2015-07-01. An"
, "-- estimate of hypothetical leap seconds prior to 1972-01-01 is"
, "-- included. These can be understood as leap seconds that may have"
, "-- been introduced had UTC used the SI second since its inception in 1961."
, "-- One should be extremely careful in using this information as it is"
, "-- generally not appropriate. One specific case where it may be useful"
, "-- is in reducing the error in computed time differences between UTC time"
, "-- stamps in the 1961--1971 range from the order of 10 SI seconds to 1 SI"
, "-- second."
, "pseudoLeapSeconds :: [(Day, Int)]"
, "pseudoLeapSeconds = " ++ showL lsToString ls
, ""
, "-- | List of all official leap seconds from 1972-01-01 to 2015-07-01."
, "leapSeconds :: [(Day, Int)]"
, "leapSeconds = takeWhile (> introduction) pseudoLeapSeconds ++ [introduction]"
, " where"
, " introduction = (fromGregorian 1972 01 01, 10)"
, ""
, "-- | 'Data.Time.Clock.TAI.LeapSecondTable' containing all leap seconds"
, "-- from 1972-01-01 to " ++ (show.fst.head) ls ++ "."
, "lst :: LeapSecondTable"
, "lst d = fmap snd $ listToMaybe $ dropWhile ((>d).fst) leapSeconds"
] where ls = eopToLS eops
main = do
interact (showModule . parseEOPData)