fmt.format(date[1], result[1]);
date[2] = fmt.parse(result[1], status);
- if (date[1] != date[2] || result[0] != result[1]) {
+ /* This test case worked OK by accident before.Ê date[1] != date[0],
+ * because we use -80/+20 year window for 2-digit year parsing.
+ * (date[0] is in year 1926, date[1] is in year 2026.)Ê result[1] set
+ * by the first format call returns "07/13/26 07:48:28 p.m. PST",
+ * which is correct, because DST was not used in year 1926 in zone
+ * America/Los_Angeles.Ê When this is parsed, date[1] becomes a time
+ * in 2026, which is "07/13/26 08:48:28 p.m. PDT".Ê There was a zone
+ * offset calculation bug that observed DST in 1926, which was resolved.
+ * Before the bug was resolved, result[0] == result[1] was true,
+ * but after the bug fix, the expected result is actually
+ * result[0] != result[1]. -Yoshit
+ */
+ /* TODO: We need to review this code and clarify what we really
+ * want to test here.
+ */
+ //if (date[1] != date[2] || result[0] != result[1]) {
+ if (date[1] != date[2]) {
errln("Round trip failure: \"%S\" (%f), \"%S\" (%f)", result[0].getBuffer(), date[1], result[1].getBuffer(), date[2]);
}
}
// Test parse with incomplete information
fmt = new SimpleDateFormat(UnicodeString("G y"), Locale("en_US@calendar=japanese"), status);
- aDate = -3197120400000.;
+ /* The test data below should points to 1868-09-08T00:00:00 in America/Los_Angeles.
+ * The time calculated by original test code uses -7:00 UTC offset, because it assumes
+ * DST is observed (because of a timezone bug, DST is observed for early 20th century
+ * day to infinite past time). The bug was fixed and DST is no longer used for time before
+ * 1900 for any zones. However, ICU timezone transition data is represented by 32-bit integer
+ * (sec) and cannot represent transitions before 1901 defined in Olson tzdata. For example,
+ * based on Olson definition, offset -7:52:58 should be used for Nov 18, 1883 or older dates.
+ * If ICU properly capture entire Olson zone definition, the start time of "Meiji 1" is
+ * -3197117222000. -Yoshito
+ */
+ /* TODO: When ICU support the Olson LMT offset for America/Los_Angeles, we need to update
+ * the reference data.
+ */
+ //aDate = -3197120400000.;
+ aDate = -3197116800000.;
CHECK(status, "creating date format instance");
if(!fmt) {
errln("Coudln't create en_US instance");
}
{
UnicodeString expect = CharsToUnicodeString("\\u5b89\\u6c385\\u5e747\\u67084\\u65e5\\u6728\\u66dc\\u65e5");
- UDate expectDate = -6106035600000.0;
+ //UDate expectDate = -6106035600000.0;
+ UDate expectDate = -6106032000000.0; // 1776-07-04T00:00:00Z-0800
Locale loc("ja_JP@calendar=japanese");
status = U_ZERO_ERROR;
{ // This Feb 29th falls on a leap year by gregorian year, but not by Japanese year.
UnicodeString expect = CharsToUnicodeString("\\u5EB7\\u6B632\\u5e742\\u670829\\u65e5\\u65e5\\u66dc\\u65e5");
// Add -1:00 to the following for historical TZ - aliu
- UDate expectDate = -16214403600000.0; // courtesy of date format round trip test
+ //UDate expectDate = -16214403600000.0; // courtesy of date format round trip test
+ UDate expectDate = -16214400000000.0; // 1456-03-09T00:00:00Z-0800
Locale loc("ja_JP@calendar=japanese");
status = U_ZERO_ERROR;
/********************************************************************
- * COPYRIGHT:
- * Copyright (c) 1997-2006, International Business Machines Corporation and
- * others. All Rights Reserved.
+ * Copyright (c) 1997-2007, International Business Machines
+ * Corporation and others. All Rights Reserved.
********************************************************************/
#include "unicode/utypes.h"
failure(status, "cal->get");
int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status);
int32_t raw_offset = tz->getRawOffset();
+ /* Because of better historical timezone support based on Olson data,
+ * DST is not observed in year 98. Thus, the expected result is changed.
+ * As of Mar 2007, ICU timezone transition data is represented by 32-bit.
+ * When we support 64-bit Olson transition data, the actual offset in
+ * AD 98 for America/Los_Angeles will be changed again (-7:52:58). Until
+ * then, expected result is offset == raw_offset. -Yoshito
+ */
+ /*
if (offset == raw_offset)
errln("Offsets should not match when in DST");
+ */
+ /* TODO: When ICU support the Olson LMT offset for America/Los_Angeles, we need to update
+ * the reference data.
+ */
+ if (offset != raw_offset)
+ errln("Offsets should match");
delete cal;
}
* definition. This test has been updated to reflect this.
* 12/3/99 aliu
*
+ * Added tests for additional zones and aliases from the icuzones file.
+ * Markus Scherer 2006-nov-06
+ *
* [srl - from java - 7/5/1998]
* @bug 4130885
* Certain short zone IDs, used since 1.1.x, are incorrect.
{"EST", -300, FALSE}, // updated Aug 2003 aliu
{"PRT", -240, FALSE},
{"CNT", -210, TRUE},
- {"AGT", -180, FALSE}, // updated 26 Sep 2000 aliu
+ {"AGT", -180, TRUE}, // updated by tzdata2007k
{"BET", -180, TRUE},
// "CAT", -60, FALSE, // Wrong:
// As of bug 4130885, fix CAT (Central Africa)
{"EAT", 180, FALSE},
{"MET", 60, TRUE}, // updated 12/3/99 aliu
{"NET", 240, TRUE}, // updated 12/3/99 aliu
- {"PLT", 300, FALSE}, // updated Aug 2003 aliu
+ {"PLT", 300, TRUE}, // updated by 2008c
{"IST", 330, FALSE},
{"BST", 360, FALSE},
{"VST", 420, FALSE},
const char* compatibilityMap[] = {
// This list is copied from tz.alias. If tz.alias
- // changes, this list must be updated. Current as of Aug 2003
+ // changes, this list must be updated. Current as of Mar 2007
"ACT", "Australia/Darwin",
"AET", "Australia/Sydney",
"AGT", "America/Buenos_Aires",
"ART", "Africa/Cairo",
"AST", "America/Anchorage",
"BET", "America/Sao_Paulo",
- "BST", "Asia/Dhaka", // Spelling changed in 2000h
+ "BST", "Asia/Dhaka", // # spelling changed in 2000h; was Asia/Dacca
"CAT", "Africa/Harare",
"CNT", "America/St_Johns",
"CST", "America/Chicago",
"EAT", "Africa/Addis_Ababa",
"ECT", "Europe/Paris",
// EET Europe/Istanbul # EET is a standard UNIX zone
- // "EST", "America/New_York", # EST is an Olson alias now (2003)
- "HST", "Pacific/Honolulu",
+ // "EST", "America/New_York", # Defined as -05:00
+ // "HST", "Pacific/Honolulu", # Defined as -10:00
"IET", "America/Indianapolis",
"IST", "Asia/Calcutta",
"JST", "Asia/Tokyo",
// MET Asia/Tehran # MET is a standard UNIX zone
"MIT", "Pacific/Apia",
- // "MST", "America/Denver", # MST is an Olson alias now (2003)
+ // "MST", "America/Denver", # Defined as -07:00
"NET", "Asia/Yerevan",
"NST", "Pacific/Auckland",
"PLT", "Asia/Karachi",
-# Some Portions Copyright (c) 2006 IBM and others. All Rights Reserved.
+# Some Portions Copyright (c) 2006-2007 IBM and others. All Rights Reserved.
srcdir = @srcdir@
top_srcdir = @top_srcdir@
OBJECTS= zic.o localtime.o asctime.o scheck.o ialloc.o
TZDATA = $(firstword $(wildcard ./tzdata*.tar.gz) $(wildcard $(srcdir)/tzdata*.tar.gz))
+TZCODE = $(firstword $(wildcard ./tzcode*.tar.gz) $(wildcard $(srcdir)/tzcode*.tar.gz))
+
+TZORIG=./tzorig
+TZORIG_TZDIR=./tzorig/tzdir
+TZORIG_ABS := $(shell pwd)/tzorig
+TZORIG_TZDIR_ABS := $(TZORIG_ABS)/tzdir
+TZORIG_OPTS := CFLAGS="-D_POSIX_C_SOURCE $(TZORIG_EXTRA_CFLAGS)" TZDIR=$(TZORIG_TZDIR_ABS)
+
+
+## Options for building zdumps
+ZDUMPOUT=$(shell pwd)/zdumpout
+ICUZDUMPOUT=$(shell pwd)/icuzdumpout
+
+ZDUMP_OPTS= -v -a -d $(ZDUMPOUT) -c 1902,2038 -i
+ICUZDUMP_OPTS= -a -d $(ICUZDUMPOUT)
ifeq ($(TZDATA),)
all:
- @echo ERROR tzdata*.tar.gz can\'t be found.
+ @echo ERROR "tzdata*.tar.gz" can\'t be found.
@false
else
all: icu_data
endif
+TZCODE_TARGETS= tzorig check-dump
+
+ifeq ($(TZCODE),)
+# we're broken.
+$(TZCODE_TARGETS):
+ @echo ERROR "tzcode*.tar.gz" can\'t be found.
+ @false
+
+else
+ifeq ($(TZDATA),)
+# we're broken.
+$(TZCODE_TARGETS):
+ @echo ERROR "tzdata*.tar.gz" can\'t be found.
+ @false
+else
+tzorig: $(TZCODE) $(TZDATA)
+ -$(RMV) ./tzorig/
+ mkdir $@
+ mkdir $(TZORIG_TZDIR)
+ gunzip -d < $(TZDATA) | ( cd $@ ; tar xf - )
+ gunzip -d < $(TZCODE) | ( cd $@ ; tar xf - )
+ -mv $(TZORIG)/zdump.c $(TZORIG)/zdump.c.orig
+ cp $(srcdir)/zdump.c $(TZORIG)/zdump.c
+ -mv $(TZORIG)/factory $(TZORIG)/factory.orig
+ cat $(TZORIG)/factory.orig $(srcdir)/icuzones > $(TZORIG)/factory
+ $(MAKE) -C $@ $(TZORIG_OPTS) zdump zones
+
+$(ZDUMPOUT): tzorig
+ ( cd $(TZORIG) ; ./zdump$(EXEEXT) $(ZDUMP_OPTS) )
+
+
+dump-out: $(ZDUMPOUT) $(ICUZDUMPOUT)
+
+check-dump: dump-out
+ diff -r zdumpout icuzdumpout
+
+endif
+endif
+
+$(ICUZDUMPOUT): icuzdump$(EXEEXT)
+ -$(RMV) $(ICUZDUMPOUT)
+ -mkdir $(ICUZDUMPOUT)
+ $(INVOKE) ./icuzdump $(ICUZDUMP_OPTS)
+
+
+#
+# old 'tz' rules start here
+#
+
+
PRIMARY_YDATA= africa antarctica asia australasia \
europe northamerica southamerica
YDATA= $(PRIMARY_YDATA) pacificnew etcetera factory backward
NDATA= systemv
SDATA= solar87 solar88 solar89
-TDATA= $(YDATA) $(NDATA) $(SDATA)
+TDATA= $(YDATA) $(NDATA) $(SDATA)
YEARISTYPE= ./yearistype
ZIC = ./zic
TZDIR=zoneinfo
CFLAGS+=-D_POSIX_C_SOURCE
-CPPFLAGS+= -DTZDIR=\"$(TZDIR)\"
+CPPFLAGS+= -DTZDIR=\"$(TZDIR)\"
# more data
XDATA=zone.tab yearistype.sh leapseconds iso3166.tab
ICUDATA=ZoneMetaData.java icu_zone.txt tz2icu zoneinfo.txt
-
-
zic: $(OBJECTS) yearistype $(srcdir)/tz2icu.h
- $(CC) $(CFLAGS) $(LFLAGS) -I$(srcdir) $(OBJECTS) $(LDLIBS) -o $@
+ $(CC) $(CFLAGS) $(TZORIG_EXTRA_CFLAGS) $(LFLAGS) -I$(srcdir) $(OBJECTS) $(LDLIBS) -o $@
tz2icu: $(srcdir)/tz2icu.cpp $(srcdir)/tz2icu.h
- $(CXX) -W -Wall -I$(srcdir) -pedantic $(srcdir)/tz2icu.cpp -o $@
+ $(CXX) -W -Wall -I$(srcdir) -I$(top_srcdir)/common -pedantic $(srcdir)/tz2icu.cpp -o $@
+
+icuzdump${EXEEXT}: $(srcdir)/icuzdump.cpp
+ $(LINK.cc) -I$(srcdir) -I$(top_srcdir)/common -I$(top_srcdir)/i18n -I$(top_srcdir)/tools/toolutil -I$(top_srcdir)/io -pedantic $(srcdir)/icuzdump.cpp $(LIBICUUC) $(LIBICUDT) $(LIBICUI18N) $(LIBICUIO) $(LIBICUTOOLUTIL) -o $@
+
+
+# $(CXX) -W -Wall -I$(srcdir) -I$(top_srcdir)/common -pedantic $(srcdir)/icuzdump.cpp -o $@
yearistype.sh: $(TZDATA)
gunzip -d < $(TZDATA) | tar xf -
cp yearistype.sh yearistype
chmod +x yearistype
-tz.alias: $(srcdir)/tz.alias
- cp $< .
+posix_only: zic $(TDATA) $(srcdir)/icuzones
+ $(ZIC) -y $(YEARISTYPE) -d $(TZDIR) -L /dev/null $(TDATA) $(srcdir)/icuzones
-posix_only: zic $(TDATA)
- $(ZIC) -y $(YEARISTYPE) -d $(TZDIR) -L /dev/null $(TDATA)
-
-icu_data: tz2icu posix_only tz.alias
+icu_data: tz2icu posix_only
./tz2icu $(TZDIR) zone.tab `echo $(TZDATA) | sed -e "s/.*\/tzdata//;s/\.tar\.gz$$//"`
clean:
- -rm -f core *.o *.out zdump zic yearistype date
+ -rm -f core *.o *.out zdump${EXEEXT} zic${EXEEXT} yearistype date tz2icu${EXEEXT}
@echo ICU specific cleanup:
-rm -f $(ICUDATA)
-rm -rf $(TZDIR)
-ifneq ($(srcdir),.)
- -$(RMV) tz.alias
-endif
+ -$(RMV) icuzdump${EXEEXT} tzorig ./zdumpout/ ./icuzdumpout/
ifneq ($(TZDATA),)
-rm -rf `gunzip -d < $(TZDATA) | tar tf - | grep -o '[^ ]*$$' | tr '\n' ' '`
endif
+checkclean:
+
dataclean: clean
-rm -f $(TDATA) $(XDATA)
--- /dev/null
+/*
+*******************************************************************************
+*
+* Copyright (C) 2007, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+*******************************************************************************
+* file name: icuzdump.cpp
+* encoding: US-ASCII
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2007-04-02
+* created by: Yoshito Umaoka
+*
+* This tool write out timezone transitions for ICU timezone. This tool
+* is used as a part of tzdata update process to check if ICU timezone
+* code works as well as the corresponding Olson stock localtime/zdump.
+*/
+
+#include <cstdlib>
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+#include "unicode/utypes.h"
+#include "unicode/ustring.h"
+#include "unicode/timezone.h"
+#include "unicode/simpletz.h"
+#include "unicode/smpdtfmt.h"
+#include "unicode/decimfmt.h"
+#include "unicode/gregocal.h"
+#include "unicode/ustream.h"
+#include "unicode/putil.h"
+
+#include "uoptions.h"
+
+using namespace std;
+
+class DumpFormatter {
+public:
+ DumpFormatter() {
+ UErrorCode status = U_ZERO_ERROR;
+ stz = new SimpleTimeZone(0, "");
+ sdf = new SimpleDateFormat((UnicodeString)"yyyy-MM-dd EEE HH:mm:ss", Locale::getEnglish(), status);
+ DecimalFormatSymbols *symbols = new DecimalFormatSymbols(Locale::getEnglish(), status);
+ decf = new DecimalFormat("00", symbols, status);
+ }
+ ~DumpFormatter() {
+ }
+
+ UnicodeString& format(UDate time, int32_t offset, UBool isDst, UnicodeString& appendTo) {
+ stz->setRawOffset(offset);
+ sdf->setTimeZone(*stz);
+ UnicodeString str = sdf->format(time, appendTo);
+ if (offset < 0) {
+ appendTo += "-";
+ offset = -offset;
+ } else {
+ appendTo += "+";
+ }
+
+ int32_t hour, min, sec;
+
+ offset /= 1000;
+ sec = offset % 60;
+ offset = (offset - sec) / 60;
+ min = offset % 60;
+ hour = offset / 60;
+
+ decf->format(hour, appendTo);
+ decf->format(min, appendTo);
+ decf->format(sec, appendTo);
+ appendTo += "[DST=";
+ if (isDst) {
+ appendTo += "1";
+ } else {
+ appendTo += "0";
+ }
+ appendTo += "]";
+ return appendTo;
+ }
+private:
+ SimpleTimeZone* stz;
+ SimpleDateFormat* sdf;
+ DecimalFormat* decf;
+};
+
+class ICUZDump {
+public:
+ ICUZDump() {
+ formatter = new DumpFormatter();
+ loyear = 1902;
+ hiyear = 2050;
+ tick = 1000;
+ linesep = NULL;
+ }
+
+ ~ICUZDump() {
+ }
+
+ void setLowYear(int32_t lo) {
+ loyear = lo;
+ }
+
+ void setHighYear(int32_t hi) {
+ hiyear = hi;
+ }
+
+ void setTick(int32_t t) {
+ tick = t;
+ }
+
+ void setTimeZone(TimeZone* tz) {
+ timezone = tz;
+ }
+
+ void setDumpFormatter(DumpFormatter* fmt) {
+ formatter = fmt;
+ }
+
+ void setLineSeparator(const char* sep) {
+ linesep = sep;
+ }
+
+ void dump(ostream& out) {
+ UErrorCode status = U_ZERO_ERROR;
+ UDate SEARCH_INCREMENT = 12 * 60 * 60 * 1000; // half day
+ UDate t, cutlo, cuthi;
+ int32_t rawOffset, dstOffset;
+ UnicodeString str;
+
+ getCutOverTimes(cutlo, cuthi);
+ t = cutlo;
+ timezone->getOffset(t, FALSE, rawOffset, dstOffset, status);
+ while (t < cuthi) {
+ int32_t newRawOffset, newDstOffset;
+ UDate newt = t + SEARCH_INCREMENT;
+
+ timezone->getOffset(newt, FALSE, newRawOffset, newDstOffset, status);
+
+ UBool bSameOffset = (rawOffset + dstOffset) == (newRawOffset + newDstOffset);
+ UBool bSameDst = ((dstOffset != 0) && (newDstOffset != 0)) || ((dstOffset == 0) && (newDstOffset == 0));
+
+ if (!bSameOffset || !bSameDst) {
+ // find the boundary
+ UDate lot = t;
+ UDate hit = newt;
+ while (true) {
+ int32_t diff = (int32_t)(hit - lot);
+ if (diff <= tick) {
+ break;
+ }
+ UDate medt = lot + ((diff / 2) / tick) * tick;
+ int32_t medRawOffset, medDstOffset;
+ timezone->getOffset(medt, FALSE, medRawOffset, medDstOffset, status);
+
+ bSameOffset = (rawOffset + dstOffset) == (medRawOffset + medDstOffset);
+ bSameDst = ((dstOffset != 0) && (medDstOffset != 0)) || ((dstOffset == 0) && (medDstOffset == 0));
+
+ if (!bSameOffset || !bSameDst) {
+ hit = medt;
+ } else {
+ lot = medt;
+ }
+ }
+ // write out the boundary
+ str.remove();
+ formatter->format(lot, rawOffset + dstOffset, (dstOffset == 0 ? FALSE : TRUE), str);
+ out << str << " > ";
+ str.remove();
+ formatter->format(hit, newRawOffset + newDstOffset, (newDstOffset == 0 ? FALSE : TRUE), str);
+ out << str;
+ if (linesep != NULL) {
+ out << linesep;
+ } else {
+ out << endl;
+ }
+
+ rawOffset = newRawOffset;
+ dstOffset = newDstOffset;
+ }
+ t = newt;
+ }
+ }
+
+private:
+ void getCutOverTimes(UDate& lo, UDate& hi) {
+ UErrorCode status = U_ZERO_ERROR;
+ GregorianCalendar* gcal = new GregorianCalendar(timezone, Locale::getEnglish(), status);
+ gcal->clear();
+ gcal->set(loyear, 0, 1, 0, 0, 0);
+ lo = gcal->getTime(status);
+ gcal->set(hiyear, 0, 1, 0, 0, 0);
+ hi = gcal->getTime(status);
+ }
+
+ void dumpZone(ostream& out, const char* linesep, UnicodeString tzid, int32_t low, int32_t high) {
+ }
+
+ TimeZone* timezone;
+ int32_t loyear;
+ int32_t hiyear;
+ int32_t tick;
+
+ DumpFormatter* formatter;
+ const char* linesep;
+};
+
+class ZoneIterator {
+public:
+ ZoneIterator(UBool bAll = FALSE) {
+ if (bAll) {
+ zenum = TimeZone::createEnumeration();
+ }
+ else {
+ zenum = NULL;
+ zids = NULL;
+ idx = 0;
+ numids = 1;
+ }
+ }
+
+ ZoneIterator(const char** ids, int32_t num) {
+ zenum = NULL;
+ zids = ids;
+ idx = 0;
+ numids = num;
+ }
+
+ ~ZoneIterator() {
+ if (zenum != NULL) {
+ delete zenum;
+ }
+ }
+
+ TimeZone* next() {
+ TimeZone* tz = NULL;
+ if (zenum != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ const UnicodeString* zid = zenum->snext(status);
+ if (zid != NULL) {
+ tz = TimeZone::createTimeZone(*zid);
+ }
+ }
+ else {
+ if (idx < numids) {
+ if (zids != NULL) {
+ tz = TimeZone::createTimeZone((const UnicodeString&)zids[idx]);
+ }
+ else {
+ tz = TimeZone::createDefault();
+ }
+ idx++;
+ }
+ }
+ return tz;
+ }
+
+private:
+ const char** zids;
+ StringEnumeration* zenum;
+ int32_t idx;
+ int32_t numids;
+};
+
+enum {
+ kOptHelpH = 0,
+ kOptHelpQuestionMark,
+ kOptAllZones,
+ kOptCutover,
+ kOptDestDir,
+ kOptLineSep
+};
+
+static UOption options[]={
+ UOPTION_HELP_H,
+ UOPTION_HELP_QUESTION_MARK,
+ UOPTION_DEF("allzones", 'a', UOPT_NO_ARG),
+ UOPTION_DEF("cutover", 'c', UOPT_REQUIRES_ARG),
+ UOPTION_DEF("destdir", 'd', UOPT_REQUIRES_ARG),
+ UOPTION_DEF("linesep", 'l', UOPT_REQUIRES_ARG)
+};
+
+extern int
+main(int argc, char *argv[]) {
+ int32_t low = 1902;
+ int32_t high = 2038;
+ UBool bAll = FALSE;
+ const char *dir = NULL;
+ const char *linesep = NULL;
+
+ U_MAIN_INIT_ARGS(argc, argv);
+ argc = u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
+
+ if (argc < 0) {
+ cerr << "Illegal command line argument(s)" << endl << endl;
+ }
+
+ if (argc < 0 || options[kOptHelpH].doesOccur || options[kOptHelpQuestionMark].doesOccur) {
+ cerr
+ << "Usage: icuzdump [-options] [zoneid1 zoneid2 ...]" << endl
+ << endl
+ << "\tDump all offset transitions for the specified zones." << endl
+ << endl
+ << "Options:" << endl
+ << "\t-a : Dump all available zones." << endl
+ << "\t-d <dir> : When specified, write transitions in a file under" << endl
+ << "\t the directory for each zone." << endl
+ << "\t-l <sep> : New line code type used in file outputs. CR or LF (default)"
+ << "\t or CRLF." << endl
+ << "\t-c [<low_year>,]<high_year>" << endl
+ << "\t : When specified, dump transitions starting <low_year>" << endl
+ << "\t (inclusive) up to <high_year> (exclusive). The default" << endl
+ << "\t values are 1902(low) and 2038(high)." << endl;
+ return argc < 0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
+ }
+
+ bAll = options[kOptAllZones].doesOccur;
+
+ if (options[kOptDestDir].doesOccur) {
+ dir = options[kOptDestDir].value;
+ }
+
+ if (options[kOptLineSep].doesOccur) {
+ if (strcmp(options[kOptLineSep].value, "CR") == 0) {
+ linesep = "\r";
+ } else if (strcmp(options[kOptLineSep].value, "CRLF") == 0) {
+ linesep = "\r\n";
+ } else if (strcmp(options[kOptLineSep].value, "LF") == 0) {
+ linesep = "\n";
+ }
+ }
+
+ if (options[kOptCutover].doesOccur) {
+ char* comma = (char*)strchr(options[kOptCutover].value, ',');
+ if (comma == NULL) {
+ high = atoi(options[kOptCutover].value);
+ } else {
+ *comma = 0;
+ low = atoi(options[kOptCutover].value);
+ high = atoi(comma + 1);
+ }
+ }
+
+ ICUZDump dumper;
+ dumper.setLowYear(low);
+ dumper.setHighYear(high);
+ if (dir != NULL && linesep != NULL) {
+ // use the specified line separator only for file output
+ dumper.setLineSeparator((const char*)linesep);
+ }
+
+ ZoneIterator* zit;
+ if (bAll) {
+ zit = new ZoneIterator(TRUE);
+ } else {
+ if (argc <= 1) {
+ zit = new ZoneIterator();
+ } else {
+ zit = new ZoneIterator((const char**)&argv[1], argc - 1);
+ }
+ }
+
+ UnicodeString id;
+ if (dir != NULL) {
+ // file output
+ ostringstream path;
+ ios::openmode mode = ios::out;
+ if (linesep != NULL) {
+ mode |= ios::binary;
+ }
+ for (;;) {
+ TimeZone* tz = zit->next();
+ if (tz == NULL) {
+ break;
+ }
+ dumper.setTimeZone(tz);
+ tz->getID(id);
+
+ // target file path
+ path.str("");
+ path << dir << U_FILE_SEP_CHAR;
+ id = id.findAndReplace("/", "-");
+ path << id;
+
+ ofstream* fout = new ofstream(path.str().c_str(), mode);
+ if (fout->fail()) {
+ cerr << "Cannot open file " << path << endl;
+ delete fout;
+ delete tz;
+ break;
+ }
+
+ dumper.dump(*fout);
+ fout->close();
+ delete fout;
+ delete tz;
+ }
+
+ } else {
+ // stdout
+ UBool bFirst = TRUE;
+ for (;;) {
+ TimeZone* tz = zit->next();
+ if (tz == NULL) {
+ break;
+ }
+ dumper.setTimeZone(tz);
+ tz->getID(id);
+ if (bFirst) {
+ bFirst = FALSE;
+ } else {
+ cout << endl;
+ }
+ cout << "ZONE: " << id << endl;
+ dumper.dump(cout);
+ delete tz;
+ }
+ }
+ delete zit;
+}
--- /dev/null
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="icuzdump"
+ ProjectGUID="{655F4481-B461-4DF0-AF10-0D01114A26C1}"
+ RootNamespace="icuzdump"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\x86\Debug"
+ IntermediateDirectory=".\x86\Debug"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="copy "$(TargetPath)" ..\..\..\bin
"
+ Outputs="..\..\..\bin\$(TargetFileName)"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\include;..\toolutil,..\..\common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_DEPRECATE"
+ MinimalRebuild="false"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="true"
+ UsePrecompiledHeader="0"
+ PrecompiledHeaderFile=".\x86\Debug/icuzdump.pch"
+ AssemblerListingLocation=".\x86\Debug/"
+ ObjectFile=".\x86\Debug/"
+ ProgramDataBaseFileName=".\x86\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="icuucd.lib icuind.lib icutud.lib icuiod.lib"
+ OutputFile=".\x86\Debug/icuzdump.exe"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="..\..\..\lib"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile=".\x86\Debug/icuzdump.pdb"
+ SubSystem="1"
+ TargetMachine="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ UseFAT32Workaround="true"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\icuzdump.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- /dev/null
+######################################################################
+# Copyright (C) 2007-2008, International Business Machines
+# Corporation and others. All Rights Reserved.
+######################################################################
+# This is an ICU-specific file with the same format as regular
+# tzdata time zone files, for consistent parsing by the tools that
+# turn "Olson" tzdata into ICU's zoneinfo.txt.
+# The purpose of this file is to give ICU a superset of the time zones
+# that are in CLDR and also include legacy ICU time zones originally
+# in tz.alias for rataining backward compatibility.
+
+# Add Etc/Unknown, defined by CLDR. Give it Etc/GMT behavior.
+
+# Zone NAME GMTOFF RULES FORMAT
+Zone Etc/Unknown 0 - Unknown
+
+# Add SystemV/XXX time zones as aliases according to CLDR.
+# The Olson systemv file has these commented out.
+# An alternative to making these aliases according to CLDR would be
+# to copy and un-comment the data from the systemv file.
+
+# Link canonical alias
+Link America/Halifax SystemV/AST4ADT
+Link America/New_York SystemV/EST5EDT
+Link America/Chicago SystemV/CST6CDT
+Link America/Denver SystemV/MST7MDT
+Link America/Los_Angeles SystemV/PST8PDT
+Link America/Anchorage SystemV/YST9YDT
+Link Etc/GMT+4 SystemV/AST4
+Link Etc/GMT+5 SystemV/EST5
+Link Etc/GMT+6 SystemV/CST6
+Link Etc/GMT+7 SystemV/MST7
+Link Etc/GMT+8 SystemV/PST8
+Link Etc/GMT+9 SystemV/YST9
+Link Etc/GMT+10 SystemV/HST10
+
+
+# The list below is for supporting legacy ICU zone aliases.
+# These definitions were originally defined in tz.alias.
+
+#### Aliases that conflict with Olson compatibility Zone definition
+
+Link Australia/Darwin ACT
+Link Australia/Sydney AET
+Link America/Argentina/Buenos_Aires AGT
+Link Africa/Cairo ART
+Link America/Anchorage AST
+Link America/Sao_Paulo BET
+Link Asia/Dhaka BST
+Link Africa/Harare CAT
+Link America/St_Johns CNT
+Link America/Chicago CST
+Link Asia/Shanghai CTT
+Link Africa/Addis_Ababa EAT
+Link Europe/Paris ECT
+#Link Europe/Istanbul EET # EET is a standard UNIX zone
+####Link EST America/New_York EST # Defined as -05:00
+####Link Pacific/Honolulu HST # Defined as -10:00
+Link America/Indiana/Indianapolis IET
+Link Asia/Kolkata IST
+Link Asia/Tokyo JST
+#Link Asia/Tehran MET # MET is a standard UNIX zone
+Link Pacific/Apia MIT
+####Link America/Denver MST # Defined as -07:00
+Link Asia/Yerevan NET
+Link Pacific/Auckland NST
+Link Asia/Karachi PLT
+Link America/Phoenix PNT
+Link America/Puerto_Rico PRT
+Link America/Los_Angeles PST
+Link Pacific/Guadalcanal SST
+#Link Etc/UTC UTC # Olson LINK
+Link Asia/Ho_Chi_Minh VST
**********************************************************************
-* Copyright (c) 2003-2006, International Business Machines
+* Copyright (c) 2003-2007, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
References:
-ICU4C: http://icu.sourceforge.net/
+ICU4C: http://www.icu-project.org/
Olson: ftp://elsie.nci.nih.gov/pub/
----------------------------------------------------------------------
0. Note, these instructions will only work on POSIX type systems.
-1. Obtain the current versions of tzdataYYYYV.tar.gz (aka `tzdata') from the FTP site given
- above. Either manually download or use wget:
+1. Obtain the current versions of tzdataYYYYV.tar.gz (aka `tzdata') from
+ the FTP site given above. Either manually download or use wget:
$ cd {path_to}/icu/source/tools/tzcode
$ wget "ftp://elsie.nci.nih.gov/pub/tzdata*.tar.gz"
-2. copy only one tzdata*.tar.gz file into the icu/source/data/in/ directory (you may have to create this directory)
+2. Copy only one tzdata*.tar.gz file into the icu/source/tools/tzcode/
+ directory (this directory).
*** Make sure you only have ONE FILE named tzdata*.tar.gz in the
directory.
3. Build ICU normally. You will see a notice "updating zoneinfo.txt..."
-4. For ICU maintainers, don't forget to check in the new
- zoneinfo.txt (from its location at
- {path_to}/icu/source/data/misc/zoneinfo.txt) into CVS.
+### Following instructions for ICU maintainers only ###
+
+4. Obtain the current version of tzcodeYYYY.tar.gz from the FTP site to
+ this directory.
+
+5. Run make target "check-dump". This target extract makes the original
+ tzcode and compile the original tzdata with icu supplemental data
+ (icuzones). Then it makes zdump / icuzdump and dump all time
+ transitions for all ICU timezone to files under zdumpout / icuzdumpout
+ directory. When they produce different results, the target returns
+ the error.
+
+6. Don't forget to check in the new zoneinfo.txt (from its location at
+ {path_to}/icu/source/data/misc/zoneinfo.txt) into SVN.
+
+#
+# !!!! WARNING !!!!!
+#
+# This file is OBSOLLETE and no longer used by ICU tzdata build tool.
+# Use the file 'icuzones' to specify backward compatibility aliases.
+#
+# 2007-04-03 Yoshito Umaoka
+#
+
######################################################################
-# Copyright (C) 1999-2006, International Business Machines
+# Copyright (C) 1999-2007, International Business Machines
# Corporation and others. All Rights Reserved.
######################################################################
# A simple alias list. We use this to retain backward compatibility.
#
# Format: alias_name unix_name # optional comment
-#### Aliases that conflict with Olson compatibility links
+#### Aliases that conflict with Olson compatibility Zone definition
ACT Australia/Darwin
AET Australia/Sydney
EAT Africa/Addis_Ababa
ECT Europe/Paris
# EET Europe/Istanbul # EET is a standard UNIX zone
-#### EST America/New_York # Linked to America/Indianapolis in Olson
-HST Pacific/Honolulu # Olson LINK - was removed 2005-Nov-21, confirmed gone in 2006a.
+#### EST America/New_York # Defined as -05:00
+#### HST Pacific/Honolulu # Defined as -10:00
IET America/Indianapolis
IST Asia/Calcutta
JST Asia/Tokyo
# MET Asia/Tehran # MET is a standard UNIX zone
MIT Pacific/Apia
-#### MST America/Denver # Linked to America/Phoenix in Olson
+#### MST America/Denver # Defined as -07:00
NET Asia/Yerevan
NST Pacific/Auckland
PLT Asia/Karachi
/*
**********************************************************************
-* Copyright (c) 2003-2006, International Business Machines
+* Copyright (c) 2003-2008, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
#include "tz2icu.h"
#include "unicode/uversion.h"
+#define USE64BITDATA
+
using namespace std;
//--------------------------------------------------------------------
// Time utilities
//--------------------------------------------------------------------
-const long SECS_PER_YEAR = 31536000; // 365 days
-const long SECS_PER_LEAP_YEAR = 31622400; // 366 days
+const int64_t SECS_PER_YEAR = 31536000; // 365 days
+const int64_t SECS_PER_LEAP_YEAR = 31622400; // 366 days
+const int64_t LOWEST_TIME32 = (int64_t)((int32_t)0x80000000);
+const int64_t HIGHEST_TIME32 = (int64_t)((int32_t)0x7fffffff);
-bool isLeap(int y) {
+bool isLeap(int32_t y) {
return (y%4 == 0) && ((y%100 != 0) || (y%400 == 0)); // Gregorian
}
-long secsPerYear(int y) {
+int64_t secsPerYear(int32_t y) {
return isLeap(y) ? SECS_PER_LEAP_YEAR : SECS_PER_YEAR;
}
* Given a calendar year, return the GMT epoch seconds for midnight
* GMT of January 1 of that year. yearToSeconds(1970) == 0.
*/
-long yearToSeconds(int year) {
+int64_t yearToSeconds(int32_t year) {
// inefficient but foolproof
- long s = 0;
- int y = 1970;
+ int64_t s = 0;
+ int32_t y = 1970;
while (y < year) {
s += secsPerYear(y++);
}
* Given 1970 GMT epoch seconds, return the calendar year containing
* that time. secondsToYear(0) == 1970.
*/
-int secondsToYear(long seconds) {
+int32_t secondsToYear(int64_t seconds) {
// inefficient but foolproof
- int y = 1970;
- long s = 0;
+ int32_t y = 1970;
+ int64_t s = 0;
if (seconds >= 0) {
for (;;) {
s += secsPerYear(y++);
// A transition from one ZoneType to another
// Minimal size = 5 bytes (4+1)
struct Transition {
- long time; // seconds, 1970 epoch
- int type; // index into 'ZoneInfo.types' 0..255
- Transition(long _time, int _type) {
+ int64_t time; // seconds, 1970 epoch
+ int32_t type; // index into 'ZoneInfo.types' 0..255
+ Transition(int64_t _time, int32_t _type) {
time = _time;
type = _type;
}
// Minimal size = 6 bytes (4+1+3bits)
// SEE: SimplifiedZoneType
struct ZoneType {
- long rawoffset; // raw seconds offset from GMT
- long dstoffset; // dst seconds offset from GMT
+ int64_t rawoffset; // raw seconds offset from GMT
+ int64_t dstoffset; // dst seconds offset from GMT
// We don't really need any of the following, but they are
// retained for possible future use. See SimplifiedZoneType.
- int abbr; // index into ZoneInfo.abbrs 0..n-1
+ int32_t abbr; // index into ZoneInfo.abbrs 0..n-1
bool isdst;
bool isstd;
bool isgmt;
vector<string> abbrs;
string finalRuleID;
- int finalOffset;
- int finalYear; // -1 if none
+ int32_t finalOffset;
+ int32_t finalYear; // -1 if none
// If this is an alias, then all other fields are meaningless, and
// this field will point to the "real" zone 0..n-1.
- int aliasTo; // -1 if this is a "real" zone
+ int32_t aliasTo; // -1 if this is a "real" zone
// If there are aliases TO this zone, then the following set will
// contain their index numbers (each index >= 0).
- set<int> aliases;
+ set<int32_t> aliases;
ZoneInfo() : finalYear(-1), aliasTo(-1) {}
void optimizeTypeList();
// Set this zone to be an alias TO another zone.
- void setAliasTo(int index);
+ void setAliasTo(int32_t index);
// Clear the list of aliases OF this zone.
void clearAliases();
// Add an alias to the list of aliases OF this zone.
- void addAlias(int index);
+ void addAlias(int32_t index);
// Is this an alias to another zone?
bool isAlias() const {
}
// Retrieve alias list
- const set<int>& getAliases() const {
+ const set<int32_t>& getAliases() const {
return aliases;
}
aliases.clear();
}
-void ZoneInfo::addAlias(int index) {
+void ZoneInfo::addAlias(int32_t index) {
assert(aliasTo < 0 && index >= 0 && aliases.find(index) == aliases.end());
aliases.insert(index);
}
-void ZoneInfo::setAliasTo(int index) {
+void ZoneInfo::setAliasTo(int32_t index) {
assert(index >= 0);
assert(aliases.size() == 0);
aliasTo = index;
//--------------------------------------------------------------------
// Read zic-coded 32-bit integer from file
-long readcoded(ifstream& file, long minv=numeric_limits<long>::min(),
- long maxv=numeric_limits<long>::max()) {
+int64_t readcoded(ifstream& file, int64_t minv=numeric_limits<int64_t>::min(),
+ int64_t maxv=numeric_limits<int64_t>::max()) {
unsigned char buf[4]; // must be UNSIGNED
- long val=0;
+ int64_t val=0;
file.read((char*)buf, 4);
- for(int i=0,shift=24;i<4;++i,shift-=8) {
+ for(int32_t i=0,shift=24;i<4;++i,shift-=8) {
val |= buf[i] << shift;
}
if (val < minv || val > maxv) {
return val;
}
+// Read zic-coded 64-bit integer from file
+int64_t readcoded64(ifstream& file, int64_t minv=numeric_limits<int64_t>::min(),
+ int64_t maxv=numeric_limits<int64_t>::max()) {
+ unsigned char buf[8]; // must be UNSIGNED
+ int64_t val=0;
+ file.read((char*)buf, 8);
+ for(int32_t i=0,shift=56;i<8;++i,shift-=8) {
+ val |= (int64_t)buf[i] << shift;
+ }
+ if (val < minv || val > maxv) {
+ ostringstream os;
+ os << "coded value out-of-range: " << val << ", expected ["
+ << minv << ", " << maxv << "]";
+ throw out_of_range(os.str());
+ }
+ return val;
+}
+
// Read a boolean value
bool readbool(ifstream& file) {
char c;
file.read(&c, 1);
if (c!=0 && c!=1) {
ostringstream os;
- os << "boolean value out-of-range: " << (int)c;
+ os << "boolean value out-of-range: " << (int32_t)c;
throw out_of_range(os.str());
}
return (c!=0);
* Read the zoneinfo file structure (see tzfile.h) into a ZoneInfo
* @param file an already-open file stream
*/
-void readzoneinfo(ifstream& file, ZoneInfo& info) {
- int i;
+void readzoneinfo(ifstream& file, ZoneInfo& info, bool is64bitData=false) {
+ int32_t i;
// Check for TZ_ICU_MAGIC signature at file start. If we get a
// signature mismatch, it means we're trying to read a file which
}
// Read array sizes
- long isgmtcnt = readcoded(file, 0);
- long isdstcnt = readcoded(file, 0);
- long leapcnt = readcoded(file, 0);
- long timecnt = readcoded(file, 0);
- long typecnt = readcoded(file, 0);
- long charcnt = readcoded(file, 0);
+ int64_t isgmtcnt = readcoded(file, 0);
+ int64_t isdstcnt = readcoded(file, 0);
+ int64_t leapcnt = readcoded(file, 0);
+ int64_t timecnt = readcoded(file, 0);
+ int64_t typecnt = readcoded(file, 0);
+ int64_t charcnt = readcoded(file, 0);
// Confirm sizes that we assume to be equal. These assumptions
// are drawn from a reading of the zic source (2003a), so they
// Used temporarily to store transition times and types. We need
// to do this because the times and types are stored in two
// separate arrays.
- vector<long> transitionTimes(timecnt, -1); // temporary
- vector<int> transitionTypes(timecnt, -1); // temporary
+ vector<int64_t> transitionTimes(timecnt, -1); // temporary
+ vector<int32_t> transitionTypes(timecnt, -1); // temporary
// Read transition times
for (i=0; i<timecnt; ++i) {
- transitionTimes[i] = readcoded(file);
+ if (is64bitData) {
+ transitionTimes[i] = readcoded64(file);
+ } else {
+ transitionTimes[i] = readcoded(file);
+ }
}
// Read transition types
for (i=0; i<timecnt; ++i) {
unsigned char c;
file.read((char*) &c, 1);
- int t = (int) c;
+ int32_t t = (int32_t) c;
if (t < 0 || t >= typecnt) {
ostringstream os;
os << "illegal type: " << t << ", expected [0, " << (typecnt-1) << "]";
}
// Build transitions vector out of corresponding times and types.
- for (i=0; i<timecnt; ++i) {
- info.transitions.push_back(Transition(transitionTimes[i], transitionTypes[i]));
+ bool insertInitial = false;
+ if (is64bitData) {
+ if (timecnt > 0) {
+ int32_t minidx = -1;
+ for (i=0; i<timecnt; ++i) {
+ if (transitionTimes[i] < LOWEST_TIME32) {
+ if (minidx == -1 || transitionTimes[i] > transitionTimes[minidx]) {
+ // Preserve the latest transition before the 32bit minimum time
+ minidx = i;
+ }
+ } else if (transitionTimes[i] > HIGHEST_TIME32) {
+ // Skipping the rest of the transition data. We cannot put such
+ // transitions into zoneinfo.res, because data is limited to singed
+ // 32bit int by the ICU resource bundle.
+ break;
+ } else {
+ info.transitions.push_back(Transition(transitionTimes[i], transitionTypes[i]));
+ }
+ }
+
+ if (minidx != -1) {
+ // If there are any transitions before the 32bit minimum time,
+ // put the type information with the 32bit minimum time
+ vector<Transition>::iterator itr = info.transitions.begin();
+ info.transitions.insert(itr, Transition(LOWEST_TIME32, transitionTypes[minidx]));
+ } else {
+ // Otherwise, we need insert the initial type later
+ insertInitial = true;
+ }
+ }
+ } else {
+ for (i=0; i<timecnt; ++i) {
+ info.transitions.push_back(Transition(transitionTimes[i], transitionTypes[i]));
+ }
}
// Read types (except for the isdst and isgmt flags, which come later (why??))
unsigned char c;
file.read((char*) &c, 1);
- type.abbr = (int) c;
+ type.abbr = (int32_t) c;
if (type.isdst != (type.dstoffset != 0)) {
throw invalid_argument("isdst does not reflect dstoffset");
info.types.push_back(type);
}
+
assert(info.types.size() == (unsigned) typecnt);
+ if (insertInitial) {
+ assert(timecnt > 0);
+ assert(typecnt > 0);
+
+ int32_t initialTypeIdx = -1;
+
+ // Check if the first type is not dst
+ if (info.types.at(0).dstoffset != 0) {
+ // Initial type's rawoffset is same with the rawoffset after the
+ // first transition, but no DST is observed.
+ int64_t rawoffset0 = (info.types.at(info.transitions.at(0).type)).rawoffset;
+ // Look for matching type
+ for (i=0; i<(int32_t)info.types.size(); ++i) {
+ if (info.types.at(i).rawoffset == rawoffset0
+ && info.types.at(i).dstoffset == 0) {
+ initialTypeIdx = i;
+ break;
+ }
+ }
+ } else {
+ initialTypeIdx = 0;
+ }
+ assert(initialTypeIdx >= 0);
+ // Add the initial type associated with the lowest int32 time
+ vector<Transition>::iterator itr = info.transitions.begin();
+ info.transitions.insert(itr, Transition(LOWEST_TIME32, initialTypeIdx));
+ }
+
+
// Read the abbreviation string
if (charcnt) {
// All abbreviations are concatenated together, with a 0 at
// Split abbreviations apart into individual strings. Record
// offset of each abbr in a vector.
- vector<int> abbroffset;
+ vector<int32_t> abbroffset;
char *limit=str+charcnt;
for (char* p=str; p<limit; ++p) {
char* start = p;
for (vector<ZoneType>::iterator it=info.types.begin();
it!=info.types.end();
++it) {
- vector<int>::const_iterator x=
+ vector<int32_t>::const_iterator x=
find(abbroffset.begin(), abbroffset.end(), it->abbr);
if (x==abbroffset.end()) {
// TODO: Modify code to add a new string to the end of
ostringstream os;
os << "Warning: unusual abbr offset " << it->abbr
<< ", expected one of";
- for (vector<int>::const_iterator y=abbroffset.begin();
+ for (vector<int32_t>::const_iterator y=abbroffset.begin();
y!=abbroffset.end(); ++y) {
os << ' ' << *y;
}
#endif
it->abbr = 0;
} else {
- int index = x - abbroffset.begin();
+ int32_t index = x - abbroffset.begin();
it->abbr = index;
abbrseen[index] = true;
}
}
- for (int ii=0;ii<(int) abbrseen.size();++ii) {
+ for (int32_t ii=0;ii<(int32_t) abbrseen.size();++ii) {
if (!abbrseen[ii]) {
cerr << "Warning: unused abbreviation: " << ii << endl;
}
if (!file) {
throw invalid_argument("can't open file");
}
+
ZoneInfo info;
readzoneinfo(file, info);
throw invalid_argument("read error");
}
+#ifdef USE64BITDATA
+ ZoneInfo info64;
+ readzoneinfo(file, info64, true);
+
+ bool alldone = false;
+ int64_t eofPos = (int64_t) file.tellg();
+
+ // '\n' + <envvar string> + '\n' after the 64bit version data
+ char ch = file.get();
+ if (ch == 0x0a) {
+ bool invalidchar = false;
+ while (file.get(ch)) {
+ if (ch == 0x0a) {
+ break;
+ }
+ if (ch < 0x20) {
+ // must be printable ascii
+ invalidchar = true;
+ break;
+ }
+ }
+ if (!invalidchar) {
+ eofPos = (int64_t) file.tellg();
+ file.seekg(0, ios::end);
+ eofPos = eofPos - (int64_t) file.tellg();
+ if (eofPos == 0) {
+ alldone = true;
+ }
+ }
+ }
+ if (!alldone) {
+ ostringstream os;
+ os << (-eofPos) << " unprocessed bytes at end";
+ throw invalid_argument(os.str());
+ }
+
+ ZONEINFO[id] = info64;
+
+#else
// Check eof-relative pos (there may be a cleaner way to do this)
- long eofPos = (long) file.tellg();
+ int64_t eofPos = (int64_t) file.tellg();
char buf[32];
file.read(buf, 4);
file.seekg(0, ios::end);
- eofPos = eofPos - (long) file.tellg();
+ eofPos = eofPos - (int64_t) file.tellg();
if (eofPos) {
// 2006c merged 32 and 64 bit versions in a fat binary
// 64 version starts at the end of 32 bit version.
throw invalid_argument(os.str());
}
}
-
ZONEINFO[id] = info;
+#endif
}
/**
closedir(dp);
chdir(pwd);
- for(int i=0;i<(int)subfiles.size();i+=2) {
+ for(int32_t i=0;i<(int32_t)subfiles.size();i+=2) {
try {
handleFile(subfiles[i], subfiles[i+1]);
} catch (const exception& e) {
exit(1);
}
}
- for(int i=0;i<(int)subdirs.size();i+=2) {
+ for(int32_t i=0;i<(int32_t)subdirs.size();i+=2) {
scandir(subdirs[i], subdirs[i+1]);
}
}
* Read and discard the current line.
*/
void consumeLine(istream& in) {
- int c;
+ int32_t c;
do {
c = in.get();
} while (c != EOF && c != '\n');
// Allow 29 days in February because zic outputs February 29
// for rules like "last Sunday in February".
-const int MONTH_LEN[] = {31,29,31,30,31,30,31,31,30,31,30,31};
+const int32_t MONTH_LEN[] = {31,29,31,30,31,30,31,31,30,31,30,31};
-const int HOUR = 3600;
+const int32_t HOUR = 3600;
struct FinalZone {
- int offset; // raw offset
- int year; // takes effect for y >= year
+ int32_t offset; // raw offset
+ int32_t year; // takes effect for y >= year
string ruleid;
set<string> aliases;
- FinalZone(int _offset, int _year, const string& _ruleid) :
+ FinalZone(int32_t _offset, int32_t _year, const string& _ruleid) :
offset(_offset), year(_year), ruleid(_ruleid) {
if (offset <= -16*HOUR || offset >= 16*HOUR) {
ostringstream os;
};
struct FinalRulePart {
- int mode;
- int month;
- int dom;
- int dow;
- int time;
- int offset; // dst offset, usually either 0 or 1:00
+ int32_t mode;
+ int32_t month;
+ int32_t dom;
+ int32_t dow;
+ int32_t time;
+ int32_t offset; // dst offset, usually either 0 or 1:00
// Isstd and isgmt only have 3 valid states, corresponding to local
// wall time, local standard time, and GMT standard time.
FinalRulePart() : isset(false) {}
void set(const string& id,
const string& _mode,
- int _month,
- int _dom,
- int _dow,
- int _time,
+ int32_t _month,
+ int32_t _dom,
+ int32_t _dow,
+ int32_t _time,
bool _isstd,
bool _isgmt,
- int _offset) {
+ int32_t _offset) {
if (isset) {
throw invalid_argument("FinalRulePart set twice");
}
* Return the time mode as an ICU SimpleTimeZone int from 0..2;
* see simpletz.h.
*/
- int timemode() const {
+ int32_t timemode() const {
if (isgmt) {
assert(isstd);
return 2; // gmt standard
/**
* Return a "dowim" param suitable for SimpleTimeZone.
*/
- int stz_dowim() const {
+ int32_t stz_dowim() const {
return (mode == DOWLEQ) ? -dom : dom;
}
/**
* Return a "dow" param suitable for SimpleTimeZone.
*/
- int stz_dow() const {
+ int32_t stz_dow() const {
return (mode == DOM) ? 0 : -(dow+1);
}
};
} else if (token == "zone") {
// zone Africa/Cairo 7200 1995 Egypt # zone Africa/Cairo, offset 7200, year >= 1995, rule Egypt (0)
string id, ruleid;
- int offset, year;
+ int32_t offset, year;
in >> id >> offset >> year >> ruleid;
consumeLine(in);
finalZones[id] = FinalZone(offset, year, ruleid);
// rule US DOWGEQ 3 1 0 7200 0 0 3600 # 52: US, file data/northamerica, line 119, mode DOWGEQ, April, dom 1, Sunday, time 7200, isstd 0, isgmt 0, offset 3600
// rule US DOWLEQ 9 31 0 7200 0 0 0 # 53: US, file data/northamerica, line 114, mode DOWLEQ, October, dom 31, Sunday, time 7200, isstd 0, isgmt 0, offset 0
string id, mode;
- int month, dom, dow, time, offset;
+ int32_t month, dom, dow, time, offset;
bool isstd, isgmt;
in >> id >> mode >> month >> dom >> dow >> time >> isstd >> isgmt >> offset;
consumeLine(in);
FinalRule& fr = finalRules[id];
- int p = fr.part[0].isset ? 1 : 0;
+ int32_t p = fr.part[0].isset ? 1 : 0;
fr.part[p].set(id, mode, month, dom, dow, time, isstd, isgmt, offset);
} else if (token == "link") {
string fromid, toid; // fromid == "real" zone, toid == alias
if (aliases.size() != 0) {
first = true;
os << " :intvector { ";
- for (set<int>::const_iterator i=aliases.begin(); i!=aliases.end(); ++i) {
+ for (set<int32_t>::const_iterator i=aliases.begin(); i!=aliases.end(); ++i) {
if (!first) os << ", ";
first = false;
os << *i;
inline ostream&
operator<<(ostream& os, const ZoneMap& zoneinfo) {
- int c = 0;
+ int32_t c = 0;
for (ZoneMapIter it = zoneinfo.begin();
it != zoneinfo.end();
++it) {
// print the string list
ostream& printStringList( ostream& os, const ZoneMap& zoneinfo) {
- int n = 0; // count
- int col = 0; // column
+ int32_t n = 0; // count
+ int32_t col = 0; // column
os << " Names {" << endl
<< " ";
for (ZoneMapIter it = zoneinfo.begin();
//--------------------------------------------------------------------
// Unary predicate for finding transitions after a given time
-bool isAfter(const Transition t, long thresh) {
+bool isAfter(const Transition t, int64_t thresh) {
return t.time >= thresh;
}
* optimizeTypeList() method.
*/
struct SimplifiedZoneType {
- long rawoffset;
- long dstoffset;
+ int64_t rawoffset;
+ int64_t dstoffset;
SimplifiedZoneType() : rawoffset(-1), dstoffset(-1) {}
SimplifiedZoneType(const ZoneType& t) : rawoffset(t.rawoffset),
dstoffset(t.dstoffset) {}
set<SimplifiedZoneType> simpleset;
for (vector<Transition>::const_iterator i=transitions.begin();
i!=transitions.end(); ++i) {
- assert(i->type < (int)types.size());
+ assert(i->type < (int32_t)types.size());
simpleset.insert(types[i->type]);
}
// Map types to integer indices
- map<SimplifiedZoneType,int> simplemap;
- int n=0;
+ map<SimplifiedZoneType,int32_t> simplemap;
+ int32_t n=0;
for (set<SimplifiedZoneType>::const_iterator i=simpleset.begin();
i!=simpleset.end(); ++i) {
simplemap[*i] = n++;
// Remap transitions
for (vector<Transition>::iterator i=transitions.begin();
i!=transitions.end(); ++i) {
- assert(i->type < (int)types.size());
+ assert(i->type < (int32_t)types.size());
ZoneType oldtype = types[i->type];
SimplifiedZoneType newtype(oldtype);
assert(simplemap.find(newtype) != simplemap.end());
* Merge final zone data into this zone.
*/
void ZoneInfo::mergeFinalData(const FinalZone& fz) {
- int year = fz.year;
- long seconds = yearToSeconds(year);
+ int32_t year = fz.year;
+ int64_t seconds = yearToSeconds(year);
vector<Transition>::iterator it =
find_if(transitions.begin(), transitions.end(),
bind2nd(ptr_fun(isAfter), seconds));
void FinalRule::print(ostream& os) const {
// First print the rule part that enters DST; then the rule part
// that exits it.
- int whichpart = (part[0].offset != 0) ? 0 : 1;
+ int32_t whichpart = (part[0].offset != 0) ? 0 : 1;
assert(part[whichpart].offset != 0);
assert(part[1-whichpart].offset == 0);
os << " ";
- for (int i=0; i<2; ++i) {
+ for (int32_t i=0; i<2; ++i) {
const FinalRulePart& p = part[whichpart];
whichpart = 1-whichpart;
os << p.month << ", " << p.stz_dowim() << ", " << p.stz_dow() << ", "
return 1;
}
+//############################################################################
+//# Note: We no longer use tz.alias to define alias for legacy ICU time zones.
+//# The contents of tz.alias were migrated into zic source format and
+//# processed by zic as 'Link'.
+//############################################################################
+#if 0
// Read the legacy alias list and process it. Treat the legacy mappings
// like links, but also record them in the "legacy" hash.
try {
cerr << "Error: Unable to open " ICU_TZ_ALIAS << endl;
return 1;
}
- int n = 0;
+ int32_t n = 0;
string line;
while (getline(aliases, line)) {
string::size_type lb = line.find('#');
cerr << "Error: While reading " ICU_TZ_ALIAS ": " << error.what() << endl;
return 1;
}
-
+#endif
try {
// Recursively scan all files below the given path, accumulating
// their data into ZONEINFO. All files must be TZif files. Any
}
// 2. Create a mapping from zones to index numbers 0..n-1.
- map<string,int> zoneIDs;
+ map<string,int32_t> zoneIDs;
vector<string> zoneIDlist;
- int z=0;
+ int32_t z=0;
for (ZoneMap::iterator i=ZONEINFO.begin(); i!=ZONEINFO.end(); ++i) {
zoneIDs[i->first] = z++;
zoneIDlist.push_back(i->first);
}
- assert(z == (int) ZONEINFO.size());
+ assert(z == (int32_t) ZONEINFO.size());
// 3. Merge aliases. Sometimes aliases link to other aliases; we
// resolve these into simplest possible sets.
cerr << "Error: Unable to open " << zonetab << endl;
return 1;
}
- int n = 0;
+ int32_t n = 0;
string line;
while (getline(f, line)) {
string::size_type lb = line.find('#');
time_t sec;
time(&sec);
struct tm* now = localtime(&sec);
- int thisYear = now->tm_year + 1900;
+ int32_t thisYear = now->tm_year + 1900;
// Write out a resource-bundle source file containing data for
// all zones.
// Final Rules are used if requested by the zone
file << " Rules { " << endl;
// Emit final rules
- int frc = 0;
+ int32_t frc = 0;
for(map<string,FinalRule>::iterator i=finalRules.begin();
i!=finalRules.end(); ++i) {
const string& id = i->first;
// trims this to 171 kb. More work for the runtime code, but
// a smaller data footprint.
file << " Regions { " << endl;
- int rc = 0;
+ int32_t rc = 0;
for (map<string, set<string> >::const_iterator i=countryMap.begin();
i != countryMap.end(); ++i) {
string country = i->first;
// Emit equivalency lists
bool first1 = true;
- java << " public static final String VERSION = \"" + version + "\";" << endl;
+ java << " public static final String VERSION = \"" + version + "\";" << endl;
java << " public static final String[][] EQUIV = {" << endl;
for (ZoneMap::const_iterator i=ZONEINFO.begin(); i!=ZONEINFO.end(); ++i) {
if (i->second.isAlias() || i->second.getAliases().size() == 0) {
// the canonical zone, we should move it to position 0.
java << " { ";
bool first2 = true;
- const set<int>& s = i->second.getAliases();
- for (set<int>::const_iterator j=s.begin(); j!=s.end(); ++j) {
+ const set<int32_t>& s = i->second.getAliases();
+ for (set<int32_t>::const_iterator j=s.begin(); j!=s.end(); ++j) {
if (!first2) java << ", ";
java << '"' << zoneIDlist[*j] << '"';
first2 = false;
--- /dev/null
+static char elsieid[] = "@(#)zdump.c 8.3";
+
+/*
+** This code has been made independent of the rest of the time
+** conversion package to increase confidence in the verification it provides.
+** You can use this code to help in verifying other implementations.
+*/
+
+/*
+ * ICU note: Mr. Arthur David Olson (olsona@dc37a.nci.nih.gov) stated that
+ * "zdump.c is indeed in the public domain" in e-mail on Feb 22, 2007.
+ * This version of zdump.c is modified by ICU team to change output format
+ * and some additional options.
+ */
+
+
+#include "stdio.h" /* for stdout, stderr, perror */
+#include "string.h" /* for strcpy */
+#include "sys/types.h" /* for time_t */
+#include "time.h" /* for struct tm */
+#include "stdlib.h" /* for exit, malloc, atoi */
+#include "float.h" /* for FLT_MAX and DBL_MAX */
+#include "ctype.h" /* for isalpha et al. */
+
+/* Enable extensions and modifications for ICU. */
+#define ICU
+
+#ifdef ICU
+#include "dirent.h"
+#endif
+
+#ifndef isascii
+#define isascii(x) 1
+#endif /* !defined isascii */
+
+#ifndef ZDUMP_LO_YEAR
+#define ZDUMP_LO_YEAR (-500)
+#endif /* !defined ZDUMP_LO_YEAR */
+
+#ifndef ZDUMP_HI_YEAR
+#define ZDUMP_HI_YEAR 2500
+#endif /* !defined ZDUMP_HI_YEAR */
+
+#ifndef MAX_STRING_LENGTH
+#define MAX_STRING_LENGTH 1024
+#endif /* !defined MAX_STRING_LENGTH */
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE 0
+#endif /* !defined FALSE */
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif /* !defined EXIT_SUCCESS */
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif /* !defined EXIT_FAILURE */
+
+#ifndef SECSPERMIN
+#define SECSPERMIN 60
+#endif /* !defined SECSPERMIN */
+
+#ifndef MINSPERHOUR
+#define MINSPERHOUR 60
+#endif /* !defined MINSPERHOUR */
+
+#ifndef SECSPERHOUR
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#endif /* !defined SECSPERHOUR */
+
+#ifndef HOURSPERDAY
+#define HOURSPERDAY 24
+#endif /* !defined HOURSPERDAY */
+
+#ifndef EPOCH_YEAR
+#define EPOCH_YEAR 1970
+#endif /* !defined EPOCH_YEAR */
+
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif /* !defined TM_YEAR_BASE */
+
+#ifndef DAYSPERNYEAR
+#define DAYSPERNYEAR 365
+#endif /* !defined DAYSPERNYEAR */
+
+#ifndef isleap
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+#endif /* !defined isleap */
+
+#ifndef isleap_sum
+/*
+** See tzfile.h for details on isleap_sum.
+*/
+#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
+#endif /* !defined isleap_sum */
+
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
+#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
+
+#if HAVE_GETTEXT
+#include "locale.h" /* for setlocale */
+#include "libintl.h"
+#endif /* HAVE_GETTEXT */
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#else /* !defined lint */
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x) ((x) = 0)
+#else /* !defined GNUC_or_lint */
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** For the benefit of GNU folk...
+** `_(MSGID)' uses the current locale's message library string for MSGID.
+** The default is to use gettext if available, and use MSGID otherwise.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT
+#define _(msgid) gettext(msgid)
+#else /* !HAVE_GETTEXT */
+#define _(msgid) msgid
+#endif /* !HAVE_GETTEXT */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+#ifndef P
+#define P(x) x
+#endif /* !defined P */
+
+extern char ** environ;
+extern int getopt P((int argc, char * const argv[],
+ const char * options));
+extern char * optarg;
+extern int optind;
+extern char * tzname[2];
+
+static time_t absolute_min_time;
+static time_t absolute_max_time;
+static size_t longest;
+static char * progname;
+static int warned;
+
+static char * abbr P((struct tm * tmp));
+static void abbrok P((const char * abbrp, const char * zone));
+static long delta P((struct tm * newp, struct tm * oldp));
+static void dumptime P((const struct tm * tmp));
+static time_t hunt P((char * name, time_t lot, time_t hit));
+static void setabsolutes P((void));
+static void show P((char * zone, time_t t, int v));
+static const char * tformat P((void));
+static time_t yeartot P((long y));
+#ifdef ICU
+typedef struct listentry {
+ char * name;
+ struct listentry * next;
+} listentry;
+
+static time_t huntICU P((char * name, time_t lot, time_t hit, FILE *fp));
+static void dumptimeICU P((FILE * fp, time_t t));
+static void showICU P((FILE * fp, char * zone, time_t t1, time_t t2));
+static int getall P((struct listentry ** namelist));
+static void getzones P((char * basedir, char * subdir, struct listentry ** last, int * count));
+#endif
+
+#ifndef TYPECHECK
+#define my_localtime localtime
+#else /* !defined TYPECHECK */
+static struct tm *
+my_localtime(tp)
+time_t * tp;
+{
+ register struct tm * tmp;
+
+ tmp = localtime(tp);
+ if (tp != NULL && tmp != NULL) {
+ struct tm tm;
+ register time_t t;
+
+ tm = *tmp;
+ t = mktime(&tm);
+ if (t - *tp >= 1 || *tp - t >= 1) {
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "\n%s: ", progname);
+ (void) fprintf(stderr, tformat(), *tp);
+ (void) fprintf(stderr, " ->");
+ (void) fprintf(stderr, " year=%d", tmp->tm_year);
+ (void) fprintf(stderr, " mon=%d", tmp->tm_mon);
+ (void) fprintf(stderr, " mday=%d", tmp->tm_mday);
+ (void) fprintf(stderr, " hour=%d", tmp->tm_hour);
+ (void) fprintf(stderr, " min=%d", tmp->tm_min);
+ (void) fprintf(stderr, " sec=%d", tmp->tm_sec);
+ (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
+ (void) fprintf(stderr, " -> ");
+ (void) fprintf(stderr, tformat(), t);
+ (void) fprintf(stderr, "\n");
+ }
+ }
+ return tmp;
+}
+#endif /* !defined TYPECHECK */
+
+static void
+abbrok(abbrp, zone)
+const char * const abbrp;
+const char * const zone;
+{
+ register const char * cp;
+ register char * wp;
+
+ if (warned)
+ return;
+ cp = abbrp;
+ wp = NULL;
+ while (isascii((unsigned char) *cp) && isalpha((unsigned char) *cp))
+ ++cp;
+ if (cp - abbrp == 0)
+ wp = _("lacks alphabetic at start");
+ else if (cp - abbrp < 3)
+ wp = _("has fewer than 3 alphabetics");
+ else if (cp - abbrp > 6)
+ wp = _("has more than 6 alphabetics");
+ if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ ++cp;
+ if (isascii((unsigned char) *cp) &&
+ isdigit((unsigned char) *cp))
+ if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
+ ++cp;
+ if (*cp != '\0')
+ wp = _("differs from POSIX standard");
+ }
+ if (wp == NULL)
+ return;
+ (void) fflush(stdout);
+ (void) fprintf(stderr,
+ _("%s: warning: zone \"%s\" abbreviation \"%s\" %s\n"),
+ progname, zone, abbrp, wp);
+ warned = TRUE;
+}
+
+int
+main(argc, argv)
+int argc;
+char * argv[];
+{
+ register int i;
+ register int c;
+ register int vflag;
+ register char * cutarg;
+ register long cutloyear = ZDUMP_LO_YEAR;
+ register long cuthiyear = ZDUMP_HI_YEAR;
+ register time_t cutlotime;
+ register time_t cuthitime;
+ register char ** fakeenv;
+ time_t now;
+ time_t t;
+ time_t newt;
+ struct tm tm;
+ struct tm newtm;
+ register struct tm * tmp;
+ register struct tm * newtmp;
+#ifdef ICU
+ int nextopt;
+ char * dirarg;
+ int aflag;
+ int iflag;
+ listentry * namelist = NULL;
+ FILE * fp = stdout;
+#endif
+
+ INITIALIZE(cutlotime);
+ INITIALIZE(cuthitime);
+#if HAVE_GETTEXT
+ (void) setlocale(LC_ALL, "");
+#ifdef TZ_DOMAINDIR
+ (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
+#endif /* defined TEXTDOMAINDIR */
+ (void) textdomain(TZ_DOMAIN);
+#endif /* HAVE_GETTEXT */
+ progname = argv[0];
+ for (i = 1; i < argc; ++i)
+ if (strcmp(argv[i], "--version") == 0) {
+ (void) printf("%s\n", elsieid);
+ exit(EXIT_SUCCESS);
+ }
+ vflag = 0;
+ cutarg = NULL;
+#ifdef ICU
+ aflag = 0;
+ iflag = 0;
+ dirarg = NULL;
+ nextopt = 1;
+ while(nextopt) {
+ c = getopt(argc, argv, "ac:d:iv");
+ switch(c) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cutarg = optarg;
+ break;
+ case 'd':
+ dirarg = optarg;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ nextopt = 0;
+ break;
+ }
+ }
+ if ((c != EOF && c != -1) ||
+ (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
+ (void) fprintf(stderr,
+ _("%s: usage is %s [ --version ] [ -a ] [ -v ] [ -i ] [ -c [loyear,]hiyear ] [ -d dir ] [ zonename ... ]\n"),
+ progname, progname);
+ exit(EXIT_FAILURE);
+ }
+
+ if (dirarg != NULL) {
+ DIR * dp;
+ /* create the output directory */
+ mkdir(dirarg, 0777);
+ if ((dp = opendir(dirarg)) == NULL) {
+ fprintf(stderr, "cannot create the target directory");
+ exit(EXIT_FAILURE);
+ }
+ closedir(dp);
+ }
+#else
+ while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
+ if (c == 'v')
+ vflag = 1;
+ else cutarg = optarg;
+ if ((c != EOF && c != -1) ||
+ (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
+ (void) fprintf(stderr,
+_("%s: usage is %s [ --version ] [ -v ] [ -c [loyear,]hiyear ] zonename ...\n"),
+ progname, progname);
+ exit(EXIT_FAILURE);
+ }
+#endif
+ if (vflag) {
+ if (cutarg != NULL) {
+ long lo;
+ long hi;
+ char dummy;
+
+ if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
+ cuthiyear = hi;
+ } else if (sscanf(cutarg, "%ld,%ld%c",
+ &lo, &hi, &dummy) == 2) {
+ cutloyear = lo;
+ cuthiyear = hi;
+ } else {
+(void) fprintf(stderr, _("%s: wild -c argument %s\n"),
+ progname, cutarg);
+ exit(EXIT_FAILURE);
+ }
+ }
+ setabsolutes();
+ cutlotime = yeartot(cutloyear);
+ cuthitime = yeartot(cuthiyear);
+ }
+
+#ifdef ICU
+ if (aflag) {
+ /* get all available zones */
+ char ** fakeargv;
+ int i;
+ int count;
+
+ count = getall(&namelist);
+
+ fakeargv = (char **) malloc((size_t) (argc + count) * sizeof *argv);
+ /*
+ if ((fakeargv = (char **) malloc((size_t) (argc + count) * sizeof *argv)) == NULL) {
+ exit(EXIT_FAILURE);
+ }
+ */
+ for (i = 0; i < argc; i++) {
+ fakeargv[i] = argv[i];
+ }
+ for (i = 0; i < count; i++) {
+ fakeargv[i + argc] = namelist->name;
+ namelist = namelist->next;
+ }
+ argv = fakeargv;
+ argc += count;
+ }
+#endif
+ (void) time(&now);
+ longest = 0;
+ for (i = optind; i < argc; ++i)
+ if (strlen(argv[i]) > longest)
+ longest = strlen(argv[i]);
+ {
+ register int from;
+ register int to;
+
+ for (i = 0; environ[i] != NULL; ++i)
+ continue;
+ fakeenv = (char **) malloc((size_t) ((i + 2) *
+ sizeof *fakeenv));
+ if (fakeenv == NULL ||
+ (fakeenv[0] = (char *) malloc(longest + 4)) == NULL) {
+ (void) perror(progname);
+ exit(EXIT_FAILURE);
+ }
+ to = 0;
+ (void) strcpy(fakeenv[to++], "TZ=");
+ for (from = 0; environ[from] != NULL; ++from)
+ if (strncmp(environ[from], "TZ=", 3) != 0)
+ fakeenv[to++] = environ[from];
+ fakeenv[to] = NULL;
+ environ = fakeenv;
+ }
+ for (i = optind; i < argc; ++i) {
+ static char buf[MAX_STRING_LENGTH];
+
+ (void) strcpy(&fakeenv[0][3], argv[i]);
+ if (!vflag) {
+ show(argv[i], now, FALSE);
+ continue;
+ }
+#ifdef ICU
+ fp = NULL;
+ if (iflag) {
+ if (dirarg == NULL) {
+ /* we want to display a zone name here */
+ if (i != optind) {
+ printf("\n");
+ }
+ printf("ZONE: %s\n", argv[i]);
+ } else {
+ int zstart;
+ char path[FILENAME_MAX + 1];
+ strcpy(path, dirarg);
+ strcat(path, "/");
+ zstart = strlen(path);
+ strcat(path, argv[i]);
+ /* replace '/' with '-' */
+ while(path[++zstart] != 0) {
+ if (path[zstart] == '/') {
+ path[zstart] = '-';
+ }
+ }
+ if ((fp = fopen(path, "w")) == NULL) {
+ fprintf(stderr, "cannot create output file %s\n", path);
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+#endif
+ warned = FALSE;
+ t = absolute_min_time;
+#ifdef ICU
+ /* skip displaying info for the lowest time, which is actually not
+ * a transition when -i option is set */
+ if (!iflag) {
+#endif
+ show(argv[i], t, TRUE);
+ t += SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+#ifdef ICU
+ }
+#endif
+ if (t < cutlotime)
+ t = cutlotime;
+ tmp = my_localtime(&t);
+ if (tmp != NULL) {
+ tm = *tmp;
+ (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
+ }
+ for ( ; ; ) {
+ if (t >= cuthitime)
+ break;
+ newt = t + SECSPERHOUR * 12;
+ if (newt >= cuthitime)
+ break;
+ if (newt <= t)
+ break;
+ newtmp = localtime(&newt);
+ if (newtmp != NULL)
+ newtm = *newtmp;
+#ifdef ICU
+ if (iflag) {
+ /* We do not want to capture transitions just for
+ * abbreviated zone name changes */
+ if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
+ (delta(&newtm, &tm) != (newt - t) ||
+ newtm.tm_isdst != tm.tm_isdst)) {
+ newt = huntICU(argv[i], t, newt, fp);
+ newtmp = localtime(&newt);
+ if (newtmp != NULL) {
+ newtm = *newtmp;
+ (void) strncpy(buf,
+ abbr(&newtm),
+ (sizeof buf) - 1);
+ }
+ }
+ } else {
+#endif
+ if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
+ (delta(&newtm, &tm) != (newt - t) ||
+ newtm.tm_isdst != tm.tm_isdst ||
+ strcmp(abbr(&newtm), buf) != 0)) {
+ newt = hunt(argv[i], t, newt);
+ newtmp = localtime(&newt);
+ if (newtmp != NULL) {
+ newtm = *newtmp;
+ (void) strncpy(buf,
+ abbr(&newtm),
+ (sizeof buf) - 1);
+ }
+ }
+#ifdef ICU
+ }
+#endif
+ t = newt;
+ tm = newtm;
+ tmp = newtmp;
+ }
+#ifdef ICU
+ if (!iflag) {
+ /* skip displaying info for the highest time, which is actually not
+ * a transition when -i option is used*/
+#endif
+ t = absolute_max_time;
+ t -= SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ t += SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+
+#ifdef ICU
+ }
+ /* close file */
+ if (fp != NULL) {
+ fclose(fp);
+ }
+#endif
+ }
+ if (fflush(stdout) || ferror(stdout)) {
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) perror(_("Error writing to standard output"));
+ exit(EXIT_FAILURE);
+ }
+#ifdef ICU
+ if (aflag) {
+ struct listentry * entry = namelist;
+ struct listentry * next;
+ while (entry != NULL) {
+ free(entry->name);
+ next = entry->next;
+ free(entry);
+ entry = next;
+ }
+ }
+#endif
+ exit(EXIT_SUCCESS);
+ /* If exit fails to exit... */
+ return EXIT_FAILURE;
+}
+
+static void
+setabsolutes()
+{
+ if (0.5 == (time_t) 0.5) {
+ /*
+ ** time_t is floating.
+ */
+ if (sizeof (time_t) == sizeof (float)) {
+ absolute_min_time = (time_t) -FLT_MAX;
+ absolute_max_time = (time_t) FLT_MAX;
+ } else if (sizeof (time_t) == sizeof (double)) {
+ absolute_min_time = (time_t) -DBL_MAX;
+ absolute_max_time = (time_t) DBL_MAX;
+ } else {
+ (void) fprintf(stderr,
+_("%s: use of -v on system with floating time_t other than float or double\n"),
+ progname);
+ exit(EXIT_FAILURE);
+ }
+ } else if (0 > (time_t) -1) {
+ /*
+ ** time_t is signed. Assume overflow wraps around.
+ */
+ time_t t = 0;
+ time_t t1 = 1;
+
+ while (t < t1) {
+ t = t1;
+ t1 = 2 * t1 + 1;
+ }
+
+ absolute_max_time = t;
+ t = -t;
+ absolute_min_time = t - 1;
+ if (t < absolute_min_time)
+ absolute_min_time = t;
+ } else {
+ /*
+ ** time_t is unsigned.
+ */
+ absolute_min_time = 0;
+ absolute_max_time = absolute_min_time - 1;
+ }
+}
+
+static time_t
+yeartot(y)
+const long y;
+{
+ register long myy;
+ register long seconds;
+ register time_t t;
+
+ myy = EPOCH_YEAR;
+ t = 0;
+ while (myy != y) {
+ if (myy < y) {
+ seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
+ ++myy;
+ if (t > absolute_max_time - seconds) {
+ t = absolute_max_time;
+ break;
+ }
+ t += seconds;
+ } else {
+ --myy;
+ seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
+ if (t < absolute_min_time + seconds) {
+ t = absolute_min_time;
+ break;
+ }
+ t -= seconds;
+ }
+ }
+ return t;
+}
+
+static time_t
+hunt(char *name, time_t lot, time_t hit)
+{
+ time_t t;
+ long diff;
+ struct tm lotm;
+ register struct tm * lotmp;
+ struct tm tm;
+ register struct tm * tmp;
+ char loab[MAX_STRING_LENGTH];
+
+ lotmp = my_localtime(&lot);
+ if (lotmp != NULL) {
+ lotm = *lotmp;
+ (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
+ }
+ for ( ; ; ) {
+ diff = (long) (hit - lot);
+ if (diff < 2)
+ break;
+ t = lot;
+ t += diff / 2;
+ if (t <= lot)
+ ++t;
+ else if (t >= hit)
+ --t;
+ tmp = my_localtime(&t);
+ if (tmp != NULL)
+ tm = *tmp;
+ if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
+ (delta(&tm, &lotm) == (t - lot) &&
+ tm.tm_isdst == lotm.tm_isdst &&
+ strcmp(abbr(&tm), loab) == 0)) {
+ lot = t;
+ lotm = tm;
+ lotmp = tmp;
+ } else hit = t;
+ }
+ show(name, lot, TRUE);
+ show(name, hit, TRUE);
+ return hit;
+}
+
+/*
+** Thanks to Paul Eggert for logic used in delta.
+*/
+
+static long
+delta(newp, oldp)
+struct tm * newp;
+struct tm * oldp;
+{
+ register long result;
+ register int tmy;
+
+ if (newp->tm_year < oldp->tm_year)
+ return -delta(oldp, newp);
+ result = 0;
+ for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
+ result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
+ result += newp->tm_yday - oldp->tm_yday;
+ result *= HOURSPERDAY;
+ result += newp->tm_hour - oldp->tm_hour;
+ result *= MINSPERHOUR;
+ result += newp->tm_min - oldp->tm_min;
+ result *= SECSPERMIN;
+ result += newp->tm_sec - oldp->tm_sec;
+ return result;
+}
+
+static void
+show(char *zone, time_t t, int v)
+{
+ register struct tm * tmp;
+
+ (void) printf("%-*s ", (int) longest, zone);
+ if (v) {
+ tmp = gmtime(&t);
+ if (tmp == NULL) {
+ (void) printf(tformat(), t);
+ } else {
+ dumptime(tmp);
+ (void) printf(" UTC");
+ }
+ (void) printf(" = ");
+ }
+ tmp = my_localtime(&t);
+ dumptime(tmp);
+ if (tmp != NULL) {
+ if (*abbr(tmp) != '\0')
+ (void) printf(" %s", abbr(tmp));
+ if (v) {
+ (void) printf(" isdst=%d", tmp->tm_isdst);
+#ifdef TM_GMTOFF
+ (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
+#endif /* defined TM_GMTOFF */
+ }
+ }
+ (void) printf("\n");
+ if (tmp != NULL && *abbr(tmp) != '\0')
+ abbrok(abbr(tmp), zone);
+}
+
+static char *
+abbr(tmp)
+struct tm * tmp;
+{
+ register char * result;
+ static char nada;
+
+ if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
+ return &nada;
+ result = tzname[tmp->tm_isdst];
+ return (result == NULL) ? &nada : result;
+}
+
+/*
+** The code below can fail on certain theoretical systems;
+** it works on all known real-world systems as of 2004-12-30.
+*/
+
+static const char *
+tformat()
+{
+ if (0.5 == (time_t) 0.5) { /* floating */
+ if (sizeof (time_t) > sizeof (double))
+ return "%Lg";
+ return "%g";
+ }
+ if (0 > (time_t) -1) { /* signed */
+ if (sizeof (time_t) > sizeof (long))
+ return "%lld";
+ if (sizeof (time_t) > sizeof (int))
+ return "%ld";
+ return "%d";
+ }
+ if (sizeof (time_t) > sizeof (unsigned long))
+ return "%llu";
+ if (sizeof (time_t) > sizeof (unsigned int))
+ return "%lu";
+ return "%u";
+}
+
+static void
+dumptime(timeptr)
+register const struct tm * timeptr;
+{
+ static const char wday_name[][3] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static const char mon_name[][3] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+ register const char * wn;
+ register const char * mn;
+ register int lead;
+ register int trail;
+
+ if (timeptr == NULL) {
+ (void) printf("NULL");
+ return;
+ }
+ /*
+ ** The packaged versions of localtime and gmtime never put out-of-range
+ ** values in tm_wday or tm_mon, but since this code might be compiled
+ ** with other (perhaps experimental) versions, paranoia is in order.
+ */
+ if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
+ (int) (sizeof wday_name / sizeof wday_name[0]))
+ wn = "???";
+ else wn = wday_name[timeptr->tm_wday];
+ if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
+ (int) (sizeof mon_name / sizeof mon_name[0]))
+ mn = "???";
+ else mn = mon_name[timeptr->tm_mon];
+ (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
+ wn, mn,
+ timeptr->tm_mday, timeptr->tm_hour,
+ timeptr->tm_min, timeptr->tm_sec);
+#define DIVISOR 10
+ trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
+ lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
+ trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+ if (lead == 0)
+ (void) printf("%d", trail);
+ else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
+}
+
+#ifdef ICU
+static time_t
+huntICU(char *name, time_t lot, time_t hit, FILE * fp)
+{
+ time_t t;
+ long diff;
+ struct tm lotm;
+ register struct tm * lotmp;
+ struct tm tm;
+ register struct tm * tmp;
+ char loab[MAX_STRING_LENGTH];
+
+ lotmp = my_localtime(&lot);
+ if (lotmp != NULL) {
+ lotm = *lotmp;
+ (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
+ }
+ for ( ; ; ) {
+ diff = (long) (hit - lot);
+ if (diff < 2)
+ break;
+ t = lot;
+ t += diff / 2;
+ if (t <= lot)
+ ++t;
+ else if (t >= hit)
+ --t;
+ tmp = my_localtime(&t);
+ if (tmp != NULL)
+ tm = *tmp;
+ /* We do not want to capture transitions just for
+ * abbreviated zone name changes */
+ if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
+ (delta(&tm, &lotm) == (t - lot) &&
+ tm.tm_isdst == lotm.tm_isdst)) {
+ lot = t;
+ lotm = tm;
+ lotmp = tmp;
+ } else hit = t;
+ }
+ showICU(fp, name, lot, hit);
+ return hit;
+}
+
+static void showICU(FILE * fp, char *zone, time_t t1, time_t t2)
+{
+ if (fp == NULL) {
+ fp = stdout;
+ }
+ dumptimeICU(fp, t1);
+ fprintf(fp, " > ");
+ dumptimeICU(fp, t2);
+ fprintf(fp, "\n");
+}
+
+static void dumptimeICU(FILE * fp, time_t t)
+{
+ static const char wday_name[][3] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ struct tm gmt;
+ struct tm loc;
+ register int lead;
+ register int trail;
+ long offset;
+ long hour, min, sec;
+
+ loc = *my_localtime(&t);
+
+ trail = loc.tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
+ lead = loc.tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR + trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+
+ fprintf(fp, "%04d-%02d-%02d", lead * DIVISOR + trail, loc.tm_mon + 1, loc.tm_mday);
+ fprintf(fp, " %.3s ", wday_name[loc.tm_wday]);
+ fprintf(fp, "%02d:%02d:%02d", loc.tm_hour, loc.tm_min, loc.tm_sec);
+
+ gmt = *gmtime(&t);
+ offset = delta(&loc, &gmt);
+ if (offset < 0) {
+ offset = -offset;
+ fprintf(fp, "-");
+ } else {
+ fprintf(fp, "+");
+ }
+
+ sec = offset % 60;
+ offset = (offset - sec) / 60;
+ min = offset % 60;
+ hour = offset / 60;
+
+ fprintf(fp, "%02d", hour);
+ fprintf(fp, "%02d", min);
+ fprintf(fp, "%02d", sec);
+ fprintf(fp, "[DST=%d]", loc.tm_isdst);
+}
+
+static int getall(struct listentry ** namelist) {
+ int count = 0;
+ struct listentry dummyentry;
+ struct listentry * last = &dummyentry;
+
+ getzones(TZDIR, NULL, &last, &count);
+ if (count > 0) {
+ *namelist = dummyentry.next;
+ }
+
+ return count;
+}
+
+static void getzones(char * basedir, char * relpath, struct listentry ** last, int * count) {
+ char path[FILENAME_MAX + 1];
+ struct dirent * dir;
+ DIR * dp;
+
+ strcpy(path, basedir);
+ if (relpath != NULL) {
+ strcat(path, "/");
+ strcat(path, relpath);
+ }
+
+ if ((dp = opendir(path)) == NULL) {
+ /* file */
+ if (strstr(relpath, ".tab") == NULL) {
+ char * pzonename;
+ listentry * pentry;
+
+ if ((pzonename = malloc(strlen(relpath) + 1)) == NULL) {
+ exit(EXIT_FAILURE);
+ }
+ strcpy(pzonename, relpath);
+
+ if ((pentry = malloc(sizeof(listentry))) == NULL) {
+ exit(EXIT_FAILURE);
+ }
+
+ pentry->name = pzonename;
+ pentry->next = NULL;
+ (*last)->next = pentry;
+ *last = pentry;
+ (*count)++;
+ }
+ } else {
+ /* directory */
+ while ((dir = readdir(dp)) != NULL) {
+ char subpath[FILENAME_MAX + 1];
+
+ if (strcmp(dir->d_name, ".") == 0
+ || strcmp(dir->d_name, "..") == 0) {
+ continue;
+ }
+ if (relpath != NULL) {
+ strcpy(subpath, relpath);
+ strcat(subpath, "/");
+ strcat(subpath, dir->d_name);
+ } else {
+ strcpy(subpath, dir->d_name);
+ }
+ getzones(basedir, subpath, last, count);
+ }
+ closedir(dp);
+ }
+}
+#endif
break; /* go on to next year */
rp = &zp->z_rules[k];
rp->r_todo = FALSE;
-#ifdef ICU
- if (year >= finalRuleYear && rp == finalRule1) {
- emit_icu_zone(icuFile,
- zpfirst->z_name, zp->z_gmtoff,
- rp, finalRuleIndex, year);
- /* only emit this for the first year */
- finalRule1 = NULL;
- }
-#endif
if (useuntil && ktime >= untiltime)
break;
stdoff = rp->r_stdoff;
FALSE);
}
}
+#ifdef ICU
+ if (year >= finalRuleYear && rp == finalRule1) {
+ /* We want to shift final year 1 year after
+ * the actual final rule takes effect (year + 1),
+ * because the previous type is valid until the first
+ * transition defined by the final rule. Otherwise
+ * we may see unexpected offset shift at the
+ * begining of the year when the final rule takes
+ * effect. */
+
+ /* ICU currently can support signed int32 transition
+ * times. Thus, the transitions in year 2038 may be
+ * truncated. At this moment (tzdata2008g), only
+ * Rule Brazil is impacted by this limitation, because
+ * the final set of rules are starting in 2038. Although
+ * this code put the first couple of transitions populated
+ * by the final rules, they will be dropped off when
+ * collecting transition times. So, we need to keep
+ * the start year of the final rule in 2038, not 2039.
+ * Fortunately, the Brazil rules in 2038 and beyond use
+ * the same base offset/dst saving amount. Thus, even
+ * we skip the first couple of transitions, the final
+ * rule set for 2038 works properly. So for now,
+ * we do not increment the final rule start year only when
+ * it falls into year 2038. We need to revisit this code
+ * in future to fix the root cause of this problem (ICU
+ * resource type limitation - signed int32).
+ * Oct 7, 2008 - Yoshito */
+ int finalStartYear = (year == 2038) ? year : year + 1;
+ emit_icu_zone(icuFile,
+ zpfirst->z_name, zp->z_gmtoff,
+ rp, finalRuleIndex, finalStartYear);
+ /* only emit this for the first year */
+ finalRule1 = NULL;
+ }
+#endif
eats(zp->z_filename, zp->z_linenum,
rp->r_filename, rp->r_linenum);
doabbr(ab, zp->z_format, rp->r_abbrvar,