intl/icu/source/tools/tzcode/icuzdump.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2 *******************************************************************************
     3 *
     4 *   Copyright (C) 2007, International Business Machines
     5 *   Corporation and others.  All Rights Reserved.
     6 *
     7 *******************************************************************************
     8 *   file name:  icuzdump.cpp
     9 *   encoding:   US-ASCII
    10 *   tab size:   8 (not used)
    11 *   indentation:4
    12 *
    13 *   created on: 2007-04-02
    14 *   created by: Yoshito Umaoka
    15 *
    16 *   This tool write out timezone transitions for ICU timezone.  This tool
    17 *   is used as a part of tzdata update process to check if ICU timezone
    18 *   code works as well as the corresponding Olson stock localtime/zdump.
    19 */
    21 #include <cstdlib>
    22 #include <cstring>
    23 #include <fstream>
    24 #include <sstream>
    25 #include <iostream>
    27 #include "unicode/utypes.h"
    28 #include "unicode/ustring.h"
    29 #include "unicode/timezone.h"
    30 #include "unicode/simpletz.h"
    31 #include "unicode/smpdtfmt.h"
    32 #include "unicode/decimfmt.h"
    33 #include "unicode/gregocal.h"
    34 #include "unicode/ustream.h"
    35 #include "unicode/putil.h"
    37 #include "uoptions.h"
    39 using namespace std;
    41 class DumpFormatter {
    42 public:
    43     DumpFormatter() {
    44         UErrorCode status = U_ZERO_ERROR;
    45         stz = new SimpleTimeZone(0, "");
    46         sdf = new SimpleDateFormat((UnicodeString)"yyyy-MM-dd EEE HH:mm:ss", Locale::getEnglish(), status);
    47         DecimalFormatSymbols *symbols = new DecimalFormatSymbols(Locale::getEnglish(), status);
    48         decf = new DecimalFormat("00", symbols, status);
    49     }
    50     ~DumpFormatter() {
    51     }
    53     UnicodeString& format(UDate time, int32_t offset, UBool isDst, UnicodeString& appendTo) {
    54         stz->setRawOffset(offset);
    55         sdf->setTimeZone(*stz);
    56         UnicodeString str = sdf->format(time, appendTo);
    57         if (offset < 0) {
    58             appendTo += "-";
    59             offset = -offset;
    60         } else {
    61             appendTo += "+";
    62         }
    64         int32_t hour, min, sec;
    66         offset /= 1000;
    67         sec = offset % 60;
    68         offset = (offset - sec) / 60;
    69         min = offset % 60;
    70         hour = offset / 60;
    72         decf->format(hour, appendTo);
    73         decf->format(min, appendTo);
    74         decf->format(sec, appendTo);
    75         appendTo += "[DST=";
    76         if (isDst) {
    77             appendTo += "1";
    78         } else {
    79             appendTo += "0";
    80         }
    81         appendTo += "]";
    82         return appendTo;
    83     }
    84 private:
    85     SimpleTimeZone*     stz;
    86     SimpleDateFormat*   sdf;
    87     DecimalFormat*      decf;
    88 };
    90 class ICUZDump {
    91 public:
    92     ICUZDump() {
    93         formatter = new DumpFormatter();
    94         loyear = 1902;
    95         hiyear = 2050;
    96         tick = 1000;
    97         linesep = NULL;
    98     }
   100     ~ICUZDump() {
   101     }
   103     void setLowYear(int32_t lo) {
   104         loyear = lo;
   105     }
   107     void setHighYear(int32_t hi) {
   108         hiyear = hi;
   109     }
   111     void setTick(int32_t t) {
   112         tick = t;
   113     }
   115     void setTimeZone(TimeZone* tz) {
   116         timezone = tz;
   117     }
   119     void setDumpFormatter(DumpFormatter* fmt) {
   120         formatter = fmt;
   121     }
   123     void setLineSeparator(const char* sep) {
   124         linesep = sep;
   125     }
   127     void dump(ostream& out) {
   128         UErrorCode status = U_ZERO_ERROR;
   129         UDate SEARCH_INCREMENT = 12 * 60 * 60 * 1000; // half day
   130         UDate t, cutlo, cuthi;
   131         int32_t rawOffset, dstOffset;
   132         UnicodeString str;
   134         getCutOverTimes(cutlo, cuthi);
   135         t = cutlo;
   136         timezone->getOffset(t, FALSE, rawOffset, dstOffset, status);
   137         while (t < cuthi) {
   138             int32_t newRawOffset, newDstOffset;
   139             UDate newt = t + SEARCH_INCREMENT;
   141             timezone->getOffset(newt, FALSE, newRawOffset, newDstOffset, status);
   143             UBool bSameOffset = (rawOffset + dstOffset) == (newRawOffset + newDstOffset);
   144             UBool bSameDst = ((dstOffset != 0) && (newDstOffset != 0)) || ((dstOffset == 0) && (newDstOffset == 0));
   146             if (!bSameOffset || !bSameDst) {
   147                 // find the boundary
   148                 UDate lot = t;
   149                 UDate hit = newt;
   150                 while (true) {
   151                     int32_t diff = (int32_t)(hit - lot);
   152                     if (diff <= tick) {
   153                         break;
   154                     }
   155                     UDate medt = lot + ((diff / 2) / tick) * tick;
   156                     int32_t medRawOffset, medDstOffset;
   157                     timezone->getOffset(medt, FALSE, medRawOffset, medDstOffset, status);
   159                     bSameOffset = (rawOffset + dstOffset) == (medRawOffset + medDstOffset);
   160                     bSameDst = ((dstOffset != 0) && (medDstOffset != 0)) || ((dstOffset == 0) && (medDstOffset == 0));
   162                     if (!bSameOffset || !bSameDst) {
   163                         hit = medt;
   164                     } else {
   165                         lot = medt;
   166                     }
   167                 }
   168                 // write out the boundary
   169                 str.remove();
   170                 formatter->format(lot, rawOffset + dstOffset, (dstOffset == 0 ? FALSE : TRUE), str);
   171                 out << str << " > ";
   172                 str.remove();
   173                 formatter->format(hit, newRawOffset + newDstOffset, (newDstOffset == 0 ? FALSE : TRUE), str);
   174                 out << str;
   175                 if (linesep != NULL) {
   176                     out << linesep;
   177                 } else {
   178                     out << endl;
   179                 }
   181                 rawOffset = newRawOffset;
   182                 dstOffset = newDstOffset;
   183             }
   184             t = newt;
   185         }
   186     }
   188 private:
   189     void getCutOverTimes(UDate& lo, UDate& hi) {
   190         UErrorCode status = U_ZERO_ERROR;
   191         GregorianCalendar* gcal = new GregorianCalendar(timezone, Locale::getEnglish(), status);
   192         gcal->clear();
   193         gcal->set(loyear, 0, 1, 0, 0, 0);
   194         lo = gcal->getTime(status);
   195         gcal->set(hiyear, 0, 1, 0, 0, 0);
   196         hi = gcal->getTime(status);
   197     }
   199     void dumpZone(ostream& out, const char* linesep, UnicodeString tzid, int32_t low, int32_t high) {
   200     }
   202     TimeZone*   timezone;
   203     int32_t     loyear;
   204     int32_t     hiyear;
   205     int32_t     tick;
   207     DumpFormatter*  formatter;
   208     const char*  linesep;
   209 };
   211 class ZoneIterator {
   212 public:
   213     ZoneIterator(UBool bAll = FALSE) {
   214         if (bAll) {
   215             zenum = TimeZone::createEnumeration();
   216         }
   217         else {
   218             zenum = NULL;
   219             zids = NULL;
   220             idx = 0;
   221             numids = 1;
   222         }
   223     }
   225     ZoneIterator(const char** ids, int32_t num) {
   226         zenum = NULL;
   227         zids = ids;
   228         idx = 0;
   229         numids = num;
   230     }
   232     ~ZoneIterator() {
   233         if (zenum != NULL) {
   234             delete zenum;
   235         }
   236     }
   238     TimeZone* next() {
   239         TimeZone* tz = NULL;
   240         if (zenum != NULL) {
   241             UErrorCode status = U_ZERO_ERROR;
   242             const UnicodeString* zid = zenum->snext(status);
   243             if (zid != NULL) {
   244                 tz = TimeZone::createTimeZone(*zid);
   245             }
   246         }
   247         else {
   248             if (idx < numids) {
   249                 if (zids != NULL) {
   250                     tz = TimeZone::createTimeZone((const UnicodeString&)zids[idx]);
   251                 }
   252                 else {
   253                     tz = TimeZone::createDefault();
   254                 }
   255                 idx++;
   256             }
   257         }
   258         return tz;
   259     }
   261 private:
   262     const char** zids;
   263     StringEnumeration* zenum;
   264     int32_t idx;
   265     int32_t numids;
   266 };
   268 enum { 
   269   kOptHelpH = 0,
   270   kOptHelpQuestionMark,
   271   kOptAllZones,
   272   kOptCutover,
   273   kOptDestDir,
   274   kOptLineSep
   275 };
   277 static UOption options[]={
   278     UOPTION_HELP_H,
   279     UOPTION_HELP_QUESTION_MARK,
   280     UOPTION_DEF("allzones", 'a', UOPT_NO_ARG),
   281     UOPTION_DEF("cutover", 'c', UOPT_REQUIRES_ARG),
   282     UOPTION_DEF("destdir", 'd', UOPT_REQUIRES_ARG),
   283     UOPTION_DEF("linesep", 'l', UOPT_REQUIRES_ARG)
   284 };
   286 extern int
   287 main(int argc, char *argv[]) {
   288     int32_t low = 1902;
   289     int32_t high = 2038;
   290     UBool bAll = FALSE;
   291     const char *dir = NULL;
   292     const char *linesep = NULL;
   294     U_MAIN_INIT_ARGS(argc, argv);
   295     argc = u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
   297     if (argc < 0) {
   298         cerr << "Illegal command line argument(s)" << endl << endl;
   299     }
   301     if (argc < 0 || options[kOptHelpH].doesOccur || options[kOptHelpQuestionMark].doesOccur) {
   302         cerr
   303             << "Usage: icuzdump [-options] [zoneid1 zoneid2 ...]" << endl
   304             << endl
   305             << "\tDump all offset transitions for the specified zones." << endl
   306             << endl
   307             << "Options:" << endl
   308             << "\t-a       : Dump all available zones." << endl
   309             << "\t-d <dir> : When specified, write transitions in a file under" << endl
   310             << "\t           the directory for each zone." << endl
   311             << "\t-l <sep> : New line code type used in file outputs. CR or LF (default)"
   312             << "\t           or CRLF." << endl
   313             << "\t-c [<low_year>,]<high_year>" << endl
   314             << "\t         : When specified, dump transitions starting <low_year>" << endl
   315             << "\t           (inclusive) up to <high_year> (exclusive).  The default" << endl
   316             << "\t           values are 1902(low) and 2038(high)." << endl;
   317         return argc < 0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
   318     }
   320     bAll = options[kOptAllZones].doesOccur;
   322     if (options[kOptDestDir].doesOccur) {
   323         dir = options[kOptDestDir].value;
   324     }
   326     if (options[kOptLineSep].doesOccur) {
   327         if (strcmp(options[kOptLineSep].value, "CR") == 0) {
   328             linesep = "\r";
   329         } else if (strcmp(options[kOptLineSep].value, "CRLF") == 0) {
   330             linesep = "\r\n";
   331         } else if (strcmp(options[kOptLineSep].value, "LF") == 0) {
   332             linesep = "\n";
   333         }
   334     }
   336     if (options[kOptCutover].doesOccur) {
   337         char* comma = (char*)strchr(options[kOptCutover].value, ',');
   338         if (comma == NULL) {
   339             high = atoi(options[kOptCutover].value);
   340         } else {
   341             *comma = 0;
   342             low = atoi(options[kOptCutover].value);
   343             high = atoi(comma + 1);
   344         }
   345     }
   347     ICUZDump dumper;
   348     dumper.setLowYear(low);
   349     dumper.setHighYear(high);
   350     if (dir != NULL && linesep != NULL) {
   351         // use the specified line separator only for file output
   352         dumper.setLineSeparator((const char*)linesep);
   353     }
   355     ZoneIterator* zit;
   356     if (bAll) {
   357         zit = new ZoneIterator(TRUE);
   358     } else {
   359         if (argc <= 1) {
   360             zit = new ZoneIterator();
   361         } else {
   362             zit = new ZoneIterator((const char**)&argv[1], argc - 1);
   363         }
   364     }
   366     UnicodeString id;
   367     if (dir != NULL) {
   368         // file output
   369         ostringstream path;
   370         ios::openmode mode = ios::out;
   371         if (linesep != NULL) {
   372             mode |= ios::binary;
   373         }
   374         for (;;) {
   375             TimeZone* tz = zit->next();
   376             if (tz == NULL) {
   377                 break;
   378             }
   379             dumper.setTimeZone(tz);
   380             tz->getID(id);
   382             // target file path
   383             path.str("");
   384             path << dir << U_FILE_SEP_CHAR;
   385             id = id.findAndReplace("/", "-");
   386             path << id;
   388             ofstream* fout = new ofstream(path.str().c_str(), mode);
   389             if (fout->fail()) {
   390                 cerr << "Cannot open file " << path << endl;
   391                 delete fout;
   392                 delete tz;
   393                 break;
   394             }
   396             dumper.dump(*fout);
   397             fout->close();
   398             delete fout;
   399             delete tz;
   400         }
   402     } else {
   403         // stdout
   404         UBool bFirst = TRUE;
   405         for (;;) {
   406             TimeZone* tz = zit->next();
   407             if (tz == NULL) {
   408                 break;
   409             }
   410             dumper.setTimeZone(tz);
   411             tz->getID(id);
   412             if (bFirst) {
   413                 bFirst = FALSE;
   414             } else {
   415                 cout << endl;
   416             }
   417             cout << "ZONE: " << id << endl;
   418             dumper.dump(cout);
   419             delete tz;
   420         }
   421     }
   422     delete zit;
   423 }

mercurial