-
Notifications
You must be signed in to change notification settings - Fork 6
/
source-to-json.py
executable file
·139 lines (123 loc) · 4.53 KB
/
source-to-json.py
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env python2
# tz.js - Library for working with timezones in JavaScript
# Written in 2011 by L. David Baron <dbaron@dbaron.org>
# To the extent possible under law, the author(s) have dedicated all
# copyright and related and neighboring rights to this software to the
# public domain worldwide. This software is distributed without any
# warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication
# along with this software. If not, see
# <http://creativecommons.org/publicdomain/zero/1.0/>.
# This script is intended to convert the source time zone data from the
# Olson time zone database (http://www.twinsun.com/tz/tz-link.htm), that
# is, the tzdata* data, into a JSON format suitable for inclusion in the
# tz.js JavaScript library.
# It is not yet anywhere near complete, but at some point in the future
# I would like to replace the current data (generated by
# compiled-to-json.py) with a more compact data format generated here.
from optparse import OptionParser
import os.path
import re
import tarfile
op = OptionParser()
(options, args) = op.parse_args()
if len(args) == 1:
tzdatatar = args[0]
else:
op.error("expected a single argument (the tzdata archive)")
tzversion = re.match('tzdata(.*)\.tar\.gz$', os.path.basename(tzdatatar))
if tzversion is None:
raise StandardError("argument must be tzdata archive")
tzversion = tzversion.groups()[0]
print "/* Time zone data version " + tzversion + ". */"
def read_lines():
tar = tarfile.open(name=tzdatatar, mode="r:*")
members_of_tar = set([
# We use only these members of the tar file and ignore the rest,
# since they have information we don't want.
"africa",
"antarctica",
"asia",
"australasia",
"europe",
"northamerica",
"southamerica"
])
for tarinfo in tar:
if not tarinfo.isfile() or not tarinfo.name in members_of_tar:
continue
# FIXME: Should set encoding on this |io| to iso-8859-1.
io = tar.extractfile(tarinfo)
for line in io:
line = line.rstrip("\n")
line = line.partition("#")[0]
line = line.rstrip(" \t")
if line is "":
continue
yield line
io.close()
tar.close()
zones = {}
rules = {}
def process_time(s):
if s == '-':
return 0
negate = 1
if s[0] == '-':
negate = -1
s = s[1:]
# FIXME: Do a little more validation on these integers?
words = [int(n) for n in s.split(":")]
value = words[0] * 3600
if len(words) > 1:
value = value + words[1] * 60
if len(words) > 2:
value = value + words[2]
if len(words) > 3:
raise StandardError("unexpected time " + s)
return value * negate
def handle_zone_line(words):
(gmtoff, rules, fmt) = words[0:3]
until = " ".join(words[3:])
# FIXME: process the "until" instead -- it's in LOCAL time unless suffixed
return { "o": process_time(gmtoff), "r": rules, "f": fmt, "u": until }
ws_re = re.compile("[ \t]+")
current_zone = None
for line in read_lines():
# For documentation, see zic(8), which is included in the tzcode*
# distribution.
words = ws_re.split(line)
if words[0] == '':
# FIXME: Check appending consistency with UNTIL value
if current_zone is None:
raise StandardError("continuation line when not in Zone")
current_zone.append(handle_zone_line(words[1:]))
elif words[0] == 'Zone':
# FIXME: Check appending consistency with UNTIL value
current_zone = []
current_zone.append(handle_zone_line(words[2:]))
name = words[1]
if name in zones:
raise StandardError("duplicate zone " + name)
zones[name] = current_zone
elif words[0] == 'Rule':
current_zone = None
(name_, from_, to_, type_, in_, on_, at_, save_, letter_) = words[1:]
rule = rules.setdefault(name_, [])
rule.append(words[2:])
elif words[0] == 'Link':
current_zone = None
# ignore
else:
raise StandardError("unexpected line " + " ".join(words))
print zones
print rules
# FIXME: TO BE WRITTEN
# For rule generation, see the stringzone (and stringrule) functions in
# zic.c in the tzcode distribution, noting the cases that stringzone
# generates the empty string.
# In the cases where rules aren't much use, or when they can't be
# generated at all, it may be better to use the dominant format
# generated by compiled-to-json.py, though. See the outzone function in
# zic.c.