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"
45 UErrorCode status
= U_ZERO_ERROR
;
46 stz
= new SimpleTimeZone(0, "");
47 sdf
= new SimpleDateFormat((UnicodeString
)"yyyy-MM-dd EEE HH:mm:ss", Locale::getEnglish(), status
);
48 DecimalFormatSymbols
*symbols
= new DecimalFormatSymbols(Locale::getEnglish(), status
);
49 decf
= new DecimalFormat("00", symbols
, status
);
54 UnicodeString
& format(UDate time
, int32_t offset
, UBool isDst
, UnicodeString
& appendTo
) {
55 stz
->setRawOffset(offset
);
56 sdf
->setTimeZone(*stz
);
57 UnicodeString str
= sdf
->format(time
, appendTo
);
65 int32_t hour
, min
, sec
;
69 offset
= (offset
- sec
) / 60;
73 decf
->format(hour
, appendTo
);
74 decf
->format(min
, appendTo
);
75 decf
->format(sec
, appendTo
);
87 SimpleDateFormat
* sdf
;
94 formatter
= new DumpFormatter();
104 void setLowYear(int32_t lo
) {
108 void setHighYear(int32_t hi
) {
112 void setTick(int32_t t
) {
116 void setTimeZone(TimeZone
* tz
) {
120 void setDumpFormatter(DumpFormatter
* fmt
) {
124 void setLineSeparator(const char* sep
) {
128 void dump(ostream
& out
) {
129 UErrorCode status
= U_ZERO_ERROR
;
130 UDate SEARCH_INCREMENT
= 12 * 60 * 60 * 1000; // half day
131 UDate t
, cutlo
, cuthi
;
132 int32_t rawOffset
, dstOffset
;
135 getCutOverTimes(cutlo
, cuthi
);
137 timezone
->getOffset(t
, FALSE
, rawOffset
, dstOffset
, status
);
139 int32_t newRawOffset
, newDstOffset
;
140 UDate newt
= t
+ SEARCH_INCREMENT
;
142 timezone
->getOffset(newt
, FALSE
, newRawOffset
, newDstOffset
, status
);
144 UBool bSameOffset
= (rawOffset
+ dstOffset
) == (newRawOffset
+ newDstOffset
);
145 UBool bSameDst
= ((dstOffset
!= 0) && (newDstOffset
!= 0)) || ((dstOffset
== 0) && (newDstOffset
== 0));
147 if (!bSameOffset
|| !bSameDst
) {
152 int32_t diff
= (int32_t)(hit
- lot
);
156 UDate medt
= lot
+ ((diff
/ 2) / tick
) * tick
;
157 int32_t medRawOffset
, medDstOffset
;
158 timezone
->getOffset(medt
, FALSE
, medRawOffset
, medDstOffset
, status
);
160 bSameOffset
= (rawOffset
+ dstOffset
) == (medRawOffset
+ medDstOffset
);
161 bSameDst
= ((dstOffset
!= 0) && (medDstOffset
!= 0)) || ((dstOffset
== 0) && (medDstOffset
== 0));
163 if (!bSameOffset
|| !bSameDst
) {
169 // write out the boundary
171 formatter
->format(lot
, rawOffset
+ dstOffset
, (dstOffset
== 0 ? FALSE
: TRUE
), str
);
174 formatter
->format(hit
, newRawOffset
+ newDstOffset
, (newDstOffset
== 0 ? FALSE
: TRUE
), str
);
176 if (linesep
!= NULL
) {
182 rawOffset
= newRawOffset
;
183 dstOffset
= newDstOffset
;
190 void getCutOverTimes(UDate
& lo
, UDate
& hi
) {
191 UErrorCode status
= U_ZERO_ERROR
;
192 GregorianCalendar
* gcal
= new GregorianCalendar(timezone
, Locale::getEnglish(), status
);
194 gcal
->set(loyear
, 0, 1, 0, 0, 0);
195 lo
= gcal
->getTime(status
);
196 gcal
->set(hiyear
, 0, 1, 0, 0, 0);
197 hi
= gcal
->getTime(status
);
205 DumpFormatter
* formatter
;
211 ZoneIterator(UBool bAll
= FALSE
) {
213 zenum
= TimeZone::createEnumeration();
223 ZoneIterator(const char** ids
, int32_t num
) {
239 UErrorCode status
= U_ZERO_ERROR
;
240 const UnicodeString
* zid
= zenum
->snext(status
);
242 tz
= TimeZone::createTimeZone(*zid
);
248 tz
= TimeZone::createTimeZone((const UnicodeString
&)zids
[idx
]);
251 tz
= TimeZone::createDefault();
261 StringEnumeration
* zenum
;
268 kOptHelpQuestionMark
,
275 static UOption options
[]={
277 UOPTION_HELP_QUESTION_MARK
,
278 UOPTION_DEF("allzones", 'a', UOPT_NO_ARG
),
279 UOPTION_DEF("cutover", 'c', UOPT_REQUIRES_ARG
),
280 UOPTION_DEF("destdir", 'd', UOPT_REQUIRES_ARG
),
281 UOPTION_DEF("linesep", 'l', UOPT_REQUIRES_ARG
)
285 main(int argc
, char *argv
[]) {
289 const char *dir
= NULL
;
290 const char *linesep
= NULL
;
292 U_MAIN_INIT_ARGS(argc
, argv
);
293 argc
= u_parseArgs(argc
, argv
, UPRV_LENGTHOF(options
), options
);
296 cerr
<< "Illegal command line argument(s)" << endl
<< endl
;
299 if (argc
< 0 || options
[kOptHelpH
].doesOccur
|| options
[kOptHelpQuestionMark
].doesOccur
) {
301 << "Usage: icuzdump [-options] [zoneid1 zoneid2 ...]" << endl
303 << "\tDump all offset transitions for the specified zones." << endl
305 << "Options:" << endl
306 << "\t-a : Dump all available zones." << endl
307 << "\t-d <dir> : When specified, write transitions in a file under" << endl
308 << "\t the directory for each zone." << endl
309 << "\t-l <sep> : New line code type used in file outputs. CR or LF (default)"
310 << "\t or CRLF." << endl
311 << "\t-c [<low_year>,]<high_year>" << endl
312 << "\t : When specified, dump transitions starting <low_year>" << endl
313 << "\t (inclusive) up to <high_year> (exclusive). The default" << endl
314 << "\t values are 1902(low) and 2038(high)." << endl
;
315 return argc
< 0 ? U_ILLEGAL_ARGUMENT_ERROR
: U_ZERO_ERROR
;
318 bAll
= options
[kOptAllZones
].doesOccur
;
320 if (options
[kOptDestDir
].doesOccur
) {
321 dir
= options
[kOptDestDir
].value
;
324 if (options
[kOptLineSep
].doesOccur
) {
325 if (strcmp(options
[kOptLineSep
].value
, "CR") == 0) {
327 } else if (strcmp(options
[kOptLineSep
].value
, "CRLF") == 0) {
329 } else if (strcmp(options
[kOptLineSep
].value
, "LF") == 0) {
334 if (options
[kOptCutover
].doesOccur
) {
335 char* comma
= (char*)strchr(options
[kOptCutover
].value
, ',');
337 high
= atoi(options
[kOptCutover
].value
);
340 low
= atoi(options
[kOptCutover
].value
);
341 high
= atoi(comma
+ 1);
346 dumper
.setLowYear(low
);
347 dumper
.setHighYear(high
);
348 if (dir
!= NULL
&& linesep
!= NULL
) {
349 // use the specified line separator only for file output
350 dumper
.setLineSeparator((const char*)linesep
);
355 zit
= new ZoneIterator(TRUE
);
358 zit
= new ZoneIterator();
360 zit
= new ZoneIterator((const char**)&argv
[1], argc
- 1);
368 ios::openmode mode
= ios::out
;
369 if (linesep
!= NULL
) {
373 TimeZone
* tz
= zit
->next();
377 dumper
.setTimeZone(tz
);
382 path
<< dir
<< U_FILE_SEP_CHAR
;
383 id
= id
.findAndReplace("/", "-");
386 ofstream
* fout
= new ofstream(path
.str().c_str(), mode
);
388 cerr
<< "Cannot open file " << path
.str() << endl
;
404 TimeZone
* tz
= zit
->next();
408 dumper
.setTimeZone(tz
);
415 cout
<< "ZONE: " << id
<< endl
;