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.

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

mercurial