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 +}