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 |