2 *******************************************************************************
4 * Copyright (C) 2007, 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
);
199 void dumpZone(ostream
& out
, const char* linesep
, UnicodeString tzid
, int32_t low
, int32_t high
) {
207 DumpFormatter
* formatter
;
213 ZoneIterator(UBool bAll
= FALSE
) {
215 zenum
= TimeZone::createEnumeration();
225 ZoneIterator(const char** ids
, int32_t num
) {
241 UErrorCode status
= U_ZERO_ERROR
;
242 const UnicodeString
* zid
= zenum
->snext(status
);
244 tz
= TimeZone::createTimeZone(*zid
);
250 tz
= TimeZone::createTimeZone((const UnicodeString
&)zids
[idx
]);
253 tz
= TimeZone::createDefault();
263 StringEnumeration
* zenum
;
270 kOptHelpQuestionMark
,
277 static UOption options
[]={
279 UOPTION_HELP_QUESTION_MARK
,
280 UOPTION_DEF("allzones", 'a', UOPT_NO_ARG
),
281 UOPTION_DEF("cutover", 'c', UOPT_REQUIRES_ARG
),
282 UOPTION_DEF("destdir", 'd', UOPT_REQUIRES_ARG
),
283 UOPTION_DEF("linesep", 'l', UOPT_REQUIRES_ARG
)
287 main(int argc
, char *argv
[]) {
291 const char *dir
= NULL
;
292 const char *linesep
= NULL
;
294 U_MAIN_INIT_ARGS(argc
, argv
);
295 argc
= u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[0]), options
);
298 cerr
<< "Illegal command line argument(s)" << endl
<< endl
;
301 if (argc
< 0 || options
[kOptHelpH
].doesOccur
|| options
[kOptHelpQuestionMark
].doesOccur
) {
303 << "Usage: icuzdump [-options] [zoneid1 zoneid2 ...]" << endl
305 << "\tDump all offset transitions for the specified zones." << endl
307 << "Options:" << endl
308 << "\t-a : Dump all available zones." << endl
309 << "\t-d <dir> : When specified, write transitions in a file under" << endl
310 << "\t the directory for each zone." << endl
311 << "\t-l <sep> : New line code type used in file outputs. CR or LF (default)"
312 << "\t or CRLF." << endl
313 << "\t-c [<low_year>,]<high_year>" << endl
314 << "\t : When specified, dump transitions starting <low_year>" << endl
315 << "\t (inclusive) up to <high_year> (exclusive). The default" << endl
316 << "\t values are 1902(low) and 2038(high)." << endl
;
317 return argc
< 0 ? U_ILLEGAL_ARGUMENT_ERROR
: U_ZERO_ERROR
;
320 bAll
= options
[kOptAllZones
].doesOccur
;
322 if (options
[kOptDestDir
].doesOccur
) {
323 dir
= options
[kOptDestDir
].value
;
326 if (options
[kOptLineSep
].doesOccur
) {
327 if (strcmp(options
[kOptLineSep
].value
, "CR") == 0) {
329 } else if (strcmp(options
[kOptLineSep
].value
, "CRLF") == 0) {
331 } else if (strcmp(options
[kOptLineSep
].value
, "LF") == 0) {
336 if (options
[kOptCutover
].doesOccur
) {
337 char* comma
= (char*)strchr(options
[kOptCutover
].value
, ',');
339 high
= atoi(options
[kOptCutover
].value
);
342 low
= atoi(options
[kOptCutover
].value
);
343 high
= atoi(comma
+ 1);
348 dumper
.setLowYear(low
);
349 dumper
.setHighYear(high
);
350 if (dir
!= NULL
&& linesep
!= NULL
) {
351 // use the specified line separator only for file output
352 dumper
.setLineSeparator((const char*)linesep
);
357 zit
= new ZoneIterator(TRUE
);
360 zit
= new ZoneIterator();
362 zit
= new ZoneIterator((const char**)&argv
[1], argc
- 1);
370 ios::openmode mode
= ios::out
;
371 if (linesep
!= NULL
) {
375 TimeZone
* tz
= zit
->next();
379 dumper
.setTimeZone(tz
);
384 path
<< dir
<< U_FILE_SEP_CHAR
;
385 id
= id
.findAndReplace("/", "-");
388 ofstream
* fout
= new ofstream(path
.str().c_str(), mode
);
390 cerr
<< "Cannot open file " << path
<< endl
;
406 TimeZone
* tz
= zit
->next();
410 dumper
.setTimeZone(tz
);
417 cout
<< "ZONE: " << id
<< endl
;