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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/tools/tzcode/icuzdump.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,423 @@
     1.4 +/*
     1.5 +*******************************************************************************
     1.6 +*
     1.7 +*   Copyright (C) 2007, International Business Machines
     1.8 +*   Corporation and others.  All Rights Reserved.
     1.9 +*
    1.10 +*******************************************************************************
    1.11 +*   file name:  icuzdump.cpp
    1.12 +*   encoding:   US-ASCII
    1.13 +*   tab size:   8 (not used)
    1.14 +*   indentation:4
    1.15 +*
    1.16 +*   created on: 2007-04-02
    1.17 +*   created by: Yoshito Umaoka
    1.18 +*
    1.19 +*   This tool write out timezone transitions for ICU timezone.  This tool
    1.20 +*   is used as a part of tzdata update process to check if ICU timezone
    1.21 +*   code works as well as the corresponding Olson stock localtime/zdump.
    1.22 +*/
    1.23 +
    1.24 +#include <cstdlib>
    1.25 +#include <cstring>
    1.26 +#include <fstream>
    1.27 +#include <sstream>
    1.28 +#include <iostream>
    1.29 +
    1.30 +#include "unicode/utypes.h"
    1.31 +#include "unicode/ustring.h"
    1.32 +#include "unicode/timezone.h"
    1.33 +#include "unicode/simpletz.h"
    1.34 +#include "unicode/smpdtfmt.h"
    1.35 +#include "unicode/decimfmt.h"
    1.36 +#include "unicode/gregocal.h"
    1.37 +#include "unicode/ustream.h"
    1.38 +#include "unicode/putil.h"
    1.39 +
    1.40 +#include "uoptions.h"
    1.41 +
    1.42 +using namespace std;
    1.43 +
    1.44 +class DumpFormatter {
    1.45 +public:
    1.46 +    DumpFormatter() {
    1.47 +        UErrorCode status = U_ZERO_ERROR;
    1.48 +        stz = new SimpleTimeZone(0, "");
    1.49 +        sdf = new SimpleDateFormat((UnicodeString)"yyyy-MM-dd EEE HH:mm:ss", Locale::getEnglish(), status);
    1.50 +        DecimalFormatSymbols *symbols = new DecimalFormatSymbols(Locale::getEnglish(), status);
    1.51 +        decf = new DecimalFormat("00", symbols, status);
    1.52 +    }
    1.53 +    ~DumpFormatter() {
    1.54 +    }
    1.55 +
    1.56 +    UnicodeString& format(UDate time, int32_t offset, UBool isDst, UnicodeString& appendTo) {
    1.57 +        stz->setRawOffset(offset);
    1.58 +        sdf->setTimeZone(*stz);
    1.59 +        UnicodeString str = sdf->format(time, appendTo);
    1.60 +        if (offset < 0) {
    1.61 +            appendTo += "-";
    1.62 +            offset = -offset;
    1.63 +        } else {
    1.64 +            appendTo += "+";
    1.65 +        }
    1.66 +
    1.67 +        int32_t hour, min, sec;
    1.68 +
    1.69 +        offset /= 1000;
    1.70 +        sec = offset % 60;
    1.71 +        offset = (offset - sec) / 60;
    1.72 +        min = offset % 60;
    1.73 +        hour = offset / 60;
    1.74 +
    1.75 +        decf->format(hour, appendTo);
    1.76 +        decf->format(min, appendTo);
    1.77 +        decf->format(sec, appendTo);
    1.78 +        appendTo += "[DST=";
    1.79 +        if (isDst) {
    1.80 +            appendTo += "1";
    1.81 +        } else {
    1.82 +            appendTo += "0";
    1.83 +        }
    1.84 +        appendTo += "]";
    1.85 +        return appendTo;
    1.86 +    }
    1.87 +private:
    1.88 +    SimpleTimeZone*     stz;
    1.89 +    SimpleDateFormat*   sdf;
    1.90 +    DecimalFormat*      decf;
    1.91 +};
    1.92 +
    1.93 +class ICUZDump {
    1.94 +public:
    1.95 +    ICUZDump() {
    1.96 +        formatter = new DumpFormatter();
    1.97 +        loyear = 1902;
    1.98 +        hiyear = 2050;
    1.99 +        tick = 1000;
   1.100 +        linesep = NULL;
   1.101 +    }
   1.102 +
   1.103 +    ~ICUZDump() {
   1.104 +    }
   1.105 +
   1.106 +    void setLowYear(int32_t lo) {
   1.107 +        loyear = lo;
   1.108 +    }
   1.109 +
   1.110 +    void setHighYear(int32_t hi) {
   1.111 +        hiyear = hi;
   1.112 +    }
   1.113 +
   1.114 +    void setTick(int32_t t) {
   1.115 +        tick = t;
   1.116 +    }
   1.117 +
   1.118 +    void setTimeZone(TimeZone* tz) {
   1.119 +        timezone = tz;
   1.120 +    }
   1.121 +
   1.122 +    void setDumpFormatter(DumpFormatter* fmt) {
   1.123 +        formatter = fmt;
   1.124 +    }
   1.125 +
   1.126 +    void setLineSeparator(const char* sep) {
   1.127 +        linesep = sep;
   1.128 +    }
   1.129 +
   1.130 +    void dump(ostream& out) {
   1.131 +        UErrorCode status = U_ZERO_ERROR;
   1.132 +        UDate SEARCH_INCREMENT = 12 * 60 * 60 * 1000; // half day
   1.133 +        UDate t, cutlo, cuthi;
   1.134 +        int32_t rawOffset, dstOffset;
   1.135 +        UnicodeString str;
   1.136 +
   1.137 +        getCutOverTimes(cutlo, cuthi);
   1.138 +        t = cutlo;
   1.139 +        timezone->getOffset(t, FALSE, rawOffset, dstOffset, status);
   1.140 +        while (t < cuthi) {
   1.141 +            int32_t newRawOffset, newDstOffset;
   1.142 +            UDate newt = t + SEARCH_INCREMENT;
   1.143 +
   1.144 +            timezone->getOffset(newt, FALSE, newRawOffset, newDstOffset, status);
   1.145 +
   1.146 +            UBool bSameOffset = (rawOffset + dstOffset) == (newRawOffset + newDstOffset);
   1.147 +            UBool bSameDst = ((dstOffset != 0) && (newDstOffset != 0)) || ((dstOffset == 0) && (newDstOffset == 0));
   1.148 +
   1.149 +            if (!bSameOffset || !bSameDst) {
   1.150 +                // find the boundary
   1.151 +                UDate lot = t;
   1.152 +                UDate hit = newt;
   1.153 +                while (true) {
   1.154 +                    int32_t diff = (int32_t)(hit - lot);
   1.155 +                    if (diff <= tick) {
   1.156 +                        break;
   1.157 +                    }
   1.158 +                    UDate medt = lot + ((diff / 2) / tick) * tick;
   1.159 +                    int32_t medRawOffset, medDstOffset;
   1.160 +                    timezone->getOffset(medt, FALSE, medRawOffset, medDstOffset, status);
   1.161 +
   1.162 +                    bSameOffset = (rawOffset + dstOffset) == (medRawOffset + medDstOffset);
   1.163 +                    bSameDst = ((dstOffset != 0) && (medDstOffset != 0)) || ((dstOffset == 0) && (medDstOffset == 0));
   1.164 +
   1.165 +                    if (!bSameOffset || !bSameDst) {
   1.166 +                        hit = medt;
   1.167 +                    } else {
   1.168 +                        lot = medt;
   1.169 +                    }
   1.170 +                }
   1.171 +                // write out the boundary
   1.172 +                str.remove();
   1.173 +                formatter->format(lot, rawOffset + dstOffset, (dstOffset == 0 ? FALSE : TRUE), str);
   1.174 +                out << str << " > ";
   1.175 +                str.remove();
   1.176 +                formatter->format(hit, newRawOffset + newDstOffset, (newDstOffset == 0 ? FALSE : TRUE), str);
   1.177 +                out << str;
   1.178 +                if (linesep != NULL) {
   1.179 +                    out << linesep;
   1.180 +                } else {
   1.181 +                    out << endl;
   1.182 +                }
   1.183 +
   1.184 +                rawOffset = newRawOffset;
   1.185 +                dstOffset = newDstOffset;
   1.186 +            }
   1.187 +            t = newt;
   1.188 +        }
   1.189 +    }
   1.190 +
   1.191 +private:
   1.192 +    void getCutOverTimes(UDate& lo, UDate& hi) {
   1.193 +        UErrorCode status = U_ZERO_ERROR;
   1.194 +        GregorianCalendar* gcal = new GregorianCalendar(timezone, Locale::getEnglish(), status);
   1.195 +        gcal->clear();
   1.196 +        gcal->set(loyear, 0, 1, 0, 0, 0);
   1.197 +        lo = gcal->getTime(status);
   1.198 +        gcal->set(hiyear, 0, 1, 0, 0, 0);
   1.199 +        hi = gcal->getTime(status);
   1.200 +    }
   1.201 +
   1.202 +    void dumpZone(ostream& out, const char* linesep, UnicodeString tzid, int32_t low, int32_t high) {
   1.203 +    }
   1.204 +
   1.205 +    TimeZone*   timezone;
   1.206 +    int32_t     loyear;
   1.207 +    int32_t     hiyear;
   1.208 +    int32_t     tick;
   1.209 +
   1.210 +    DumpFormatter*  formatter;
   1.211 +    const char*  linesep;
   1.212 +};
   1.213 +
   1.214 +class ZoneIterator {
   1.215 +public:
   1.216 +    ZoneIterator(UBool bAll = FALSE) {
   1.217 +        if (bAll) {
   1.218 +            zenum = TimeZone::createEnumeration();
   1.219 +        }
   1.220 +        else {
   1.221 +            zenum = NULL;
   1.222 +            zids = NULL;
   1.223 +            idx = 0;
   1.224 +            numids = 1;
   1.225 +        }
   1.226 +    }
   1.227 +
   1.228 +    ZoneIterator(const char** ids, int32_t num) {
   1.229 +        zenum = NULL;
   1.230 +        zids = ids;
   1.231 +        idx = 0;
   1.232 +        numids = num;
   1.233 +    }
   1.234 +
   1.235 +    ~ZoneIterator() {
   1.236 +        if (zenum != NULL) {
   1.237 +            delete zenum;
   1.238 +        }
   1.239 +    }
   1.240 +
   1.241 +    TimeZone* next() {
   1.242 +        TimeZone* tz = NULL;
   1.243 +        if (zenum != NULL) {
   1.244 +            UErrorCode status = U_ZERO_ERROR;
   1.245 +            const UnicodeString* zid = zenum->snext(status);
   1.246 +            if (zid != NULL) {
   1.247 +                tz = TimeZone::createTimeZone(*zid);
   1.248 +            }
   1.249 +        }
   1.250 +        else {
   1.251 +            if (idx < numids) {
   1.252 +                if (zids != NULL) {
   1.253 +                    tz = TimeZone::createTimeZone((const UnicodeString&)zids[idx]);
   1.254 +                }
   1.255 +                else {
   1.256 +                    tz = TimeZone::createDefault();
   1.257 +                }
   1.258 +                idx++;
   1.259 +            }
   1.260 +        }
   1.261 +        return tz;
   1.262 +    }
   1.263 +
   1.264 +private:
   1.265 +    const char** zids;
   1.266 +    StringEnumeration* zenum;
   1.267 +    int32_t idx;
   1.268 +    int32_t numids;
   1.269 +};
   1.270 +
   1.271 +enum { 
   1.272 +  kOptHelpH = 0,
   1.273 +  kOptHelpQuestionMark,
   1.274 +  kOptAllZones,
   1.275 +  kOptCutover,
   1.276 +  kOptDestDir,
   1.277 +  kOptLineSep
   1.278 +};
   1.279 +
   1.280 +static UOption options[]={
   1.281 +    UOPTION_HELP_H,
   1.282 +    UOPTION_HELP_QUESTION_MARK,
   1.283 +    UOPTION_DEF("allzones", 'a', UOPT_NO_ARG),
   1.284 +    UOPTION_DEF("cutover", 'c', UOPT_REQUIRES_ARG),
   1.285 +    UOPTION_DEF("destdir", 'd', UOPT_REQUIRES_ARG),
   1.286 +    UOPTION_DEF("linesep", 'l', UOPT_REQUIRES_ARG)
   1.287 +};
   1.288 +
   1.289 +extern int
   1.290 +main(int argc, char *argv[]) {
   1.291 +    int32_t low = 1902;
   1.292 +    int32_t high = 2038;
   1.293 +    UBool bAll = FALSE;
   1.294 +    const char *dir = NULL;
   1.295 +    const char *linesep = NULL;
   1.296 +
   1.297 +    U_MAIN_INIT_ARGS(argc, argv);
   1.298 +    argc = u_parseArgs(argc, argv, sizeof(options)/sizeof(options[0]), options);
   1.299 +
   1.300 +    if (argc < 0) {
   1.301 +        cerr << "Illegal command line argument(s)" << endl << endl;
   1.302 +    }
   1.303 +
   1.304 +    if (argc < 0 || options[kOptHelpH].doesOccur || options[kOptHelpQuestionMark].doesOccur) {
   1.305 +        cerr
   1.306 +            << "Usage: icuzdump [-options] [zoneid1 zoneid2 ...]" << endl
   1.307 +            << endl
   1.308 +            << "\tDump all offset transitions for the specified zones." << endl
   1.309 +            << endl
   1.310 +            << "Options:" << endl
   1.311 +            << "\t-a       : Dump all available zones." << endl
   1.312 +            << "\t-d <dir> : When specified, write transitions in a file under" << endl
   1.313 +            << "\t           the directory for each zone." << endl
   1.314 +            << "\t-l <sep> : New line code type used in file outputs. CR or LF (default)"
   1.315 +            << "\t           or CRLF." << endl
   1.316 +            << "\t-c [<low_year>,]<high_year>" << endl
   1.317 +            << "\t         : When specified, dump transitions starting <low_year>" << endl
   1.318 +            << "\t           (inclusive) up to <high_year> (exclusive).  The default" << endl
   1.319 +            << "\t           values are 1902(low) and 2038(high)." << endl;
   1.320 +        return argc < 0 ? U_ILLEGAL_ARGUMENT_ERROR : U_ZERO_ERROR;
   1.321 +    }
   1.322 +
   1.323 +    bAll = options[kOptAllZones].doesOccur;
   1.324 +
   1.325 +    if (options[kOptDestDir].doesOccur) {
   1.326 +        dir = options[kOptDestDir].value;
   1.327 +    }
   1.328 +
   1.329 +    if (options[kOptLineSep].doesOccur) {
   1.330 +        if (strcmp(options[kOptLineSep].value, "CR") == 0) {
   1.331 +            linesep = "\r";
   1.332 +        } else if (strcmp(options[kOptLineSep].value, "CRLF") == 0) {
   1.333 +            linesep = "\r\n";
   1.334 +        } else if (strcmp(options[kOptLineSep].value, "LF") == 0) {
   1.335 +            linesep = "\n";
   1.336 +        }
   1.337 +    }
   1.338 +
   1.339 +    if (options[kOptCutover].doesOccur) {
   1.340 +        char* comma = (char*)strchr(options[kOptCutover].value, ',');
   1.341 +        if (comma == NULL) {
   1.342 +            high = atoi(options[kOptCutover].value);
   1.343 +        } else {
   1.344 +            *comma = 0;
   1.345 +            low = atoi(options[kOptCutover].value);
   1.346 +            high = atoi(comma + 1);
   1.347 +        }
   1.348 +    }
   1.349 +
   1.350 +    ICUZDump dumper;
   1.351 +    dumper.setLowYear(low);
   1.352 +    dumper.setHighYear(high);
   1.353 +    if (dir != NULL && linesep != NULL) {
   1.354 +        // use the specified line separator only for file output
   1.355 +        dumper.setLineSeparator((const char*)linesep);
   1.356 +    }
   1.357 +
   1.358 +    ZoneIterator* zit;
   1.359 +    if (bAll) {
   1.360 +        zit = new ZoneIterator(TRUE);
   1.361 +    } else {
   1.362 +        if (argc <= 1) {
   1.363 +            zit = new ZoneIterator();
   1.364 +        } else {
   1.365 +            zit = new ZoneIterator((const char**)&argv[1], argc - 1);
   1.366 +        }
   1.367 +    }
   1.368 +
   1.369 +    UnicodeString id;
   1.370 +    if (dir != NULL) {
   1.371 +        // file output
   1.372 +        ostringstream path;
   1.373 +        ios::openmode mode = ios::out;
   1.374 +        if (linesep != NULL) {
   1.375 +            mode |= ios::binary;
   1.376 +        }
   1.377 +        for (;;) {
   1.378 +            TimeZone* tz = zit->next();
   1.379 +            if (tz == NULL) {
   1.380 +                break;
   1.381 +            }
   1.382 +            dumper.setTimeZone(tz);
   1.383 +            tz->getID(id);
   1.384 +
   1.385 +            // target file path
   1.386 +            path.str("");
   1.387 +            path << dir << U_FILE_SEP_CHAR;
   1.388 +            id = id.findAndReplace("/", "-");
   1.389 +            path << id;
   1.390 +
   1.391 +            ofstream* fout = new ofstream(path.str().c_str(), mode);
   1.392 +            if (fout->fail()) {
   1.393 +                cerr << "Cannot open file " << path << endl;
   1.394 +                delete fout;
   1.395 +                delete tz;
   1.396 +                break;
   1.397 +            }
   1.398 +
   1.399 +            dumper.dump(*fout);
   1.400 +            fout->close();
   1.401 +            delete fout;
   1.402 +            delete tz;
   1.403 +        }
   1.404 +
   1.405 +    } else {
   1.406 +        // stdout
   1.407 +        UBool bFirst = TRUE;
   1.408 +        for (;;) {
   1.409 +            TimeZone* tz = zit->next();
   1.410 +            if (tz == NULL) {
   1.411 +                break;
   1.412 +            }
   1.413 +            dumper.setTimeZone(tz);
   1.414 +            tz->getID(id);
   1.415 +            if (bFirst) {
   1.416 +                bFirst = FALSE;
   1.417 +            } else {
   1.418 +                cout << endl;
   1.419 +            }
   1.420 +            cout << "ZONE: " << id << endl;
   1.421 +            dumper.dump(cout);
   1.422 +            delete tz;
   1.423 +        }
   1.424 +    }
   1.425 +    delete zit;
   1.426 +}

mercurial