2 *******************************************************************************
4 * Copyright (C) 2007-2016, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: icuzdump.cpp
10 * tab size: 8 (not used)
13 * created on: 2007-04-02
14 * created by: Yoshito Umaoka
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.
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"
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
);
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
);
64 int32_t hour
, min
, sec
;
68 offset
= (offset
- sec
) / 60;
72 decf
->format(hour
, appendTo
);
73 decf
->format(min
, appendTo
);
74 decf
->format(sec
, appendTo
);
86 SimpleDateFormat
* sdf
;
93 formatter
= new DumpFormatter();
103 void setLowYear(int32_t lo
) {
107 void setHighYear(int32_t hi
) {
111 void setTick(int32_t t
) {
115 void setTimeZone(TimeZone
* tz
) {
119 void setDumpFormatter(DumpFormatter
* fmt
) {
123 void setLineSeparator(const char* sep
) {
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
;
134 getCutOverTimes(cutlo
, cuthi
);
136 timezone
->getOffset(t
, FALSE
, rawOffset
, dstOffset
, status
);
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
) {
151 int32_t diff
= (int32_t)(hit
- lot
);
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
) {
168 // write out the boundary
170 formatter
->format(lot
, rawOffset
+ dstOffset
, (dstOffset
== 0 ? FALSE
: TRUE
), str
);
173 formatter
->format(hit
, newRawOffset
+ newDstOffset
, (newDstOffset
== 0 ? FALSE
: TRUE
), str
);
175 if (linesep
!= NULL
) {
181 rawOffset
= newRawOffset
;
182 dstOffset
= newDstOffset
;
189 void getCutOverTimes(UDate
& lo
, UDate
& hi
) {
190 UErrorCode status
= U_ZERO_ERROR
;
191 GregorianCalendar
* gcal
= new GregorianCalendar(timezone
, Locale::getEnglish(), status
);
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
);
204 DumpFormatter
* formatter
;
210 ZoneIterator(UBool bAll
= FALSE
) {
212 zenum
= TimeZone::createEnumeration();
222 ZoneIterator(const char** ids
, int32_t num
) {
238 UErrorCode status
= U_ZERO_ERROR
;
239 const UnicodeString
* zid
= zenum
->snext(status
);
241 tz
= TimeZone::createTimeZone(*zid
);
247 tz
= TimeZone::createTimeZone((const UnicodeString
&)zids
[idx
]);
250 tz
= TimeZone::createDefault();
260 StringEnumeration
* zenum
;
267 kOptHelpQuestionMark
,
274 static UOption options
[]={
276 UOPTION_HELP_QUESTION_MARK
,
277 UOPTION_DEF("allzones", 'a', UOPT_NO_ARG
),
278 UOPTION_DEF("cutover", 'c', UOPT_REQUIRES_ARG
),
279 UOPTION_DEF("destdir", 'd', UOPT_REQUIRES_ARG
),
280 UOPTION_DEF("linesep", 'l', UOPT_REQUIRES_ARG
)
284 main(int argc
, char *argv
[]) {
288 const char *dir
= NULL
;
289 const char *linesep
= NULL
;
291 U_MAIN_INIT_ARGS(argc
, argv
);
292 argc
= u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[0]), options
);
295 cerr
<< "Illegal command line argument(s)" << endl
<< endl
;
298 if (argc
< 0 || options
[kOptHelpH
].doesOccur
|| options
[kOptHelpQuestionMark
].doesOccur
) {
300 << "Usage: icuzdump [-options] [zoneid1 zoneid2 ...]" << endl
302 << "\tDump all offset transitions for the specified zones." << endl
304 << "Options:" << endl
305 << "\t-a : Dump all available zones." << endl
306 << "\t-d <dir> : When specified, write transitions in a file under" << endl
307 << "\t the directory for each zone." << endl
308 << "\t-l <sep> : New line code type used in file outputs. CR or LF (default)"
309 << "\t or CRLF." << endl
310 << "\t-c [<low_year>,]<high_year>" << endl
311 << "\t : When specified, dump transitions starting <low_year>" << endl
312 << "\t (inclusive) up to <high_year> (exclusive). The default" << endl
313 << "\t values are 1902(low) and 2038(high)." << endl
;
314 return argc
< 0 ? U_ILLEGAL_ARGUMENT_ERROR
: U_ZERO_ERROR
;
317 bAll
= options
[kOptAllZones
].doesOccur
;
319 if (options
[kOptDestDir
].doesOccur
) {
320 dir
= options
[kOptDestDir
].value
;
323 if (options
[kOptLineSep
].doesOccur
) {
324 if (strcmp(options
[kOptLineSep
].value
, "CR") == 0) {
326 } else if (strcmp(options
[kOptLineSep
].value
, "CRLF") == 0) {
328 } else if (strcmp(options
[kOptLineSep
].value
, "LF") == 0) {
333 if (options
[kOptCutover
].doesOccur
) {
334 char* comma
= (char*)strchr(options
[kOptCutover
].value
, ',');
336 high
= atoi(options
[kOptCutover
].value
);
339 low
= atoi(options
[kOptCutover
].value
);
340 high
= atoi(comma
+ 1);
345 dumper
.setLowYear(low
);
346 dumper
.setHighYear(high
);
347 if (dir
!= NULL
&& linesep
!= NULL
) {
348 // use the specified line separator only for file output
349 dumper
.setLineSeparator((const char*)linesep
);
354 zit
= new ZoneIterator(TRUE
);
357 zit
= new ZoneIterator();
359 zit
= new ZoneIterator((const char**)&argv
[1], argc
- 1);
367 ios::openmode mode
= ios::out
;
368 if (linesep
!= NULL
) {
372 TimeZone
* tz
= zit
->next();
376 dumper
.setTimeZone(tz
);
381 path
<< dir
<< U_FILE_SEP_CHAR
;
382 id
= id
.findAndReplace("/", "-");
385 ofstream
* fout
= new ofstream(path
.str().c_str(), mode
);
387 cerr
<< "Cannot open file " << path
.str() << endl
;
403 TimeZone
* tz
= zit
->next();
407 dumper
.setTimeZone(tz
);
414 cout
<< "ZONE: " << id
<< endl
;