ICU-65 Move time zone data to icudata

X-SVN-Rev: 261
This commit is contained in:
Alan Liu 1999-11-30 23:05:49 +00:00
parent 95fdf250fd
commit f7f02c918a
10 changed files with 2359 additions and 1 deletions

View file

@ -50,6 +50,9 @@ Package=<4>
Begin Project Dependency
Project_Dep_Name toolutil
End Project Dependency
Begin Project Dependency
Project_Dep_Name gentz
End Project Dependency
}}}
###############################################################################
@ -225,6 +228,18 @@ Package=<4>
###############################################################################
Project: "gentz"=..\tools\gentz\gentz.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Project: "i18n"=..\i18n\i18n.dsp - Package Owner=<4>
Package=<5>

View file

@ -0,0 +1,245 @@
######################################################################
# Copyright (C) 1999, International Business Machines
# Corporation and others. All Rights Reserved.
######################################################################
# See: ftp://elsie.nci.nih.gov/pub/tzdata<year>
# where <year> is "1999b" or a similar string.
######################################################################
# This package handles the parsing of time zone files.
# Author: Alan Liu
######################################################################
# Usage:
# Call ParseFile for each file to be imported. Then call Postprocess
# to remove unused rules and links.
package TZ;
use strict;
use Carp;
use vars qw(@ISA @EXPORT $VERSION $YEAR $STANDARD);
require 'dumpvar.pl';
@ISA = qw(Exporter);
@EXPORT = qw(ParseFile
Postprocess
);
$VERSION = '0.1';
$STANDARD = '-'; # Name of the Standard Time rule
######################################################################
# Param: File name
# Param: Ref to hash of zones
# Param: Ref to hash of rules
# Param: Current year
sub ParseFile {
my ($FILE, $ZONES, $RULES, $YEAR) = @_;
local(*FILE);
open(FILE,"<$FILE") or confess "Can't open $FILE: $!";
my $zone; # Current zone
my $badLineCount = 0;
while (<FILE>) {
s/\#.*//;
next if (!/\S/);
#|# Zone NAME GMTOFF RULES FORMAT [UNTIL]
#|Zone America/Montreal -4:54:16 - LMT 1884
#| -5:00 Mont E%sT
#|Zone America/Thunder_Bay -5:57:00 - LMT 1895
#| -5:00 Canada E%sT 1970
#| -5:00 Mont E%sT 1973
#| -5:00 - EST 1974
#| -5:00 Canada E%sT
my ($zoneGmtoff, $zoneRule, $zoneFormat, $zoneUntil);
if (/^zone/i) {
# Zone block start
if (/^zone\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/i
|| /^zone\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)()/i) {
$zone = $1;
($zoneGmtoff, $zoneRule, $zoneFormat, $zoneUntil) =
($2, $3, $4, $5);
} else {
print STDERR "Can't parse in $FILE: $_";
++$badLineCount;
}
} elsif (/^\s/ && $zone) {
# Zone continuation
if (/^\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/
|| /^\s+(\S+)\s+(\S+)\s+(\S+)()/) {
($zoneGmtoff, $zoneRule, $zoneFormat, $zoneUntil) =
($1, $2, $3, $4);
} else {
print STDERR "Can't parse in $FILE: $_";
++$badLineCount;
}
} elsif (/^rule/i) {
# Here is where we parse a single line of the rule table.
# Our goal is to accept only rules applying to the current
# year. This is normally a matter of accepting rules
# that match the current year. However, in some cases this
# is more complicated. For example:
#|# Tonga
#|# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
#|Rule Tonga 1999 max - Oct Sat>=1 2:00s 1:00 S
#|Rule Tonga 2000 max - Apr Sun>=16 2:00s 0 -
# To handle this properly, we save every rule we encounter
# (thus overwriting older ones with newer ones, since rules
# are listed in order), and also use slot [2] to mark when
# we see a current year rule. When that happens, we stop
# saving rules. Thus we match the latest rule we see, or
# a matching rule if we find one. The format of slot [2]
# is just a 2 bit flag ([2]&1 means slot [0] matched,
# [2]&2 means slot [1] matched).
# Note that later, when the rules are post processed
# (see Postprocess), the slot [2] will be overwritten
# with the compressed rule string used to implement
# equality testing.
$zone = undef;
# Rule
#|# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
#|Rule US 1918 1919 - Mar lastSun 2:00 1:00 W # War
#|Rule US 1918 1919 - Oct lastSun 2:00 0 S
#|Rule US 1942 only - Feb 9 2:00 1:00 W # War
#|Rule US 1945 only - Sep 30 2:00 0 S
#|Rule US 1967 max - Oct lastSun 2:00 0 S
#|Rule US 1967 1973 - Apr lastSun 2:00 1:00 D
#|Rule US 1974 only - Jan 6 2:00 1:00 D
#|Rule US 1975 only - Feb 23 2:00 1:00 D
#|Rule US 1976 1986 - Apr lastSun 2:00 1:00 D
#|Rule US 1987 max - Apr Sun>=1 2:00 1:00 D
if (/^rule\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+
(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/xi) {
my ($name, $from, $to, $type, $in, $on, $at, $save, $letter) =
($1, $2, $3, $4, $5, $6, $7, $8, $9);
my $i = $save ? 0:1;
if (!exists $RULES->{$name}) {
$RULES->{$name} = [];
}
my $ruleArray = $RULES->{$name};
# Check our bit mask to see if we've already matched
# a current rule. If so, do nothing. If not, then
# save this rule line as the best one so far.
if (@{$ruleArray} < 3 ||
!($ruleArray->[2] & $i)) {
my $h = $ruleArray->[$i];
$ruleArray->[$i]->{from} = $from;
$ruleArray->[$i]->{to} = $to;
$ruleArray->[$i]->{type} = $type;
$ruleArray->[$i]->{in} = $in;
$ruleArray->[$i]->{on} = $on;
$ruleArray->[$i]->{at} = $at;
$ruleArray->[$i]->{save} = $save;
$ruleArray->[$i]->{letter} = $letter;
# Does this rule match the current year? If so,
# set the bit mask so we don't overwrite this rule.
# This makes us ingore rules for subsequent years
# that are already listed in the database -- as long
# as we have an overriding rule for the current year.
if (($from == $YEAR && $to =~ /only/i) ||
($from <= $YEAR &&
(($to =~ /^\d/ && $YEAR <= $to) || $to =~ /max/i))) {
$ruleArray->[2] |= $i;
}
}
} else {
print STDERR "Can't parse in $FILE: $_";
++$badLineCount;
}
} elsif (/^link/i) {
#|# Old names, for S5 users
#|
#|# Link LINK-FROM LINK-TO
#|Link America/New_York EST5EDT
#|Link America/Chicago CST6CDT
#|Link America/Denver MST7MDT
#|Link America/Los_Angeles PST8PDT
#|Link America/Indianapolis EST
#|Link America/Phoenix MST
#|Link Pacific/Honolulu HST
if (/^link\s+(\S+)\s+(\S+)/i) {
# We currently only record a single link -- if there
# are more than one, we should modify this.
my ($from, $to) = ($1, $2);
$ZONES->{$from}->{link} = $to;
} else {
print STDERR "Can't parse in $FILE: $_";
++$badLineCount;
}
} else {
# Unexpected line
print STDERR "Ignoring in $FILE: $_";
++$badLineCount;
}
if ($zoneRule &&
($zoneUntil !~ /\S/ || ($zoneUntil =~ /^\d/ &&
$zoneUntil >= $YEAR))) {
$ZONES->{$zone}->{gmtoff} = $zoneGmtoff;
$ZONES->{$zone}->{rule} = $zoneRule;
$ZONES->{$zone}->{format} = $zoneFormat;
$ZONES->{$zone}->{until} = $zoneUntil;
}
}
close(FILE);
}
######################################################################
# Param: Ref to hash of zones
# Param: Ref to hash of rules
sub Postprocess {
my ($ZONES, $RULES) = @_;
my %ruleInUse;
# Eliminate zone links that have no corresponding zone
foreach (keys %$ZONES) {
if (exists $ZONES->{$_}->{link} && !exists $ZONES->{$_}->{rule}) {
if (0) {
print STDERR
"Deleting link from historical/nonexistent zone: ",
$_, " -> ", $ZONES->{$_}->{link}, "\n";
}
delete $ZONES->{$_};
}
}
# Check that each zone has a corresponding rule
foreach (sort keys %$ZONES) {
my $ruleName = $ZONES->{$_}->{rule};
next if ($ruleName eq $STANDARD);
if (exists $RULES->{$ruleName}) {
$ruleInUse{$ruleName} = 1;
} else {
# This means the zone is using the standard rule now
$ZONES->{$_}->{rule} = $STANDARD;
}
}
# Check that both parts are there for rules
# Check for unused rules
# Make coded string for comparisons
foreach (keys %$RULES) {
if (!exists $ruleInUse{$_}) {
if (0) {
print STDERR "Deleting historical/unused rule: $_\n";
}
delete $RULES->{$_};
} elsif (!$RULES->{$_}->[0] || !$RULES->{$_}->[1]) {
print STDERR "Rule doesn't have both parts: $_\n";
} else {
# Generate code
# This has all the data about a rule; it can be used
# to see if two rules behave identically
$RULES->{$_}->[2] =
lc($RULES->{$_}->[0]->{in} . "," .
$RULES->{$_}->[0]->{on} . "," .
$RULES->{$_}->[0]->{at} . "," .
$RULES->{$_}->[0]->{save} . ";" .
$RULES->{$_}->[1]->{in} . "," .
$RULES->{$_}->[1]->{on} . "," .
$RULES->{$_}->[1]->{at}); # [1]->{save} is always zero
}
}
}

View file

@ -0,0 +1,197 @@
######################################################################
# Copyright (C) 1999, International Business Machines
# Corporation and others. All Rights Reserved.
######################################################################
# See: ftp://elsie.nci.nih.gov/pub/tzdata<year>
# where <year> is "1999b" or a similar string.
######################################################################
# This package contains utility functions for time zone data.
# Author: Alan Liu
######################################################################
# Zones - A time zone object is a hash with the following keys:
# {gmtoff} The offset from GMT, e.g. "-5:00"
# {rule} The name of the rule, e.g. "-", "Canada", "EU", "US"
# {format} The local abbreviation, e.g. "E%sT"
# {until} Data is good until this year, e.g., "2000". Often blank.
# These correspond to file entries:
#|# Zone NAME GMTOFF RULES FORMAT [UNTIL]
#|Zone America/Montreal -4:54:16 - LMT 1884
#| -5:00 Mont E%sT
# Optionally, a zone may also have the key:
# {link} An old name for this zone, e.g. "HST" (for Pacific/Honolulu)
# Links come from the file entries:
#|# Link LINK-FROM LINK-TO
#|Link America/New_York EST5EDT
#|Link America/Chicago CST6CDT
# The name of the zone itself is not kept in the zone object.
# Instead, zones are kept in a big hash. The keys are the names; the
# values are references to the zone objects. The big hash of all
# zones is referred to in all caps: %ZONES ($ZONES if it's a
# reference).
# Example: $ZONES->{"America/Los_Angeles"} =
# 'format' => 'P%sT'
# 'gmtoff' => '-8:00'
# 'link' => 'US/Pacific-New'
# 'rule' => 'US'
# 'until' => ''
######################################################################
# Rules - A time zone rule is an array with the following elements:
# [0] Onset rule
# [1] Cease rule
# [2] Encoded string
# The onset rule and cease rule have the same format. They are each
# references to a hash with keys:
# {from} Start year
# {to} End year, or "only" or "max"
# {type} Unknown, usually "-"
# {in} Month, 3 letters
# {on} Day specifier, e.g. "lastSun", "Sun>=1", "23"
# {at} Time, e.g. "2:00", "1:00u"
# {save} Amount of savings, for the onset; 0 for the cease
# {letter} Guess: the letter that goes into %s in the zone {format}
# These correspond to the file entries thus:
#|# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
#|Rule US 1942 only - Feb 9 2:00 1:00 W # War
#|Rule US 1945 only - Sep 30 2:00 0 S
#|Rule US 1967 max - Oct lastSun 2:00 0 S
#|Rule US 1967 1973 - Apr lastSun 2:00 1:00 D
#|Rule US 1974 only - Jan 6 2:00 1:00 D
#|Rule US 1975 only - Feb 23 2:00 1:00 D
#|Rule US 1976 1986 - Apr lastSun 2:00 1:00 D
#|Rule US 1987 max - Apr Sun>=1 2:00 1:00 D
# Entry [2], the encoded string, is used to see if two rules are the
# same. It consists of "[0]->{in},[0]->{on},[0]->{at},[0]->{save};
# [1]->{in},[1]->{on},[1]->{at}". Note that the separator between
# values is a comma, between onset and cease is a semicolon. Also
# note that the cease {save} is not used as this is always 0. The
# whole string is forced to lowercase.
# Rules don't contain their own name. Like zones, rules are kept in a
# big hash; the keys are the names, the values the references to the
# arrays. This hash of all rules is referred to in all caps, %RULES
# or for a reference, $RULES.
# Example: $RULES->{"US"} =
# 0 HASH(0x8fa03c)
# 'at' => '2:00'
# 'from' => 1987
# 'in' => 'Apr'
# 'letter' => 'D'
# 'on' => 'Sun>=1'
# 'save' => '1:00'
# 'to' => 'max'
# 'type' => '-'
# 1 HASH(0x8f9fc4)
# 'at' => '2:00'
# 'from' => 1967
# 'in' => 'Oct'
# 'letter' => 'S'
# 'on' => 'lastSun'
# 'save' => 0
# 'to' => 'max'
# 'type' => '-'
# 2 'apr,sun>=1,2:00,1:00;oct,lastsun,2:00'
package TZ;
use strict;
use Carp;
use vars qw(@ISA @EXPORT $VERSION $STANDARD);
require 'dumpvar.pl';
@ISA = qw(Exporter);
@EXPORT = qw(ZoneEquals
RuleEquals
FormZoneEquivalencyGroups
);
$VERSION = '0.1';
$STANDARD = '-'; # Name of the Standard Time rule
######################################################################
# Param: zone object (hash ref)
# Param: zone object (hash ref)
# Param: ref to hash of all rules
# Return: true if two zones are equivalent
sub ZoneEquals {
my $z1 = shift;
my $z2 = shift;
my $RULES = shift;
($z1, $z2) = ($z1->{rule}, $z2->{rule});
return ($z1 eq $z2) ||
RuleEquals($RULES->{$z1}, $RULES->{$z2});
}
######################################################################
# Param: rule object (hash ref)
# Param: rule object (hash ref)
# Return: true if two rules are equivalent
sub RuleEquals {
my $r1 = shift;
my $r2 = shift;
# Just compare the precomputed encoding strings.
# defined() catches undefined rules. The only undefined
# rule is $STANDARD; any others would be cause by
# Postprocess().
return defined($r1) && defined($r2) && $r1->[2] eq $r2->[2];
# There's actually one more level of equivalency analysis we could
# do. This is to recognize that Sun >=1 is the same as First Sun.
# We don't do this yet.
}
######################################################################
# Given a hash of all zones and a hash of all rules, create a list
# of equivalency groups. These are groups of zones with the same
# offset and equivalent rules. Equivalency is tested with
# ZoneEquals and RuleEquals. The resultant equivalency list is an
# array of refs to groups. Each group is an array of one or more
# zone names.
# Param: IN ref to hash of all zones
# Param: IN ref to hash of all rules
# Param: OUT ref to array to receive group refs
sub FormZoneEquivalencyGroups {
my ($ZONES, $RULES, $EQUIV) = @_;
# Group the zones by offset. This improves efficiency greatly;
# instead of an n^2 computation, we just need to do n^2 within
# each offset; a much smaller total number.
my %ZONES_BY_OFFSET;
foreach (keys %$ZONES) {
push @{$ZONES_BY_OFFSET{$ZONES->{$_}->{gmtoff}}}, $_;
}
# Find equivalent rules
foreach my $gmtoff (keys %ZONES_BY_OFFSET) {
# Make an array of equivalency groups
# (array of refs to array of names)
my @equiv;
foreach my $name1 (@{$ZONES_BY_OFFSET{$gmtoff}}) {
my $found = 0;
foreach my $group (@equiv) {
my $name2 = $group->[0];
if (ZoneEquals($ZONES->{$name1}, $ZONES->{$name2}, $RULES)) {
push @$group, $name1;
$found = 1;
last;
}
}
if (!$found) {
my @newGroup = ( $name1 );
push @equiv, \@newGroup;
}
}
push @$EQUIV, @equiv;
}
}

View file

@ -0,0 +1,468 @@
/*
**********************************************************************
* Copyright (C) 1999, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Date Name Description
* 11/24/99 aliu Creation.
**********************************************************************
*/
/* This program reads a text file full of parsed time zone data and
* outputs a binary file, tz.dat, which then goes on to become part of
* the memory-mapped (or dll) ICU data file.
*
* The data file read by this program is generated by a perl script,
* tz.pl. The input to tz.pl is standard unix time zone data from
* ftp://elsie.nci.nih.gov.
*
* As a matter of policy, the perl script tz.pl wants to do as much of
* the parsing, data processing, and error checking as possible, and
* this program wants to just do the binary translation step.
*
* See tz.pl for the file format that is READ by this program.
*/
#include <stdio.h>
#include <stdlib.h>
#include "utypes.h"
#include "cmemory.h"
#include "cstring.h"
#include "filestrm.h"
#include "udata.h"
#include "unewdata.h"
#include "tzdat.h"
#define INPUT_FILE "tz.txt"
#define OUTPUT_FILE "tz.dat"
#define DATA_NAME "tz"
#define DATA_TYPE "dat"
#define DATA_COPYRIGHT \
"Copyright (C) 1999, International Business Machines " \
"Corporation and others. All Rights Reserved."
/* UDataInfo cf. udata.h */
static const UDataInfo dataInfo = {
sizeof(UDataInfo),
0,
U_IS_BIG_ENDIAN,
U_CHARSET_FAMILY,
sizeof(UChar),
0,
'z', 'o', 'n', 'e', /* dataFormat */
1, 0, 0, 0, /* formatVersion */
1, 9, 9, 9 /* dataVersion */
};
class gentz {
// These must match SimpleTimeZone!!!
enum { WALL_TIME = 0,
STANDARD_TIME,
UTC_TIME
};
// The largest number of zones we accept as sensible. Anything
// larger is considered an error. Adjust as needed.
enum { MAX_ZONES = 1000 };
// The maximum sensible GMT offset, in seconds
static const int32_t MAX_GMT_OFFSET;
static const char COMMENT;
static const char CR;
static const char LF;
static const char MINUS;
static const char SPACE;
static const char TAB;
static const char ZERO;
static const char SEP;
static const char NUL;
static const char* END_KEYWORD;
enum { BUFLEN = 1024 };
char buffer[BUFLEN];
TZHeader header;
StandardZone* stdZones;
DSTZone* dstZones;
char* nameTable;
int32_t zoneCount; // Total number of zones
int32_t stdZoneSize;
int32_t dstZoneSize;
int32_t nameTableSize; // Total bytes in name table
bool_t useCopyright;
public:
int main(int argc, char *argv[]);
private:
int32_t writeTzDatFile(FileStream* out);
void parseTzTextFile(FileStream* in);
// High level parsing
void parseHeader(FileStream* in);
StandardZone* parseStandardZones(FileStream* in);
void parse1StandardZone(FileStream* in, StandardZone& zone);
DSTZone* parseDSTZones(FileStream* in);
void parse1DSTZone(FileStream* in, DSTZone& zone);
void parseDSTRule(char*& p, TZRule& rule);
char* parseNameTable(FileStream* in);
// Low level parsing and reading
int32_t readIntegerLine(FileStream* in, int32_t min, int32_t max);
int32_t _parseInteger(char*& p);
int32_t parseInteger(char*& p, char nextExpectedChar, int32_t, int32_t);
int32_t readLine(FileStream* in);
// Error handling
void die(const char* msg);
void usage(const char* argv0);
};
int main(int argc, char *argv[]) {
gentz x;
return x.main(argc, argv);
}
const int32_t gentz::MAX_GMT_OFFSET = (int32_t)24*60*60;
const char gentz::COMMENT = '#';
const char gentz::CR = ((char)13);
const char gentz::LF = ((char)10);
const char gentz::MINUS = '-';
const char gentz::SPACE = ' ';
const char gentz::TAB = ((char)9);
const char gentz::ZERO = '0';
const char gentz::SEP = ',';
const char gentz::NUL = ((char)0);
const char* gentz::END_KEYWORD = "end";
void gentz::usage(const char* argv0) {
fprintf(stderr,
"Usage: %s [-c[+|-]] infile outfile\n"
" -c[+|-] [do|do not] include copyright (default=+)\n"
" infile text file produced by tz.pl\n"
" outfile binary file suitable for memory mapping\n",
argv0);
exit(1);
}
int gentz::main(int argc, char *argv[]) {
// Parse arguments
useCopyright = TRUE;
const char* infile = 0;
const char* outfile = 0;
for (int i=1; i<argc; ++i) {
const char* arg = argv[i];
if (arg[0] == '-') {
if (arg[1] != 'c') {
usage(argv[0]);
}
switch (arg[2]) {
case '+':
useCopyright = TRUE;
break;
case '-':
useCopyright = FALSE;
break;
default:
usage(argv[0]);
}
} else if (infile == 0) {
infile = arg;
} else if (outfile == 0) {
outfile = arg;
} else {
usage(argv[0]);
}
}
if (outfile == 0) {
usage(argv[0]);
}
*buffer = NUL;
FileStream* in = T_FileStream_open(infile, "r");
if (in == 0) {
die("Cannot open input file");
}
parseTzTextFile(in);
T_FileStream_close(in);
*buffer = NUL;
fprintf(stdout, "Input file %s, data version %u(%u)\n",
infile, header.versionYear, header.versionSuffix);
fprintf(stdout, "Read %ld standard zones, %ld dst zones, %ld zone names\n",
header.standardCount, header.dstCount, zoneCount);
FileStream* out = T_FileStream_open(outfile, "w");
if (out == 0) {
die("Cannot open output file");
}
int32_t wlen = writeTzDatFile(out);
T_FileStream_close(out);
fprintf(stdout, "Wrote to %s: %ld bytes\n",
outfile, wlen);
// REMOVE THIS NOTICE when it no longer applies:
fprintf(stdout, "NOTE: Currently, gentz writes the output file to"
" the data directory and creates an EMPTY file of the"
" same name in the target directory. Ignore the empty file.");
return 0; // success
}
int32_t gentz::writeTzDatFile(FileStream* out) {
UNewDataMemory *pdata;
UErrorCode status = U_ZERO_ERROR;
pdata = udata_create(DATA_TYPE, DATA_NAME, &dataInfo,
useCopyright ? DATA_COPYRIGHT : 0, &status);
if (U_FAILURE(status)) {
die("Unable to create data memory");
}
udata_writeBlock(pdata, &header, sizeof(header));
udata_writeBlock(pdata, stdZones, stdZoneSize);
udata_writeBlock(pdata, dstZones, dstZoneSize);
udata_writeBlock(pdata, nameTable, nameTableSize);
uint32_t dataLength = udata_finish(pdata, &status);
if (U_FAILURE(status)) {
die("Error writing output file");
}
if (dataLength != (sizeof(header) + stdZoneSize +
dstZoneSize + nameTableSize)) {
die("Written file doesn't match expected size");
}
return dataLength;
}
void gentz::parseTzTextFile(FileStream* in) {
parseHeader(in);
stdZones = parseStandardZones(in);
dstZones = parseDSTZones(in);
if (zoneCount != (int32_t)(header.standardCount + header.dstCount)) {
die("Zone counts don't add up");
}
nameTable = parseNameTable(in);
// Fixup the header offsets
stdZoneSize = (char*)&stdZones[header.standardCount] - (char*)&stdZones[0];
dstZoneSize = (char*)&dstZones[header.dstCount] - (char*)&dstZones[0];
header.standardOffset = sizeof(header);
header.dstOffset = header.standardOffset + stdZoneSize;
header.nameTableOffset = header.dstOffset + dstZoneSize;
if (header.standardOffset < 0 ||
header.dstOffset < 0 ||
header.nameTableOffset < 0) {
die("Negative offset in header after fixup");
}
}
void gentz::parseHeader(FileStream* in) {
// Version string, e.g., "1999j" -> (1999<<16) | 10
header.versionYear = (uint16_t) readIntegerLine(in, 0, 0xFFFF);
header.versionSuffix = (uint16_t) readIntegerLine(in, 0, 0xFFFF);
// Zone count
zoneCount = readIntegerLine(in, 0, MAX_ZONES);
// Size of name table in bytes
// (0x00FFFFFF is an arbitrary upper limit; adjust as needed.)
nameTableSize = readIntegerLine(in, 1, 0x00FFFFFF);
}
StandardZone* gentz::parseStandardZones(FileStream* in) {
header.standardCount = readIntegerLine(in, 1, MAX_ZONES);
StandardZone* zones = new StandardZone[header.standardCount];
if (zones == 0) {
die("Out of memory");
}
for (uint32_t i=0; i<header.standardCount; i++) {
parse1StandardZone(in, zones[i]);
}
readLine(in);
if (icu_strcmp(buffer, END_KEYWORD) != 0) {
die("Keyword 'end' missing");
}
return zones;
}
void gentz::parse1StandardZone(FileStream* in, StandardZone& zone) {
readLine(in);
char* p = buffer;
zone.nameOffset = parseInteger(p, SEP, 0, nameTableSize);
zone.gmtOffset = parseInteger(p, NUL, -MAX_GMT_OFFSET, MAX_GMT_OFFSET);
}
DSTZone* gentz::parseDSTZones(FileStream* in) {
header.dstCount = readIntegerLine(in, 1, MAX_ZONES);
DSTZone* zones = new DSTZone[header.dstCount];
if (zones == 0) {
die("Out of memory");
}
for (uint32_t i=0; i<header.dstCount; i++) {
parse1DSTZone(in, zones[i]);
}
readLine(in);
if (icu_strcmp(buffer, END_KEYWORD) != 0) {
die("Keyword 'end' missing");
}
return zones;
}
void gentz::parse1DSTZone(FileStream* in, DSTZone& zone) {
readLine(in);
char* p = buffer;
zone.nameOffset = parseInteger(p, SEP, 0, nameTableSize);
zone.gmtOffset = parseInteger(p, SEP, -MAX_GMT_OFFSET, MAX_GMT_OFFSET);
parseDSTRule(p, zone.onsetRule);
parseDSTRule(p, zone.ceaseRule);
zone.dstSavings = (uint16_t) parseInteger(p, NUL, 0, 12*60);
}
void gentz::parseDSTRule(char*& p, TZRule& rule) {
rule.month = (uint8_t) parseInteger(p, SEP, 0, 11);
rule.dowim = (int8_t) parseInteger(p, SEP, -31, 31);
rule.dow = (int8_t) parseInteger(p, SEP, -7, 7);
rule.time = (uint16_t) parseInteger(p, SEP, 0, 24*60);
rule.mode = *p++;
if (*p++ != SEP) {
die("Separator missing");
}
switch (rule.mode) {
case 'w':
rule.mode = WALL_TIME;
break;
case 's':
rule.mode = STANDARD_TIME;
break;
case 'u':
rule.mode = UTC_TIME;
break;
default:
die("Invalid rule time mode");
break;
}
}
char* gentz::parseNameTable(FileStream* in) {
int32_t n = readIntegerLine(in, 1, MAX_ZONES);
if (n != zoneCount) {
die("Zone count doesn't match name table count");
}
char* names = new char[nameTableSize];
if (names == 0) {
die("Out of memory");
}
char* p = names;
char* limit = names + nameTableSize;
for (int32_t i=0; i<n; ++i) {
int32_t len = readLine(in);
if ((p + len) <= limit) {
icu_memcpy(p, buffer, len);
p += len;
*p++ = NUL;
} else {
die("Name table longer than declared size");
}
}
if (p != limit) {
die("Name table shorter than declared size");
}
return names;
}
/**
* Read a line from the FileStream and parse it as an
* integer. There should be nothing else on the line.
*/
int32_t gentz::readIntegerLine(FileStream* in, int32_t min, int32_t max) {
readLine(in);
char* p = buffer;
return parseInteger(p, NUL, min, max);
}
/**
* Parse an integer from the given character buffer.
* Advance p past the last parsed character. Return
* the result. The integer must be of the form
* /-?\d+/.
*/
int32_t gentz::_parseInteger(char*& p) {
int32_t n = 0;
int32_t digitCount = 0;
int32_t digit;
bool_t negative = FALSE;
if (*p == MINUS) {
++p;
negative = TRUE;
}
for (;;) {
digit = *p - ZERO;
if (digit < 0 || digit > 9) {
break;
}
n = 10*n + digit;
p++;
digitCount++;
}
if (digitCount < 1) {
die("Unable to parse integer");
}
if (negative) {
n = -n;
}
return n;
}
int32_t gentz::parseInteger(char*& p, char nextExpectedChar,
int32_t min, int32_t max) {
int32_t n = _parseInteger(p);
if (*p++ != nextExpectedChar) {
die("Character following integer unexpected");
}
if (n < min || n > max) {
die("Integer field out of range");
}
return n;
}
void gentz::die(const char* msg) {
fprintf(stderr, "ERROR, %s\n", msg);
if (*buffer) {
fprintf(stderr, "Current input line: %s\n", buffer);
}
exit(1);
}
int32_t gentz::readLine(FileStream* in) {
T_FileStream_readLine(in, buffer, BUFLEN);
// Trim off trailing comment
char* p = icu_strchr(buffer, COMMENT);
if (p != 0) {
// Back up past any space or tab characters before
// the comment character.
while (p > buffer && (p[-1] == SPACE || p[-1] == TAB)) {
p--;
}
*p = NUL;
}
// Delete any trailing ^J and/or ^M characters
p = buffer + icu_strlen(buffer);
while (p > buffer && (p[-1] == CR || p[-1] == LF)) {
p--;
}
*p = NUL;
return icu_strlen(buffer);
}

View file

@ -0,0 +1,102 @@
# Microsoft Developer Studio Project File - Name="gentz" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=gentz - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "gentz.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "gentz.mak" CFG="gentz - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "gentz - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "gentz - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "gentz - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /MD /Za /W3 /GX /O2 /I "..\..\common" /I "..\toolutil" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 toolutil.lib icuuc.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /libpath:"..\toolutil\Release" /libpath:"..\..\..\lib\Release"
!ELSEIF "$(CFG)" == "gentz - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /Za /W3 /Gm /GX /ZI /Od /I "..\..\common" /I "..\toolutil" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 toolutil.lib icuuc.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"..\toolutil\Debug" /libpath:"..\..\..\lib\Debug"
!ENDIF
# Begin Target
# Name "gentz - Win32 Release"
# Name "gentz - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\gentz.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View file

@ -0,0 +1,37 @@
Readme file for ICU time zone data (source/tools/gentz)
The time zone data in ICU is taken from the UNIX data files at
ftp://elsie.nci.nih.gov/pub/tzdata<year>.
Two tools are used to process the data into a format suitable for ICU:
tz.pl directory of raw data files -> tz.txt
gentz tz.txt -> tz.dat (memory mappable binary file)
After gentz is run, standard ICU data tools are used to incorporate
tz.dat into the icudata module.
In order to incorporate the raw data from that source into ICU, take
the following steps.
1. Download the archive of current zone data. This should be a file
named something like tzdata1999j.tar.gz. Use the URL listed above.
2. Unpack the archive into a directory, retaining the name of the
archive. For example, unpack tzdata1999j.tar.gz into tzdata1999j/.
Place this directory anywhere; one option is to place it within
source/tools/gentz.
3. Run the perl script tz.pl, passing it the directory location as a
command-line argument. On Windows system use the batch file
tz.bat. The output of this step is the intermediate text file
source/tools/gentz/tz.txt.
4. Run source/tools/makedata on Windows. On UNIX systems the
equivalent build steps are performed by 'make' and 'make install'.
The tz.txt file is typically checked into CVS, whereas the raw data
files are not, since they are readily available from the URL listed
above.
Alan Liu 1999

17
icu4c/source/tools/gentz/tz.bat Executable file
View file

@ -0,0 +1,17 @@
@echo off
REM Copyright (C) 1999, International Business Machines
REM Corporation and others. All Rights Reserved.
REM This script is a Windows launcher for the tz.pl script. For this
REM to work, the perl executable must be on the path. We recommend
REM the ActiveState build; see http://www.activestate.com. See the
REM tz.pl script itself for more documentation.
if "%OS%" == "Windows_NT" goto WinNT
perl -w -x -S "tz.pl" %1 %2 %3 %4 %5 %6 %7 %8 %9
goto end
:WinNT
perl -w -x -S "tz.pl" %*
if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto end
if %errorlevel% == 9009 echo You do not have Perl in your PATH.
:end

484
icu4c/source/tools/gentz/tz.pl Executable file
View file

@ -0,0 +1,484 @@
#!/usr/bin/perl
######################################################################
# Copyright (C) 1999, International Business Machines
# Corporation and others. All Rights Reserved.
######################################################################
# See: ftp://elsie.nci.nih.gov/pub/tzdata<year>
# where <year> is "1999b" or a similar string.
######################################################################
# This script takes time zone data in elsie.nci.nih.gov format and
# parses it into a form usable by ICU. The raw data contains more
# data than we need, since it contains historical zone data. We
# parse out the current zones and create a listing of current zones.
# Author: Alan Liu
######################################################################
# To update the zone data, download the latest data from the NIH URL
# listed above into a directory. Run this script with the directory
# name as an argument. THE DIRECTORY NAME MUST END IN tzdataYYYYR.
######################################################################
# OUTPUT FILE FORMAT (filename $OUT)
#
# As a matter of policy, this script wants to do as much of
# the parsing, data processing, and error checking as possible,
# leaving the C++ program that parses this file to just do the binary
# translation step.
#
# - The file is line based, with one record per line.
# - Lines may be followed by a comment; the parser must ignore
# anything of the form /\s+#.*$/ in each line.
# |3065,14400 # Asia/Dubai GMT+4:00
# - The file contains a header and 3 lists.
# - The header contains the version of the unix data, the total
# zone count, and the length of the name table in bytes.
# |1999 # (tzdata1999j) ftp://elsie.nci.nih.gov data version YEAR
# |10 # (tzdata1999j) ftp://elsie.nci.nih.gov data version SUFFIX
# |387 # total zone count
# |5906 # length of name table in bytes
# - Lists start with a count of the records to follow, the records
# themselves (one per line), and a single line with the keyword
# 'end'.
# - The first list is the list of standard zones:
# |208 # count of standard zones to follow
# |0,0 # Africa/Abidjan GMT+0:00
# |28,10800 # Africa/Addis_Ababa GMT+3:00
# ...
# |end
# Each standard zone record contains two integers. The first
# is a byte offset into the name table for the name of the zone.
# The second integer is the GMT offset in SECONDS for this zone.
# - The second list is the list of DST zones:
# |179 # count of dst zones to follow
# |15,0,8,1,0,0,w,11,31,0,0,w,20 # Africa/Accra GMT+0:00 Sep 1...
# |184,7200,3,-1,6,0,s,8,-1,5,1380,s,60 # Africa/Cairo GMT+2:0...
# ...
# |end
# Each record starts with the same two integers as a standard
# zone record. Following this are data for the onset rule and
# the cease rule. Each rule is described by the following integers:
# month (JAN = 0)
# dowim } These two values are in SimpleTimeZone encoded
# dow } format for DOM, DOWIM, DOW>=DOM, or DOW<=DOM.
# time MINUTES
# time mode ('w', 's', 'u')
# The last integer in the record is the DST savings in MINUTES,
# typically 60.
# - The third list is the name table:
# |387 # count of names to follow
# |Africa/Abidjan
# |Africa/Accra
# ...
# |end
# Each name is terminated by a newline (like all lines in the file).
# The offsets in the first two lists refer to this table.
######################################################################
# As of 1999j, here are the various possible values taken by the
# rule fields. See code below that generates this data.
#
# at: 0:00, 0:00s, 1:00, 1:00s, 1:00u, 23:00s, 2:00, 2:00s, 2:30, 2:45s,
# 3:00, 3:00s
# in: Apr, Dec, Feb, Jan, Jun, Mar, May, Nov, Oct, Sep
# letter: -, D, GHST, GMT, HS, S, SLST
# on: 1, 12, 15, 18, 2, 20, 21, 22, 23, 25, 28, 3, 30, 31, 4, 7, Fri>=1,
# Fri>=15, Sat>=1, Sat>=15, Sun<=14, Sun>=1, Sun>=10, Sun>=11, Sun>=15,
# Sun>=16, Sun>=23, S un>=8, Sun>=9, lastFri, lastSun, lastThu
# save: 0, 0:20, 0:30, 1:00
# type: -
require 5; # Minimum version of perl needed
use strict;
use Getopt::Long;
use vars qw(@FILES $YEAR $DATA_DIR $OUT $SEP @MONTH
$VERSION_YEAR $VERSION_SUFFIX $RAW_VERSION);
require 'dumpvar.pl';
use TZFileParser;
use TZUtility;
# We get the current year from the system here. Later
# we double check this against the zone data version.
$YEAR = 1900+@{[localtime]}[5]; # Get the current year
$DATA_DIR = shift;
if (!$DATA_DIR || ! -d $DATA_DIR) {
print STDERR "No data directory or invalid directory specified\n\n";
usage();
}
if ($DATA_DIR =~ /(tzdata(\d{4})(\w?))/) {
$RAW_VERSION = $1;
$VERSION_YEAR = $2;
$VERSION_SUFFIX = $3;
if ($YEAR != $VERSION_YEAR) {
print STDERR "WARNING: You appear to be building $VERSION_YEAR data. Don't you want to use current $YEAR data?\n";
usage(); # Add an override option for this check, if needed
}
$VERSION_SUFFIX =~ tr/a-z/A-Z/;
if ($VERSION_SUFFIX =~ /[A-Z]/) {
$VERSION_SUFFIX = ord($VERSION_SUFFIX) - ord('A') + 1;
} else {
if ($VERSION_SUFFIX) {
print STDERR "Warning: Ignoring version suffix '$VERSION_SUFFIX' for \"$DATA_DIR\"\n";
}
$VERSION_SUFFIX = 0;
}
print "Time zone version $RAW_VERSION = $VERSION_YEAR($VERSION_SUFFIX)\n";
} else {
print STDERR "The directory specified doesn't contain \"tzdataNNNNR\", so I can't tell what version the data is. Please rename the directory and try again.\n";
usage();
}
# Output file name
$OUT = 'tz.txt';
# Separator between fields in the output file
$SEP = ','; # Don't use ':'!
@FILES = qw(africa
antarctica
asia
australasia
backward
etcetera
europe
factory
northamerica
pacificnew
solar87
solar88
solar89
southamerica);
@MONTH = qw(jan feb mar apr may jun
jul aug sep oct nov dec);
main();
sub usage {
print STDERR "Usage: $0 data_dir\n\n";
print STDERR "data_dir contains the unpacked files from\n";
print STDERR "ftp://elsie.nci.nih.gov/pub/tzdataYYYYR,\n";
print STDERR "where YYYY is the year and R is the revision\n";
print STDERR "letter.\n";
print STDERR "\n";
print STDERR "Files that are expected to be present are:\n";
print STDERR join(", ", @FILES), "\n";
exit 1;
}
sub main {
my (%ZONES, %RULES, @EQUIV);
print "Reading";
foreach (@FILES) {
if (! -e "$DATA_DIR/$_") {
print STDERR "\nMissing file $DATA_DIR/$_\n\n";
usage();
}
print ".";
TZ::ParseFile("$DATA_DIR/$_", \%ZONES, \%RULES, $YEAR);
}
print "done\n";
TZ::Postprocess(\%ZONES, \%RULES);
print
"Read ", scalar keys %ZONES, " current zones and ",
scalar keys %RULES, " rules for $YEAR\n";
# Write out the zone data in a compact readable format.
# Create a name table from the zone names. The format of
# the name table is:
#
# The names are listed in lexical order, and each name
# is assigned an offset. The first name's offset is 0.
# The offset of name i+1 is the offset of name i + the
# length of name i + 1 (for the zero byte).
#
# Store the offsets in a hash %NAME_OFFSET. Store the
# names in a big scalar, $NAME_LIST, with "\n" between
# each name and after the last.
#
# Store the length of the entire name table in $NAME_SIZE.
#
# Also, count the number of standard and DST zones.
my $offset = 0;
my $NAME_LIST = '';
my %NAME_OFFSET;
my $STD_COUNT = 0; # Count of standard zones
my $DST_COUNT = 0; # Count of DST zones
foreach my $z (sort keys %ZONES) {
$NAME_OFFSET{$z} = $offset;
$offset += length($z) + 1;
$NAME_LIST .= "$z\n";
if ($ZONES{$z}->{rule} eq $TZ::STANDARD) {
$STD_COUNT++;
} else {
$DST_COUNT++;
}
}
my $NAME_SIZE = $offset;
open(OUT,">$OUT") or die "Can't open $OUT for writing: $!";
# Zone data version
print OUT $VERSION_YEAR, " # ($RAW_VERSION) ftp://elsie.nci.nih.gov data version YEAR\n";
print OUT $VERSION_SUFFIX, " # ($RAW_VERSION) ftp://elsie.nci.nih.gov data version SUFFIX\n";
print OUT scalar keys %ZONES, " # total zone count\n";
print OUT $NAME_SIZE, " # length of name table in bytes\n";
# Output first the standard zones, then the dst zones.
# Precede each list with the count of zones to follow,
# and follow it with the keyword 'end'.
for my $type (qw(standard dst)) {
print OUT ($type eq 'standard'
? $STD_COUNT : $DST_COUNT), " # count of $type zones to follow\n";
foreach my $z (sort keys %ZONES) {
my $isStd = ($ZONES{$z}->{rule} eq $TZ::STANDARD);
next if ($isStd ne ($type eq 'standard'));
print OUT $NAME_OFFSET{$z}, ",";
print OUT formatZone($z, $ZONES{$z}, \%RULES), "\n";
}
print OUT "end\n"; # 'end' keyword for error checking
}
# Output the name table, followed by 'end' keyword
print OUT scalar keys %ZONES, " # count of names to follow\n";
print OUT $NAME_LIST, "end\n";
close(OUT);
print "$OUT written.\n";
if (0) {
TZ::FormZoneEquivalencyGroups(\%ZONES, \%RULES, \@EQUIV);
print
"Equivalency groups (including unique zones): ",
scalar @EQUIV, "\n";
}
#::dumpValue($ZONES{"America/Los_Angeles"});
#::dumpValue($RULES{"US"});
#::dumpValue($RULES{"Tonga"});
# Find all the different values of rule fields:
# in, at, on, save, type, letter
if (0) {
my %RULEVALS;
foreach my $ruleName (keys %RULES) {
for (my $i=0; $i<2; ++$i) {
foreach my $key (qw(in on at save type letter)) {
if (@{$RULES{$ruleName}} < 2) {
print $ruleName, ":";
::dumpValue($RULES{$ruleName});
}
my $x = $RULES{$ruleName}->[$i]->{$key};
$RULEVALS{$key}->{$x} = 1;
}
}
}
foreach my $key (sort keys %RULEVALS) {
print "$key: ", join(", ", sort keys %{$RULEVALS{$key}}), "\n";
}
}
}
# Format a time zone as a machine-readable line of text. Another
# tool will read this line to construct a binary data structure
# representing this zone.
# Param: Zone name
# Param: Zone hash
# Param: Ref to hash of all rules
# Return: One line description of this zone.
sub formatZone { # ($z, $ZONES{$z}, \%RULES)
my $name = shift;
my $zone = shift;
my $rules = shift;
my @spec;
my @notes = ( $name );
# GMT offset
push @notes, ($zone->{gmtoff}=~/^-/?"GMT":"GMT+") . $zone->{gmtoff};
push @spec, parseOffset($zone->{gmtoff});
#|rawOffset The new SimpleTimeZone's raw GMT offset
#|ID The new SimpleTimeZone's time zone ID.
#|startMonth The daylight savings starting month. Month is
#| 0-based. eg, 0 for January.
#|startDay The daylight savings starting
#| day-of-week-in-month. See setStartRule() for a
#| complete explanation.
#|startDayOfWeek The daylight savings starting day-of-week. See
#| setStartRule() for a complete explanation.
#|startTime The daylight savings starting time, expressed as the
#| number of milliseconds after midnight.
#|endMonth The daylight savings ending month. Month is
#| 0-based. eg, 0 for January.
#|endDay The daylight savings ending day-of-week-in-month.
#| See setStartRule() for a complete explanation.
#|endDayOfWeek The daylight savings ending day-of-week. See
#| setStartRule() for a complete explanation.
#|endTime The daylight savings ending time, expressed as the
#| number of milliseconds after midnight.
my $rule = $zone->{rule};
if ($rule ne $TZ::STANDARD) {
$rule = $rules->{$rule};
# $rule is now an array ref, with [0] being the onset and
# [1] being the cease.
formatRule($rule->[0], \@spec, \@notes); # Onset
formatRule($rule->[1], \@spec, \@notes); # Cease
my @a = parseTime($rule->[0]->{save});
if ($a[1] ne 'w') {
die "Strange DST savings value: \"$rule->[0]->{save}\"";
}
push @notes, $rule->[0]->{save};
push @spec, $a[0];
}
join($SEP, @spec) . " # " . join(' ', @notes);
}
# Format a rule and return the string
# Param: reference to rule hash
# Param: ref to spec array (this is a result param)
# Param: ref to annotation array (this is a result param)
sub formatRule {
my $rule = shift;
my $spec = shift;
my $notes = shift;
push @$notes, $rule->{in}, $rule->{on}, $rule->{at};
push @$spec, parseMonth($rule->{in}); # Month
push @$spec, parseDaySpecifier($rule->{on}); # Day
push @$spec, parseTime($rule->{at}); # Time
}
# Parse an offset of the form d, d:dd, or d:dd:dd, or any of the above
# preceded by a '-'. Return the total number of seconds represented.
# Param: String
# Return: Integer number of seconds
sub parseOffset {
local $_ = shift;
if (/^(-)?(\d{1,2})(:(\d\d))?(:(\d\d))?$/) {
# 1 2 4 6
my $a = (($2 * 60) + (defined $4?$4:0)) * 60 + (defined $6?$6:0);
$a = -$a if (defined $1 && $1 eq '-');
return $a;
} else {
die "Cannot parse offset \"$_\"";
}
}
# Parse a time of the format dd:dds, where s is a suffix character.
# Return the time, in minutes, and the suffix, in an array.
# Only the suffixes 's' and 'u' are recognized.
# Param: String, with optional suffix
# Return: Array ( seconds, suffix ). If no suffix, 'w' is used.
sub parseTime {
local $_ = shift;
if (/^(\d{1,2}):(\d\d)([su])?$/) {
my $a = ($1*60) + $2;
my $s = defined $3?$3:'w';
return ( $a, $s );
} else {
die "Cannot parse time \"$_\"";
}
}
# Given a month string, return an integer from 0 (Jan) to 11 (Dec).
# Param: Str
# Return: Int 0..11.
sub parseMonth {
local $_ = shift;
for (my $i=0; $i<12; $i++) {
return $i if (/$MONTH[$i]/i);
}
die "Can't parse month \"$_\"";
}
# Given a specifier for the day of the month on which a rule triggers,
# return an array of two integers encoding that information. We use
# the ICU/java.util.SimpleTimeZone encoding scheme using two integers.
# We return the two integers in an array of ( dowim dow ).
# Param: String, such as
# 1, 12, 15, 18, 2, 20, 21, 22, 23, 25, 28, 3, 30, 31, 4, 7, Fri>=1,
# Fri>=15, Sat>=1, Sat>=15, Sun<=14, Sun>=1, Sun>=10, Sun>=11, Sun>=15,
# Sun>=16, Sun>=23, Sun>=8, Sun>=9, lastFri, lastSun, lastThu
# This is the {on} field of the rule hash.
# Return: Array of two integers, ( dowim dow ).
# The dow has Sunday = 1 .. Saturday = 7.
sub parseDaySpecifier {
local $_ = shift;
#|+If both dayOfWeekInMonth and dayOfWeek are positive, they specify the
#| day of week in the month (e.g., (2, WEDNESDAY) is the second Wednesday
#| of the month).
#|+If dayOfWeek is positive and dayOfWeekInMonth is negative, they specify
#| the day of week in the month counting backward from the end of the month.
#| (e.g., (-1, MONDAY) is the last Monday in the month)
#|+If dayOfWeek is zero and dayOfWeekInMonth is positive, dayOfWeekInMonth
#| specifies the day of the month, regardless of what day of the week it is.
#| (e.g., (10, 0) is the tenth day of the month)
#|+If dayOfWeek is zero and dayOfWeekInMonth is negative, dayOfWeekInMonth
#| specifies the day of the month counting backward from the end of the
#| month, regardless of what day of the week it is (e.g., (-2, 0) is the
#| next-to-last day of the month).
#|+If dayOfWeek is negative and dayOfWeekInMonth is positive, they specify the
#| first specified day of the week on or after the specfied day of the month.
#| (e.g., (15, -SUNDAY) is the first Sunday after the 15th of the month
#| [or the 15th itself if the 15th is a Sunday].)
#|+If dayOfWeek and dayOfWeekInMonth are both negative, they specify the
#| last specified day of the week on or before the specified day of the month.
#| (e.g., (-20, -TUESDAY) is the last Tuesday before the 20th of the month
#| [or the 20th itself if the 20th is a Tuesday].)
# dowim dow
# >0 >0 day of week in month
# <0 >0 day of week in month (from end)
# >0 0 day of month
# <0 0 day of month (from end; -1 is last dom)
# >0 <0 first dow on or after dom
# <0 <0 last dow on or before dom
my $dowim;
my $dow = 0;
# Check for straight DOM
if (/^\d+$/) {
$dowim = $_;
$dow = 0;
return ( $dowim, $dow );
}
# Anything else must have a dow embedded in it; parse it out
my @DOW = ( 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' );
for (my $i=0; $i<@DOW; $i++) {
if (s/$DOW[$i]//) {
$dow = $i + 1;
last;
}
}
if ($dow == 0) {
die "Cannot parse day specifier \"$_\"";
}
# Now we have either >=n, <=n, last, or first.
if (/^last$/) {
$dowim = -1;
} elsif (/^first$/) {
$dowim = 1;
} elsif (/^>=(\d+)$/) {
$dowim = $1;
$dow = -$dow;
} elsif (/^<=(\d+)$/) {
$dowim = -$1;
$dow = -$dow;
} else {
die "Cannot parse day specifier \"$_\"";
}
( $dowim, $dow );
}
__END__

View file

@ -0,0 +1,784 @@
1999 # (tzdata1999j) ftp://elsie.nci.nih.gov data version YEAR
10 # (tzdata1999j) ftp://elsie.nci.nih.gov data version SUFFIX
387 # total zone count
5906 # length of name table in bytes
208 # count of standard zones to follow
0,0 # Africa/Abidjan GMT+0:00
28,10800 # Africa/Addis_Ababa GMT+3:00
47,3600 # Africa/Algiers GMT+1:00
62,10800 # Africa/Asmera GMT+3:00
76,0 # Africa/Bamako GMT+0:00
90,3600 # Africa/Bangui GMT+1:00
104,0 # Africa/Banjul GMT+0:00
118,0 # Africa/Bissau GMT+0:00
132,7200 # Africa/Blantyre GMT+2:00
148,3600 # Africa/Brazzaville GMT+1:00
167,7200 # Africa/Bujumbura GMT+2:00
197,0 # Africa/Casablanca GMT+0:00
228,0 # Africa/Conakry GMT+0:00
243,0 # Africa/Dakar GMT+0:00
256,10800 # Africa/Dar_es_Salaam GMT+3:00
277,10800 # Africa/Djibouti GMT+3:00
293,3600 # Africa/Douala GMT+1:00
307,0 # Africa/El_Aaiun GMT+0:00
339,7200 # Africa/Gaborone GMT+2:00
355,7200 # Africa/Harare GMT+2:00
389,10800 # Africa/Kampala GMT+3:00
420,7200 # Africa/Kigali GMT+2:00
434,3600 # Africa/Kinshasa GMT+1:00
450,3600 # Africa/Lagos GMT+1:00
463,3600 # Africa/Libreville GMT+1:00
481,0 # Africa/Lome GMT+0:00
493,3600 # Africa/Luanda GMT+1:00
507,7200 # Africa/Lubumbashi GMT+2:00
525,7200 # Africa/Lusaka GMT+2:00
539,3600 # Africa/Malabo GMT+1:00
553,7200 # Africa/Maputo GMT+2:00
567,7200 # Africa/Maseru GMT+2:00
581,7200 # Africa/Mbabane GMT+2:00
596,10800 # Africa/Mogadishu GMT+3:00
613,0 # Africa/Monrovia GMT+0:00
629,10800 # Africa/Nairobi GMT+3:00
644,3600 # Africa/Ndjamena GMT+1:00
660,3600 # Africa/Niamey GMT+1:00
674,0 # Africa/Nouakchott GMT+0:00
692,0 # Africa/Ouagadougou GMT+0:00
711,3600 # Africa/Porto-Novo GMT+1:00
729,0 # Africa/Sao_Tome GMT+0:00
745,0 # Africa/Timbuktu GMT+0:00
761,7200 # Africa/Tripoli GMT+2:00
836,-14400 # America/Anguilla GMT-4:00
853,-14400 # America/Antigua GMT-4:00
887,-14400 # America/Aruba GMT-4:00
935,-10800 # America/Belem GMT-3:00
1069,-14400 # America/Caracas GMT-4:00
1085,-10800 # America/Catamarca GMT-3:00
1103,-10800 # America/Cayenne GMT-3:00
1119,-18000 # America/Cayman GMT-5:00
1168,-10800 # America/Cordoba GMT-3:00
1218,-14400 # America/Curacao GMT-4:00
1249,-25200 # America/Dawson_Creek GMT-7:00
1301,-14400 # America/Dominica GMT-4:00
1444,-14400 # America/Grenada GMT-4:00
1460,-14400 # America/Guadeloupe GMT-4:00
1497,-18000 # America/Guayaquil GMT-5:00
1515,-14400 # America/Guyana GMT-4:00
1561,-18000 # America/Indiana/Knox GMT-5:00
1582,-18000 # America/Indiana/Marengo GMT-5:00
1606,-18000 # America/Indiana/Vevay GMT-5:00
1628,-18000 # America/Indianapolis GMT-5:00
1680,-18000 # America/Jamaica GMT-5:00
1696,-10800 # America/Jujuy GMT-3:00
1725,-14400 # America/La_Paz GMT-4:00
1807,-21600 # America/Managua GMT-6:00
1823,-14400 # America/Manaus GMT-4:00
1838,-14400 # America/Martinique GMT-4:00
1874,-10800 # America/Mendoza GMT-3:00
1981,-14400 # America/Montserrat GMT-4:00
2061,-7200 # America/Noronha GMT-2:00
2077,-18000 # America/Panama GMT-5:00
2112,-10800 # America/Paramaribo GMT-3:00
2131,-25200 # America/Phoenix GMT-7:00
2170,-14400 # America/Port_of_Spain GMT-4:00
2192,-18000 # America/Porto_Acre GMT-5:00
2211,-14400 # America/Porto_Velho GMT-4:00
2231,-14400 # America/Puerto_Rico GMT-4:00
2292,-21600 # America/Regina GMT-6:00
2307,-10800 # America/Rosario GMT-3:00
2340,-14400 # America/Santo_Domingo GMT-4:00
2418,-14400 # America/St_Kitts GMT-4:00
2435,-14400 # America/St_Lucia GMT-4:00
2452,-14400 # America/St_Thomas GMT-4:00
2470,-14400 # America/St_Vincent GMT-4:00
2489,-21600 # America/Swift_Current GMT-6:00
2581,-14400 # America/Tortola GMT-4:00
2687,28800 # Antarctica/Casey GMT+8:00
2704,25200 # Antarctica/Davis GMT+7:00
2721,36000 # Antarctica/DumontDUrville GMT+10:00
2747,21600 # Antarctica/Mawson GMT+6:00
2802,10800 # Antarctica/Syowa GMT+3:00
2819,10800 # Asia/Aden GMT+3:00
2887,18000 # Asia/Ashkhabad GMT+5:00
2915,10800 # Asia/Bahrain GMT+3:00
2938,25200 # Asia/Bangkok GMT+7:00
2976,28800 # Asia/Brunei GMT+8:00
2988,19800 # Asia/Calcutta GMT+5:30
3017,21600 # Asia/Colombo GMT+6:00
3030,21600 # Asia/Dacca GMT+6:00
3055,28800 # Asia/Dili GMT+8:00
3065,14400 # Asia/Dubai GMT+4:00
3076,18000 # Asia/Dushanbe GMT+5:00
3140,25200 # Asia/Jakarta GMT+7:00
3153,32400 # Asia/Jayapura GMT+9:00
3182,16200 # Asia/Kabul GMT+4:30
3208,18000 # Asia/Karachi GMT+5:00
3234,20700 # Asia/Katmandu GMT+5:45
3265,28800 # Asia/Kuala_Lumpur GMT+8:00
3283,28800 # Asia/Kuching GMT+8:00
3296,10800 # Asia/Kuwait GMT+3:00
3344,14400 # Asia/Muscat GMT+4:00
3396,25200 # Asia/Phnom_Penh GMT+7:00
3412,32400 # Asia/Pyongyang GMT+9:00
3427,10800 # Asia/Qatar GMT+3:00
3438,23400 # Asia/Rangoon GMT+6:30
3451,10800 # Asia/Riyadh GMT+3:00
3463,11224 # Asia/Riyadh87 GMT+3:07:04
3477,11224 # Asia/Riyadh88 GMT+3:07:04
3491,11224 # Asia/Riyadh89 GMT+3:07:04
3505,25200 # Asia/Saigon GMT+7:00
3517,18000 # Asia/Samarkand GMT+5:00
3557,28800 # Asia/Singapore GMT+8:00
3584,18000 # Asia/Tashkent GMT+5:00
3623,21600 # Asia/Thimbu GMT+6:00
3635,32400 # Asia/Tokyo GMT+9:00
3646,28800 # Asia/Ujung_Pandang GMT+8:00
3693,25200 # Asia/Vientiane GMT+7:00
3819,-3600 # Atlantic/Cape_Verde GMT-1:00
3855,-3600 # Atlantic/Jan_Mayen GMT-1:00
3891,0 # Atlantic/Reykjavik GMT+0:00
3910,-7200 # Atlantic/South_Georgia GMT-2:00
3933,0 # Atlantic/St_Helena GMT+0:00
4122,28800 # Australia/Perth GMT+8:00
4163,0 # Etc/GMT GMT+0
4171,-3600 # Etc/GMT+1 GMT-1
4181,-36000 # Etc/GMT+10 GMT-10
4192,-39600 # Etc/GMT+11 GMT-11
4203,-43200 # Etc/GMT+12 GMT-12
4214,-7200 # Etc/GMT+2 GMT-2
4224,-10800 # Etc/GMT+3 GMT-3
4234,-14400 # Etc/GMT+4 GMT-4
4244,-18000 # Etc/GMT+5 GMT-5
4254,-21600 # Etc/GMT+6 GMT-6
4264,-25200 # Etc/GMT+7 GMT-7
4274,-28800 # Etc/GMT+8 GMT-8
4284,-32400 # Etc/GMT+9 GMT-9
4294,3600 # Etc/GMT-1 GMT+1
4304,36000 # Etc/GMT-10 GMT+10
4315,39600 # Etc/GMT-11 GMT+11
4326,43200 # Etc/GMT-12 GMT+12
4337,46800 # Etc/GMT-13 GMT+13
4348,50400 # Etc/GMT-14 GMT+14
4359,7200 # Etc/GMT-2 GMT+2
4369,10800 # Etc/GMT-3 GMT+3
4379,14400 # Etc/GMT-4 GMT+4
4389,18000 # Etc/GMT-5 GMT+5
4399,21600 # Etc/GMT-6 GMT+6
4409,25200 # Etc/GMT-7 GMT+7
4419,28800 # Etc/GMT-8 GMT+8
4429,32400 # Etc/GMT-9 GMT+9
4439,0 # Etc/UCT GMT+0
4447,0 # Etc/UTC GMT+0
4962,7200 # Europe/Tallinn GMT+2:00
5111,10800 # Indian/Antananarivo GMT+3:00
5131,18000 # Indian/Chagos GMT+5:00
5145,25200 # Indian/Christmas GMT+7:00
5162,23400 # Indian/Cocos GMT+6:30
5175,10800 # Indian/Comoro GMT+3:00
5189,18000 # Indian/Kerguelen GMT+5:00
5206,14400 # Indian/Mahe GMT+4:00
5218,18000 # Indian/Maldives GMT+5:00
5234,14400 # Indian/Mauritius GMT+4:00
5251,10800 # Indian/Mayotte GMT+3:00
5266,14400 # Indian/Reunion GMT+4:00
5285,-39600 # Pacific/Apia GMT-11:00
5360,46800 # Pacific/Enderbury GMT+13:00
5378,-36000 # Pacific/Fakaofo GMT-10:00
5407,43200 # Pacific/Funafuti GMT+12:00
5424,-21600 # Pacific/Galapagos GMT-6:00
5442,-32400 # Pacific/Gambier GMT-9:00
5458,39600 # Pacific/Guadalcanal GMT+11:00
5478,36000 # Pacific/Guam GMT+10:00
5491,-36000 # Pacific/Honolulu GMT-10:00
5508,-36000 # Pacific/Johnston GMT-10:00
5525,50400 # Pacific/Kiritimati GMT+14:00
5544,39600 # Pacific/Kosrae GMT+11:00
5559,43200 # Pacific/Kwajalein GMT+12:00
5577,43200 # Pacific/Majuro GMT+12:00
5592,-34200 # Pacific/Marquesas GMT-9:30
5610,-39600 # Pacific/Midway GMT-11:00
5625,43200 # Pacific/Nauru GMT+12:00
5639,-39600 # Pacific/Niue GMT-11:00
5652,41400 # Pacific/Norfolk GMT+11:30
5683,-39600 # Pacific/Pago_Pago GMT-11:00
5701,32400 # Pacific/Palau GMT+9:00
5715,-28800 # Pacific/Pitcairn GMT-8:00
5732,39600 # Pacific/Ponape GMT+11:00
5747,36000 # Pacific/Port_Moresby GMT+10:00
5786,36000 # Pacific/Saipan GMT+10:00
5801,-36000 # Pacific/Tahiti GMT-10:00
5816,43200 # Pacific/Tarawa GMT+12:00
5849,36000 # Pacific/Truk GMT+10:00
5862,43200 # Pacific/Wake GMT+12:00
5875,43200 # Pacific/Wallis GMT+12:00
5890,36000 # Pacific/Yap GMT+10:00
end
179 # count of dst zones to follow
15,0,8,1,0,0,w,11,31,0,0,w,20 # Africa/Accra GMT+0:00 Sep 1 0:00 Dec 31 0:00 0:20
184,7200,3,-1,6,0,s,8,-1,5,1380,s,60 # Africa/Cairo GMT+2:00 Apr lastFri 0:00s Sep lastThu 23:00s 1:00
215,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Africa/Ceuta GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
323,0,5,1,0,0,w,8,1,0,0,w,60 # Africa/Freetown GMT+0:00 Jun 1 0:00 Sep 1 0:00 1:00
369,7200,8,15,-1,120,w,2,15,-1,120,w,60 # Africa/Johannesburg GMT+2:00 Sep Sun>=15 2:00 Mar Sun>=15 2:00 1:00
404,7200,3,-1,1,0,w,9,15,0,0,w,60 # Africa/Khartoum GMT+2:00 Apr lastSun 0:00 Oct 15 0:00 1:00
776,3600,4,1,0,0,s,8,-1,1,0,s,60 # Africa/Tunis GMT+1:00 May 1 0:00s Sep lastSun 0:00s 1:00
789,3600,8,1,-1,120,w,3,1,-1,120,w,60 # Africa/Windhoek GMT+1:00 Sep Sun>=1 2:00 Apr Sun>=1 2:00 1:00
805,-36000,3,1,-1,120,w,9,-1,1,120,w,60 # America/Adak GMT-10:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
818,-32400,3,1,-1,120,w,9,-1,1,120,w,60 # America/Anchorage GMT-9:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
869,-10800,9,1,-1,0,w,1,21,0,0,w,60 # America/Araguaina GMT-3:00 Oct Sun>=1 0:00 Feb 21 0:00 1:00
901,-14400,9,1,-1,0,w,1,-1,1,0,w,60 # America/Asuncion GMT-4:00 Oct Sun>=1 0:00 Feb lastSun 0:00 1:00
918,-14400,3,15,-1,120,w,8,25,0,120,w,60 # America/Barbados GMT-4:00 Apr Sun>=15 2:00 Sep 25 2:00 1:00
949,-21600,11,18,0,0,w,1,12,0,0,w,60 # America/Belize GMT-6:00 Dec 18 0:00 Feb 12 0:00 1:00
964,-14400,9,1,-1,0,w,1,21,0,0,w,60 # America/Boa_Vista GMT-4:00 Oct Sun>=1 0:00 Feb 21 0:00 1:00
982,-18000,4,2,0,0,w,11,31,0,0,w,60 # America/Bogota GMT-5:00 May 2 0:00 Dec 31 0:00 1:00
997,-25200,3,1,-1,120,w,9,-1,1,120,w,60 # America/Boise GMT-7:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1011,-10800,9,15,-1,0,w,2,1,-1,0,w,60 # America/Buenos_Aires GMT-3:00 Oct Sun>=15 0:00 Mar Sun>=1 0:00 1:00
1032,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Cambridge_Bay GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1054,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Cancun GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1134,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Chicago GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1150,-25200,3,1,-1,120,w,9,-1,1,120,w,60 # America/Chihuahua GMT-7:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1184,-21600,0,15,-7,0,w,2,15,0,0,w,60 # America/Costa_Rica GMT-6:00 Jan Sat>=15 0:00 Mar 15 0:00 1:00
1203,-14400,9,1,-1,0,w,1,21,0,0,w,60 # America/Cuiaba GMT-4:00 Oct Sun>=1 0:00 Feb 21 0:00 1:00
1234,-28800,3,1,-1,120,w,9,-1,1,120,w,60 # America/Dawson GMT-8:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1270,-25200,3,1,-1,120,w,9,-1,1,120,w,60 # America/Denver GMT-7:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1285,-18000,3,1,-1,120,w,9,-1,1,120,w,60 # America/Detroit GMT-5:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1318,-25200,3,1,-1,120,w,9,-1,1,120,w,60 # America/Edmonton GMT-7:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1335,-21600,4,1,-1,0,w,8,-1,1,0,w,60 # America/El_Salvador GMT-6:00 May Sun>=1 0:00 Sep lastSun 0:00 1:00
1355,-10800,9,1,-1,0,w,1,21,0,0,w,60 # America/Fortaleza GMT-3:00 Oct Sun>=1 0:00 Feb 21 0:00 1:00
1373,-14400,3,1,-1,120,w,9,-1,1,120,w,60 # America/Glace_Bay GMT-4:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1391,-10800,2,-1,1,60,u,9,-1,1,60,u,60 # America/Godthab GMT-3:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
1407,-14400,3,1,-1,120,w,9,-1,1,120,w,60 # America/Goose_Bay GMT-4:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1425,-18000,3,1,-1,0,w,9,-1,1,0,w,60 # America/Grand_Turk GMT-5:00 Apr Sun>=1 0:00 Oct lastSun 0:00 1:00
1479,-21600,2,23,0,0,w,8,7,0,0,w,60 # America/Guatemala GMT-6:00 Mar 23 0:00 Sep 7 0:00 1:00
1530,-14400,3,1,-1,120,w,9,-1,1,120,w,60 # America/Halifax GMT-4:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1546,-18000,3,1,0,0,s,9,-1,1,0,s,60 # America/Havana GMT-5:00 Apr 1 0:00s Oct lastSun 0:00s 1:00
1649,-25200,3,1,-1,120,w,9,-1,1,120,w,60 # America/Inuvik GMT-7:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1664,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Iqaluit GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1710,-32400,3,1,-1,120,w,9,-1,1,120,w,60 # America/Juneau GMT-9:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1740,-18000,0,1,0,0,w,3,1,0,0,w,60 # America/Lima GMT-5:00 Jan 1 0:00 Apr 1 0:00 1:00
1753,-28800,3,1,-1,120,w,9,-1,1,120,w,60 # America/Los_Angeles GMT-8:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1773,-18000,3,1,-1,120,w,9,-1,1,120,w,60 # America/Louisville GMT-5:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1792,-10800,9,1,-1,0,w,1,21,0,0,w,60 # America/Maceio GMT-3:00 Oct Sun>=1 0:00 Feb 21 0:00 1:00
1857,-25200,3,1,-1,120,w,9,-1,1,120,w,60 # America/Mazatlan GMT-7:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1890,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Menominee GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1908,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Mexico_City GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1928,-10800,3,1,-1,120,w,9,-1,1,120,w,60 # America/Miquelon GMT-3:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
1945,-10800,9,18,0,0,w,1,28,0,0,w,60 # America/Montevideo GMT-3:00 Oct 18 0:00 Feb 28 0:00 1:00
1964,-18000,3,1,-1,120,w,9,-1,1,120,w,60 # America/Montreal GMT-5:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2000,-18000,3,1,-1,120,w,9,-1,1,120,w,60 # America/Nassau GMT-5:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2015,-18000,3,1,-1,120,w,9,-1,1,120,w,60 # America/New_York GMT-5:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2032,-18000,3,1,-1,120,w,9,-1,1,120,w,60 # America/Nipigon GMT-5:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2048,-32400,3,1,-1,120,w,9,-1,1,120,w,60 # America/Nome GMT-9:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2092,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Pangnirtung GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2147,-18000,3,1,-1,60,s,9,-1,1,60,s,60 # America/Port-au-Prince GMT-5:00 Apr Sun>=1 1:00s Oct lastSun 1:00s 1:00
2251,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Rainy_River GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2271,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Rankin_Inlet GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2323,-14400,9,9,-1,0,w,3,4,0,0,w,60 # America/Santiago GMT-4:00 Oct Sun>=9 0:00 Apr 4 0:00 1:00
2362,-10800,9,1,-1,0,w,1,21,0,0,w,60 # America/Sao_Paulo GMT-3:00 Oct Sun>=1 0:00 Feb 21 0:00 1:00
2380,-3600,2,-1,1,60,u,9,-1,1,60,u,60 # America/Scoresbysund GMT-1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
2401,-12600,3,1,-1,120,w,9,-1,1,120,w,60 # America/St_Johns GMT-3:30 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2511,-21600,4,1,-1,0,w,8,-1,1,0,w,60 # America/Tegucigalpa GMT-6:00 May Sun>=1 0:00 Sep lastSun 0:00 1:00
2531,-14400,3,1,-1,120,w,9,-1,1,120,w,60 # America/Thule GMT-4:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2545,-18000,3,1,-1,120,w,9,-1,1,120,w,60 # America/Thunder_Bay GMT-5:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2565,-28800,3,1,-1,120,w,9,-1,1,120,w,60 # America/Tijuana GMT-8:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2597,-28800,3,1,-1,120,w,9,-1,1,120,w,60 # America/Vancouver GMT-8:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2615,-28800,3,1,-1,120,w,9,-1,1,120,w,60 # America/Whitehorse GMT-8:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2634,-21600,3,1,-1,120,w,9,-1,1,120,w,60 # America/Winnipeg GMT-6:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2651,-32400,3,1,-1,120,w,9,-1,1,120,w,60 # America/Yakutat GMT-9:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2667,-25200,3,1,-1,120,w,9,-1,1,120,w,60 # America/Yellowknife GMT-7:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
2765,43200,9,1,-1,120,s,2,15,-1,120,s,60 # Antarctica/McMurdo GMT+12:00 Oct Sun>=1 2:00s Mar Sun>=15 2:00s 1:00
2784,-14400,9,9,-1,0,w,3,4,0,0,w,60 # Antarctica/Palmer GMT-4:00 Oct Sun>=9 0:00 Apr 4 0:00 1:00
2829,21600,2,-1,1,0,w,9,-1,1,0,w,60 # Asia/Almaty GMT+6:00 Mar lastSun 0:00 Oct lastSun 0:00 1:00
2841,7200,3,1,0,0,w,9,1,0,0,w,60 # Asia/Amman GMT+2:00 Apr 1 0:00 Oct 1 0:00 1:00
2852,43200,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Anadyr GMT+12:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
2864,14400,2,-1,1,0,w,9,-1,1,0,w,60 # Asia/Aqtau GMT+4:00 Mar lastSun 0:00 Oct lastSun 0:00 1:00
2875,18000,2,-1,1,0,w,9,-1,1,0,w,60 # Asia/Aqtobe GMT+5:00 Mar lastSun 0:00 Oct lastSun 0:00 1:00
2902,10800,3,1,0,180,s,9,1,0,180,s,60 # Asia/Baghdad GMT+3:00 Apr 1 3:00s Oct 1 3:00s 1:00
2928,14400,2,-1,1,60,w,9,-1,1,60,w,60 # Asia/Baku GMT+4:00 Mar lastSun 1:00 Oct lastSun 1:00 1:00
2951,7200,2,-1,1,0,w,9,-1,1,0,w,60 # Asia/Beirut GMT+2:00 Mar lastSun 0:00 Oct lastSun 0:00 1:00
2963,18000,2,-1,1,150,w,9,-1,1,150,w,60 # Asia/Bishkek GMT+5:00 Mar lastSun 2:30 Oct lastSun 2:30 1:00
3002,28800,3,10,-1,0,w,8,11,-1,0,w,60 # Asia/Chungking GMT+8:00 Apr Sun>=10 0:00 Sep Sun>=11 0:00 1:00
3041,7200,3,1,0,0,w,9,1,0,0,w,60 # Asia/Damascus GMT+2:00 Apr 1 0:00 Oct 1 0:00 1:00
3090,7200,3,15,-6,0,w,9,15,-6,0,w,60 # Asia/Gaza GMT+2:00 Apr Fri>=15 0:00 Oct Fri>=15 0:00 1:00
3100,28800,3,10,-1,0,w,8,11,-1,0,w,60 # Asia/Harbin GMT+8:00 Apr Sun>=10 0:00 Sep Sun>=11 0:00 1:00
3112,28800,3,10,-1,0,w,8,11,-1,0,w,60 # Asia/Hong_Kong GMT+8:00 Apr Sun>=10 0:00 Sep Sun>=11 0:00 1:00
3127,28800,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Irkutsk GMT+8:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3167,7200,3,1,-6,120,w,8,3,0,120,w,60 # Asia/Jerusalem GMT+2:00 Apr Fri>=1 2:00 Sep 3 2:00 1:00
3193,43200,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Kamchatka GMT+12:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3221,28800,3,10,-1,0,w,8,11,-1,0,w,60 # Asia/Kashgar GMT+8:00 Apr Sun>=10 0:00 Sep Sun>=11 0:00 1:00
3248,25200,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Krasnoyarsk GMT+7:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3308,28800,3,10,-1,0,w,8,11,-1,0,w,60 # Asia/Macao GMT+8:00 Apr Sun>=10 0:00 Sep Sun>=11 0:00 1:00
3319,39600,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Magadan GMT+11:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3332,28800,2,22,0,0,w,8,21,0,0,w,60 # Asia/Manila GMT+8:00 Mar 22 0:00 Sep 21 0:00 1:00
3356,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Asia/Nicosia GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
3369,21600,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Novosibirsk GMT+6:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3386,21600,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Omsk GMT+6:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3532,32400,4,-14,-1,0,w,9,-14,-1,0,w,60 # Asia/Seoul GMT+9:00 May Sun<=14 0:00 Oct Sun<=14 0:00 1:00
3543,28800,3,10,-1,0,w,8,11,-1,0,w,60 # Asia/Shanghai GMT+8:00 Apr Sun>=10 0:00 Sep Sun>=11 0:00 1:00
3572,28800,5,30,0,0,w,8,30,0,0,w,60 # Asia/Taipei GMT+8:00 Jun 30 0:00 Sep 30 0:00 1:00
3598,14400,2,-1,1,0,w,9,-1,1,0,w,60 # Asia/Tbilisi GMT+4:00 Mar lastSun 0:00 Oct lastSun 0:00 1:00
3611,12600,2,20,0,0,w,8,23,0,0,w,60 # Asia/Tehran GMT+3:30 Mar 20 0:00 Sep 23 0:00 1:00
3665,28800,2,-1,1,0,w,8,-1,1,0,w,60 # Asia/Ulan_Bator GMT+8:00 Mar lastSun 0:00 Sep lastSun 0:00 1:00
3681,28800,3,10,-1,0,w,8,11,-1,0,w,60 # Asia/Urumqi GMT+8:00 Apr Sun>=10 0:00 Sep Sun>=11 0:00 1:00
3708,36000,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Vladivostok GMT+10:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3725,32400,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Yakutsk GMT+9:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3738,18000,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Yekaterinburg GMT+5:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3757,14400,2,-1,1,120,s,9,-1,1,120,s,60 # Asia/Yerevan GMT+4:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
3770,-3600,2,-1,1,60,u,9,-1,1,60,u,60 # Atlantic/Azores GMT-1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
3786,-14400,3,1,-1,120,w,9,-1,1,120,w,60 # Atlantic/Bermuda GMT-4:00 Apr Sun>=1 2:00 Oct lastSun 2:00 1:00
3803,0,2,-1,1,60,u,9,-1,1,60,u,60 # Atlantic/Canary GMT+0:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
3839,0,2,-1,1,60,u,9,-1,1,60,u,60 # Atlantic/Faeroe GMT+0:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
3874,0,2,-1,1,60,u,9,-1,1,60,u,60 # Atlantic/Madeira GMT+0:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
3952,-14400,8,8,-1,0,w,3,16,-1,0,w,60 # Atlantic/Stanley GMT-4:00 Sep Sun>=8 0:00 Apr Sun>=16 0:00 1:00
3969,34200,9,-1,1,120,s,2,-1,1,120,s,60 # Australia/Adelaide GMT+9:30 Oct lastSun 2:00s Mar lastSun 2:00s 1:00
3988,36000,9,-1,1,120,s,2,1,-1,120,s,60 # Australia/Brisbane GMT+10:00 Oct lastSun 2:00s Mar Sun>=1 2:00s 1:00
4007,34200,9,-1,1,120,s,2,-1,1,120,s,60 # Australia/Broken_Hill GMT+9:30 Oct lastSun 2:00s Mar lastSun 2:00s 1:00
4029,34200,9,3,0,120,w,2,-1,1,120,w,60 # Australia/Darwin GMT+9:30 Oct 3 2:00 Mar lastSun 2:00 1:00
4046,36000,9,1,-1,120,s,2,-1,1,120,s,60 # Australia/Hobart GMT+10:00 Oct Sun>=1 2:00s Mar lastSun 2:00s 1:00
4063,36000,9,-1,1,120,s,2,1,-1,120,s,60 # Australia/Lindeman GMT+10:00 Oct lastSun 2:00s Mar Sun>=1 2:00s 1:00
4082,37800,9,-1,1,120,s,2,-1,1,120,s,30 # Australia/Lord_Howe GMT+10:30 Oct lastSun 2:00s Mar lastSun 2:00s 0:30
4102,36000,9,-1,1,120,s,2,-1,1,120,s,60 # Australia/Melbourne GMT+10:00 Oct lastSun 2:00s Mar lastSun 2:00s 1:00
4138,36000,9,-1,1,120,s,2,-1,1,120,s,60 # Australia/Sydney GMT+10:00 Oct lastSun 2:00s Mar lastSun 2:00s 1:00
4155,3600,2,-1,1,120,s,9,-1,1,120,s,60 # CET GMT+1:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
4159,7200,2,-1,1,60,u,9,-1,1,60,u,60 # EET GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4455,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Amsterdam GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4472,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Andorra GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4487,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Athens GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4501,0,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Belfast GMT+0:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4516,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Belgrade GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4532,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Berlin GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4546,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Brussels GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4562,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Bucharest GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4579,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Budapest GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4595,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Chisinau GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4611,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Copenhagen GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4629,0,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Dublin GMT+0:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4643,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Gibraltar GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4660,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Helsinki GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4676,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Istanbul GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4692,7200,2,-1,1,120,s,9,-1,1,120,s,60 # Europe/Kaliningrad GMT+2:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
4711,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Kiev GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4723,0,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Lisbon GMT+0:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4737,0,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/London GMT+0:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4751,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Luxembourg GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4769,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Madrid GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4783,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Malta GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4796,7200,2,-1,1,120,s,9,-1,1,120,s,60 # Europe/Minsk GMT+2:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
4809,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Monaco GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4823,10800,2,-1,1,120,s,9,-1,1,120,s,60 # Europe/Moscow GMT+3:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
4837,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Oslo GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4849,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Paris GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4862,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Prague GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4876,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Riga GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4888,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Rome GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4900,14400,2,-1,1,120,s,9,-1,1,120,s,60 # Europe/Samara GMT+4:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
4914,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Simferopol GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4932,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Sofia GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4945,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Stockholm GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4977,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Tirane GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
4991,10800,2,-1,1,120,s,9,-1,1,120,s,60 # Europe/Tiraspol GMT+3:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
5007,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Uzhgorod GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
5023,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Vaduz GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
5036,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Vienna GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
5050,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Vilnius GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
5065,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Warsaw GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
5079,7200,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Zaporozhye GMT+2:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
5097,3600,2,-1,1,60,u,9,-1,1,60,u,60 # Europe/Zurich GMT+1:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
5281,3600,2,-1,1,120,s,9,-1,1,120,s,60 # MET GMT+1:00 Mar lastSun 2:00s Oct lastSun 2:00s 1:00
5298,43200,9,1,-1,120,s,2,15,-1,120,s,60 # Pacific/Auckland GMT+12:00 Oct Sun>=1 2:00s Mar Sun>=15 2:00s 1:00
5315,45900,9,1,-1,165,s,2,15,-1,165,s,60 # Pacific/Chatham GMT+12:45 Oct Sun>=1 2:45s Mar Sun>=15 2:45s 1:00
5331,-21600,9,9,-1,0,w,3,4,0,0,w,60 # Pacific/Easter GMT-6:00 Oct Sun>=9 0:00 Apr 4 0:00 1:00
5346,39600,9,23,-1,0,w,0,23,-1,0,w,60 # Pacific/Efate GMT+11:00 Oct Sun>=23 0:00 Jan Sun>=23 0:00 1:00
5394,43200,10,1,-1,120,w,1,-1,1,180,w,60 # Pacific/Fiji GMT+12:00 Nov Sun>=1 2:00 Feb lastSun 3:00 1:00
5668,39600,11,1,0,120,s,2,2,0,120,s,60 # Pacific/Noumea GMT+11:00 Dec 1 2:00s Mar 2 2:00s 1:00
5768,-36000,9,-1,1,0,w,2,1,-1,0,w,30 # Pacific/Rarotonga GMT-10:00 Oct lastSun 0:00 Mar Sun>=1 0:00 0:30
5831,46800,9,1,-7,120,s,3,16,-1,120,s,60 # Pacific/Tongatapu GMT+13:00 Oct Sat>=1 2:00s Apr Sun>=16 2:00s 1:00
5902,0,2,-1,1,60,u,9,-1,1,60,u,60 # WET GMT+0:00 Mar lastSun 1:00u Oct lastSun 1:00u 1:00
end
387 # count of names to follow
Africa/Abidjan
Africa/Accra
Africa/Addis_Ababa
Africa/Algiers
Africa/Asmera
Africa/Bamako
Africa/Bangui
Africa/Banjul
Africa/Bissau
Africa/Blantyre
Africa/Brazzaville
Africa/Bujumbura
Africa/Cairo
Africa/Casablanca
Africa/Ceuta
Africa/Conakry
Africa/Dakar
Africa/Dar_es_Salaam
Africa/Djibouti
Africa/Douala
Africa/El_Aaiun
Africa/Freetown
Africa/Gaborone
Africa/Harare
Africa/Johannesburg
Africa/Kampala
Africa/Khartoum
Africa/Kigali
Africa/Kinshasa
Africa/Lagos
Africa/Libreville
Africa/Lome
Africa/Luanda
Africa/Lubumbashi
Africa/Lusaka
Africa/Malabo
Africa/Maputo
Africa/Maseru
Africa/Mbabane
Africa/Mogadishu
Africa/Monrovia
Africa/Nairobi
Africa/Ndjamena
Africa/Niamey
Africa/Nouakchott
Africa/Ouagadougou
Africa/Porto-Novo
Africa/Sao_Tome
Africa/Timbuktu
Africa/Tripoli
Africa/Tunis
Africa/Windhoek
America/Adak
America/Anchorage
America/Anguilla
America/Antigua
America/Araguaina
America/Aruba
America/Asuncion
America/Barbados
America/Belem
America/Belize
America/Boa_Vista
America/Bogota
America/Boise
America/Buenos_Aires
America/Cambridge_Bay
America/Cancun
America/Caracas
America/Catamarca
America/Cayenne
America/Cayman
America/Chicago
America/Chihuahua
America/Cordoba
America/Costa_Rica
America/Cuiaba
America/Curacao
America/Dawson
America/Dawson_Creek
America/Denver
America/Detroit
America/Dominica
America/Edmonton
America/El_Salvador
America/Fortaleza
America/Glace_Bay
America/Godthab
America/Goose_Bay
America/Grand_Turk
America/Grenada
America/Guadeloupe
America/Guatemala
America/Guayaquil
America/Guyana
America/Halifax
America/Havana
America/Indiana/Knox
America/Indiana/Marengo
America/Indiana/Vevay
America/Indianapolis
America/Inuvik
America/Iqaluit
America/Jamaica
America/Jujuy
America/Juneau
America/La_Paz
America/Lima
America/Los_Angeles
America/Louisville
America/Maceio
America/Managua
America/Manaus
America/Martinique
America/Mazatlan
America/Mendoza
America/Menominee
America/Mexico_City
America/Miquelon
America/Montevideo
America/Montreal
America/Montserrat
America/Nassau
America/New_York
America/Nipigon
America/Nome
America/Noronha
America/Panama
America/Pangnirtung
America/Paramaribo
America/Phoenix
America/Port-au-Prince
America/Port_of_Spain
America/Porto_Acre
America/Porto_Velho
America/Puerto_Rico
America/Rainy_River
America/Rankin_Inlet
America/Regina
America/Rosario
America/Santiago
America/Santo_Domingo
America/Sao_Paulo
America/Scoresbysund
America/St_Johns
America/St_Kitts
America/St_Lucia
America/St_Thomas
America/St_Vincent
America/Swift_Current
America/Tegucigalpa
America/Thule
America/Thunder_Bay
America/Tijuana
America/Tortola
America/Vancouver
America/Whitehorse
America/Winnipeg
America/Yakutat
America/Yellowknife
Antarctica/Casey
Antarctica/Davis
Antarctica/DumontDUrville
Antarctica/Mawson
Antarctica/McMurdo
Antarctica/Palmer
Antarctica/Syowa
Asia/Aden
Asia/Almaty
Asia/Amman
Asia/Anadyr
Asia/Aqtau
Asia/Aqtobe
Asia/Ashkhabad
Asia/Baghdad
Asia/Bahrain
Asia/Baku
Asia/Bangkok
Asia/Beirut
Asia/Bishkek
Asia/Brunei
Asia/Calcutta
Asia/Chungking
Asia/Colombo
Asia/Dacca
Asia/Damascus
Asia/Dili
Asia/Dubai
Asia/Dushanbe
Asia/Gaza
Asia/Harbin
Asia/Hong_Kong
Asia/Irkutsk
Asia/Jakarta
Asia/Jayapura
Asia/Jerusalem
Asia/Kabul
Asia/Kamchatka
Asia/Karachi
Asia/Kashgar
Asia/Katmandu
Asia/Krasnoyarsk
Asia/Kuala_Lumpur
Asia/Kuching
Asia/Kuwait
Asia/Macao
Asia/Magadan
Asia/Manila
Asia/Muscat
Asia/Nicosia
Asia/Novosibirsk
Asia/Omsk
Asia/Phnom_Penh
Asia/Pyongyang
Asia/Qatar
Asia/Rangoon
Asia/Riyadh
Asia/Riyadh87
Asia/Riyadh88
Asia/Riyadh89
Asia/Saigon
Asia/Samarkand
Asia/Seoul
Asia/Shanghai
Asia/Singapore
Asia/Taipei
Asia/Tashkent
Asia/Tbilisi
Asia/Tehran
Asia/Thimbu
Asia/Tokyo
Asia/Ujung_Pandang
Asia/Ulan_Bator
Asia/Urumqi
Asia/Vientiane
Asia/Vladivostok
Asia/Yakutsk
Asia/Yekaterinburg
Asia/Yerevan
Atlantic/Azores
Atlantic/Bermuda
Atlantic/Canary
Atlantic/Cape_Verde
Atlantic/Faeroe
Atlantic/Jan_Mayen
Atlantic/Madeira
Atlantic/Reykjavik
Atlantic/South_Georgia
Atlantic/St_Helena
Atlantic/Stanley
Australia/Adelaide
Australia/Brisbane
Australia/Broken_Hill
Australia/Darwin
Australia/Hobart
Australia/Lindeman
Australia/Lord_Howe
Australia/Melbourne
Australia/Perth
Australia/Sydney
CET
EET
Etc/GMT
Etc/GMT+1
Etc/GMT+10
Etc/GMT+11
Etc/GMT+12
Etc/GMT+2
Etc/GMT+3
Etc/GMT+4
Etc/GMT+5
Etc/GMT+6
Etc/GMT+7
Etc/GMT+8
Etc/GMT+9
Etc/GMT-1
Etc/GMT-10
Etc/GMT-11
Etc/GMT-12
Etc/GMT-13
Etc/GMT-14
Etc/GMT-2
Etc/GMT-3
Etc/GMT-4
Etc/GMT-5
Etc/GMT-6
Etc/GMT-7
Etc/GMT-8
Etc/GMT-9
Etc/UCT
Etc/UTC
Europe/Amsterdam
Europe/Andorra
Europe/Athens
Europe/Belfast
Europe/Belgrade
Europe/Berlin
Europe/Brussels
Europe/Bucharest
Europe/Budapest
Europe/Chisinau
Europe/Copenhagen
Europe/Dublin
Europe/Gibraltar
Europe/Helsinki
Europe/Istanbul
Europe/Kaliningrad
Europe/Kiev
Europe/Lisbon
Europe/London
Europe/Luxembourg
Europe/Madrid
Europe/Malta
Europe/Minsk
Europe/Monaco
Europe/Moscow
Europe/Oslo
Europe/Paris
Europe/Prague
Europe/Riga
Europe/Rome
Europe/Samara
Europe/Simferopol
Europe/Sofia
Europe/Stockholm
Europe/Tallinn
Europe/Tirane
Europe/Tiraspol
Europe/Uzhgorod
Europe/Vaduz
Europe/Vienna
Europe/Vilnius
Europe/Warsaw
Europe/Zaporozhye
Europe/Zurich
Indian/Antananarivo
Indian/Chagos
Indian/Christmas
Indian/Cocos
Indian/Comoro
Indian/Kerguelen
Indian/Mahe
Indian/Maldives
Indian/Mauritius
Indian/Mayotte
Indian/Reunion
MET
Pacific/Apia
Pacific/Auckland
Pacific/Chatham
Pacific/Easter
Pacific/Efate
Pacific/Enderbury
Pacific/Fakaofo
Pacific/Fiji
Pacific/Funafuti
Pacific/Galapagos
Pacific/Gambier
Pacific/Guadalcanal
Pacific/Guam
Pacific/Honolulu
Pacific/Johnston
Pacific/Kiritimati
Pacific/Kosrae
Pacific/Kwajalein
Pacific/Majuro
Pacific/Marquesas
Pacific/Midway
Pacific/Nauru
Pacific/Niue
Pacific/Norfolk
Pacific/Noumea
Pacific/Pago_Pago
Pacific/Palau
Pacific/Pitcairn
Pacific/Ponape
Pacific/Port_Moresby
Pacific/Rarotonga
Pacific/Saipan
Pacific/Tahiti
Pacific/Tarawa
Pacific/Tongatapu
Pacific/Truk
Pacific/Wake
Pacific/Wallis
Pacific/Yap
WET
end

View file

@ -20,11 +20,19 @@ echo create cnvalias.dat and cnvalias_dat.c from convrtrs.txt
gencnval\%toolversion%\gencnval -c-
genccode\%toolversion%\genccode "%ICU_DATA%cnvalias.dat"
echo create tz.dat from tz.txt
rem - This currently creates a spurious zero byte -
rem - tz.dat file in the gentz dir, as well as the -
rem - actual tz.dat file in the data directory. -
gentz\%toolversion%\gentz -c- gentz\tz.txt gentz\tz.dat
genccode\%toolversion%\genccode "%ICU_DATA%tz.dat"
echo create the data DLL
cl "/I..\..\include" /GD /c "%ICU_DATA%unames_dat.c" "%ICU_DATA%cnvalias_dat.c"
cl "/I..\..\include" /GD /c "%ICU_DATA%unames_dat.c" "%ICU_DATA%cnvalias_dat.c" "%ICU_DATA%tz_dat.c"
echo "/out:%ICU_DATA%icudata.dll">mkdll.tmp
echo unames_dat.obj>>mkdll.tmp
echo cnvalias_dat.obj>>mkdll.tmp
echo tz_dat.obj>>mkdll.tmp
type mkdll.lk>>mkdll.tmp
link @mkdll.tmp
@ -32,6 +40,7 @@ echo create the common, memory-mappable file
del "%ICU_DATA%icudata.dat"
echo %ICU_DATA%unames.dat>mkmap.tmp
echo %ICU_DATA%cnvalias.dat>>mkmap.tmp
echo %ICU_DATA%tz.dat>>mkmap.tmp
gencmn\%toolversion%\gencmn 1000000 mkmap.tmp
echo create conversion tables