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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
|
VZIC README
===========
This is 'vzic', a program to convert the Olson timezone database files into
VTIMEZONE files compatible with the iCalendar specification (RFC2445).
(The name is based on the 'zic' program which converts the Olson files into
time zone information files used by several Unix C libraries, including
glibc. See zic(8) and tzfile(5).)
REQUIREMENTS
============
You need the Olson timezone database files, which can be found at:
ftp://elsie.nci.nih.gov/pub/
(Old versions can be found at ftp://munnari.oz.au/pub/oldtz/)
Vzic also uses the GLib library (for hash tables, dynamic arrays, and date
calculations). You need version 2.0 or higher. You can get this from:
http://www.gtk.org
BUILDING
========
Edit the Makefile to set the OLSON_DIR, PRODUCT_ID and TZID_PREFIX variables.
Then run 'make'.
RUNNING
=======
Run 'vzic'.
The output is placed in the zoneinfo subdirectory by default,
but you can use the --output-dir options to set another toplevel output
directory.
By default it outputs VTIMEZONEs that try to be compatible with Outlook
(2000, at least). Outlook can't handle certain iCalendar constructs in
VTIMEZONEs, such as RRULEs using BYMONTHDAY, so it has to adjust the RRULEs
slightly to get Outlook to parse them. Unfortunately this means they are
slightly wrong. If given the --pure option, vzic outputs the exact data,
without worrying about compatability.
NOTE: We don't convert all the Olson files. We skip 'backward', 'etcetera',
'leapseconds', 'pacificnew', 'solar87', 'solar88' and 'solar89', 'factory'
and 'systemv', since these don't really provide any useful timezones.
See vzic.c.
MERGING CHANGES INTO A MASTER SET OF VTIMEZONES
===============================================
The Olson timezone files are updated fairly often, so we need to build new
sets of VTIMEZONE files. Though we have to be careful to ensure that the TZID
of updated timezones is also updated, since it must remain unique.
We use a version number on the end of the TZID prefix (see the TZIDPrefix
variable in vzic-output.c) to ensure this uniqueness.
But we don't want to update the version numbers of VTIMEZONEs which have not
changed. So we use the vzic-merge.pl Perl script. This merges in the new set
of VTIMEZONEs with a 'master' set. It compares each new VTIMEZONE file with
the one in the master set (ignoring changes to the TZID). If the new
VTIMEZONE file is different, it copies it to the master set and sets the
version number to the old VTIMEZONE's version number + 1.
To use vzic-merge.pl you must change the $MASTER_ZONEINFO_DIR and
$NEW_ZONEINFO_DIR variables at the top of the file to point to your 2 sets of
VTIMEZONEs. You then just run the script. (I recommend you keep a backup of
the old master VTIMEZONE files, and use diff to compare the new master set
with the old one, in case anything goes wrong.)
You must merge in changes to the zones.tab file by hand.
Note that some timezones are renamed or removed occasionally, so applications
should be able to cope with this.
COMPATABILITY NOTES
===================
It seems that Microsoft Outlook is very picky about the iCalendar files it
will accept. (I've been testing with Outlook 2000. I hope the other versions
are no worse.) Here's a few problems we've had with the VTIMEZONEs:
o Outlook doesn't like any years before 1600. We were using '1st Jan 0001'
in all VTIMEZONEs to specify the first UTC offset known for the timezone.
(The Olson data does not give a start date for this.)
Now we just skip this first component for most timezones. The UTC offset
can still be found from the TZOFFSETFROM property of the first component.
Though some timezones only specify one UTC offset that applies forever,
so in these cases we output '1st Jan 1970' (Indian/Cocos,
Pacific/Johnston).
o Outlook doesn't like the BYMONTHDAY specifier in RRULEs.
We have changed most of the VTIMEZONEs to use things like 'BYDAY=2SU'
rather than 'BYMONTHDAY=8,9,10,11,12,13,14;BYDAY=SU', though some of
them were impossible to convert correctly so they are not always correct.
o Outlook doesn't like TZOFFSETFROM/TZOFFSETTO properties which include a
seconds component, e.g. 'TZOFFSETFROM:+110628'.
Quite a lot of the Olson timezones include seconds in their UTC offsets,
though no timezones currently have a UTC offset that uses the seconds
value.
We've rounded all UTC offsets to the nearest minute. Since all timezone
offsets currently used have '00' as the seconds offset, this doesn't lose
us much.
o Outlook doesn't like lines being split in certain places, even though
the iCalendar spec says they can be split anywhere.
o Outlook can only handle one RDATE or a pair of RRULEs. So we had to remove
all historical data.
TESTING
=======
Do a 'make test-vic', then run ./test-vic.
The test-vzic program compares our libical code and VTIMEZONE data against
the Unix functions like mktime(). It steps over a period of time (1970-2037)
converting from UTC to a given timezone and back again every 15 minutes.
Any differences are output into the test-output directory.
The output matches for all of the timezones, except in a few places where the
result can't be determined. So I think we can be fairly confident that the
VTIMEZONEs are correct.
Note that you must use the same Olson data in libical that the OS is using
for mktime() etc. For example, I am using RedHat 9 which uses tzdata2002d,
so I converted this to VTIMEZONE files and installed it into the libical
timezone data directory before testing. (You need to use '--pure' when
creating the VTIMEZONE files as well.)
Testing the Parsing Code
------------------------
Run 'make test-parse'.
This runs 'vzic --dump' and 'perl-dump' and compares the output. The diff
commands should not produce any output.
'vzic --dump' dumps all the parsed data out in the original Olson format,
but without comments. The files are written into the ZonesVzic and RulesVzic
subdirectories of the zoneinfo directory.
'make perl-dump' runs the vzic-dump.pl perl script which outputs the files
in the same format as 'vzic --dump' in the ZonesPerl and RulesPerl
subdirectories. The perl script doesn't actually parse the fields; it only
strips comments and massages the fields so we have the same output format.
Currently they both produce exactly the same output so we know the parsing
code is OK.
Testing the VTIMEZONE Files
---------------------------
Run 'make test-changes'.
This runs 'vzic --dump-changes' and 'test-vzic --dump-changes' and compares
the output. The diff command should not produce any output.
Both commands output timezone changes for each zone up to a specific year
(2030) into files for each timezone. It outputs the timezone changes in a
list in this format:
Timezone Name Date and Time of Change in UTC New Offset from UTC
America/Dawson 26 Oct 1986 2:00:00 -0800
Unfortunately there are some differences here, but they all happen before
1970 so it doesn't matter too much. It looks like the libical code has
problems determining things like 'last Sunday of the month' before 1970.
This is because it uses mktime() etc. which can't really handle dates
before 1970.
Damon Chaplin <damon@gnome.org>, 25 Oct 2003.
|