| Index: icu46/source/tools/tzcode/icuzdump.cpp
|
| ===================================================================
|
| --- icu46/source/tools/tzcode/icuzdump.cpp (revision 0)
|
| +++ icu46/source/tools/tzcode/icuzdump.cpp (revision 0)
|
| @@ -0,0 +1,423 @@
|
| +/*
|
| +*******************************************************************************
|
| +*
|
| +* 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;
|
| +}
|
|
|
| Property changes on: icu46/source/tools/tzcode/icuzdump.cpp
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|