0 | module IotaTime.Tzdb.Metadata
6 | record ZoneAlias where
7 | constructor MkZoneAlias
13 | record TzdbMetadata where
14 | constructor MkTzdbMetadata
15 | tzdbVersion : Maybe String
16 | zoneAliases : List ZoneAlias
18 | versionLine : List String -> Maybe String
19 | versionLine ["#", "version", value] = Just value
20 | versionLine _ = Nothing
22 | aliasLine : List String -> Maybe ZoneAlias
23 | aliasLine ["L", canonical, alias] = Just (MkZoneAlias alias canonical)
24 | aliasLine _ = Nothing
26 | firstJust : (value -> Maybe result) -> List value -> Maybe result
27 | firstJust convert [] = Nothing
28 | firstJust convert (value :: rest) = case convert value of
29 | Just result => Just result
30 | Nothing => firstJust convert rest
32 | isWhitespace : Char -> Bool
33 | isWhitespace ' ' = True
34 | isWhitespace '\t' = True
35 | isWhitespace _ = False
37 | tokens : String -> List String
38 | tokens source = go [] [] (unpack source)
40 | finish : List Char -> List String -> List String
41 | finish [] found = reverse found
42 | finish current found = reverse (pack (reverse current) :: found)
44 | go : List Char -> List String -> List Char -> List String
45 | go current found [] = finish current found
46 | go current found (value :: rest) =
47 | if isWhitespace value
48 | then case current of
49 | [] => go [] found rest
50 | _ => go [] (pack (reverse current) :: found) rest
51 | else go (value :: current) found rest
53 | sourceLines : String -> List String
54 | sourceLines source = go [] (unpack source)
56 | go : List Char -> List Char -> List String
57 | go current [] = [pack (reverse current)]
58 | go current ('\r' :: '\n' :: rest) =
59 | pack (reverse current) :: go [] rest
60 | go current ('\n' :: rest) = pack (reverse current) :: go [] rest
61 | go current (value :: rest) = go (value :: current) rest
65 | parseTzdataIdentity : String -> (Maybe String, List ZoneAlias)
66 | parseTzdataIdentity source =
67 | let tokenLines = map tokens (sourceLines source)
68 | in (firstJust versionLine tokenLines, mapMaybe aliasLine tokenLines)
70 | findAlias : String -> List ZoneAlias -> Maybe String
71 | findAlias value [] = Nothing
72 | findAlias value (alias :: rest) =
73 | if alias.aliasId == value then Just alias.canonicalId
74 | else findAlias value rest
78 | canonicalZoneId : TzdbMetadata -> String -> String
79 | canonicalZoneId metadata value = go (length metadata.zoneAliases) value
81 | go : Nat -> String -> String
82 | go Z current = current
83 | go (S fuel) current = case findAlias current metadata.zoneAliases of
85 | Just canonical => go fuel canonical