2 ***********************************************************************
\r
3 * Copyright (C) 2007, International Business Machines *
\r
4 * Corporation and others. All Rights Reserved. *
\r
5 ***********************************************************************
\r
9 package com.ibm.icu.dev.tool.timezone;
\r
11 import java.io.BufferedWriter;
\r
12 import java.io.File;
\r
13 import java.io.FileOutputStream;
\r
14 import java.io.IOException;
\r
15 import java.io.OutputStreamWriter;
\r
16 import java.io.PrintWriter;
\r
17 import java.io.Writer;
\r
18 import java.lang.reflect.Method;
\r
19 import java.util.ArrayList;
\r
20 import java.util.Date;
\r
21 import java.util.Iterator;
\r
22 import java.util.List;
\r
23 import java.util.TreeSet;
\r
25 import com.ibm.icu.text.DecimalFormat;
\r
26 import com.ibm.icu.text.DecimalFormatSymbols;
\r
27 import com.ibm.icu.text.SimpleDateFormat;
\r
28 import com.ibm.icu.util.GregorianCalendar;
\r
29 import com.ibm.icu.util.SimpleTimeZone;
\r
30 import com.ibm.icu.util.ULocale;
\r
33 * TimeZone transition dump tool.
\r
35 public class ICUZDump {
\r
36 private static final String DEFAULT_LINE_SEP;
\r
39 String sep = System.getProperty("line.separator");
\r
40 DEFAULT_LINE_SEP = (sep == null) ? "\n" : sep;
\r
43 private TimeZoneImpl tz = null;
\r
45 private int loyear = 1900;
\r
46 private int hiyear = 2050;
\r
47 private long tick = 1000;
\r
48 private DumpFormatter formatter;
\r
49 private String linesep = DEFAULT_LINE_SEP;
\r
54 public void setLowYear(int loyear) {
\r
55 this.loyear = loyear;
\r
58 public void setHighYear(int hiyear) {
\r
59 this.hiyear = hiyear;
\r
62 public void setTick(int tick) {
\r
64 throw new IllegalArgumentException("tick must be positive");
\r
69 public void setTimeZone(Object tzimpl) {
\r
70 this.tz = new TimeZoneImpl(tzimpl);
\r
73 public void setDumpFormatter(DumpFormatter formatter) {
\r
74 this.formatter = formatter;
\r
77 public void setLineSeparator(String sep) {
\r
81 public void dump(Writer w) throws IOException {
\r
83 throw new IllegalStateException("timezone is not initialized");
\r
86 if (formatter == null) {
\r
87 formatter = new DumpFormatter();
\r
90 final long SEARCH_INCREMENT = 12 * 60 * 60 * 1000; // half day
\r
91 long cutovers[] = getCutOverTimes();
\r
92 long t = cutovers[0];
\r
93 int offset = tz.getOffset(t);
\r
94 boolean inDst = tz.inDaylightTime(t);
\r
95 while (t < cutovers[1]) {
\r
96 long newt = t + SEARCH_INCREMENT;
\r
97 int newOffset = tz.getOffset(newt);
\r
98 boolean newInDst = tz.inDaylightTime(newt);
\r
99 if (offset != newOffset || inDst != newInDst) {
\r
100 // find the boundary
\r
104 long diff = hit - lot;
\r
105 if (diff <= tick) {
\r
108 long medt = lot + ((diff / 2) / tick) * tick;
\r
109 int medOffset = tz.getOffset(medt);
\r
110 boolean medInDst = tz.inDaylightTime(medt);
\r
111 if (medOffset != offset || medInDst != inDst) {
\r
117 w.write(formatter.format(lot, offset, tz.inDaylightTime(lot)));
\r
119 w.write(formatter.format(hit, newOffset, tz.inDaylightTime(hit)));
\r
121 offset = newOffset;
\r
129 private long[] getCutOverTimes() {
\r
130 long[] cutovers = new long[2];
\r
131 cutovers[0] = tz.getTime(loyear, 0, 1, 0, 0, 0);
\r
132 cutovers[1] = tz.getTime(hiyear, 0, 1, 0, 0, 0);
\r
136 private class TimeZoneImpl {
\r
137 private Object tzobj;
\r
139 public TimeZoneImpl(Object tzobj) {
\r
140 this.tzobj = tzobj;
\r
143 public int getOffset(long time) {
\r
145 Method method = tzobj.getClass().getMethod("getOffset", new Class[] {long.class});
\r
146 Object result = method.invoke(tzobj, new Object[] {new Long(time)});
\r
147 return ((Integer)result).intValue();
\r
148 } catch (Exception e) {
\r
149 e.printStackTrace();
\r
154 public boolean inDaylightTime(long time) {
\r
156 Method method = tzobj.getClass().getMethod("inDaylightTime", new Class[] {Date.class});
\r
157 Object result = method.invoke(tzobj, new Object[] {new Date(time)});
\r
158 return ((Boolean)result).booleanValue();
\r
159 } catch (Exception e) {
\r
160 e.printStackTrace();
\r
165 public long getTime(int year, int month, int dayOfMonth, int hour, int minute, int second) {
\r
167 if (tzobj instanceof com.ibm.icu.util.TimeZone) {
\r
168 GregorianCalendar cal = new GregorianCalendar();
\r
169 cal.setTimeZone((com.ibm.icu.util.TimeZone)tzobj);
\r
171 cal.set(year, month, dayOfMonth, hour, minute, second);
\r
172 time = cal.getTimeInMillis();
\r
173 } else if (tzobj instanceof java.util.TimeZone) {
\r
174 java.util.GregorianCalendar cal = new java.util.GregorianCalendar();
\r
175 cal.setTimeZone((java.util.TimeZone)tzobj);
\r
177 cal.set(year, month, dayOfMonth, hour, minute, second);
\r
178 time = cal.getTimeInMillis();
\r
180 throw new IllegalStateException("Unsupported TimeZone implementation");
\r
186 public class DumpFormatter {
\r
187 private SimpleTimeZone stz = new SimpleTimeZone(0, "");
\r
188 private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd EEE HH:mm:ss", ULocale.US);
\r
189 private DecimalFormat decf;
\r
191 public DumpFormatter() {
\r
192 DecimalFormatSymbols decfs = new DecimalFormatSymbols(ULocale.US);
\r
193 decf = new DecimalFormat("00", decfs);
\r
196 public String format(long time, int offset, boolean isDst) {
\r
197 StringBuffer buf = new StringBuffer();
\r
198 stz.setRawOffset(offset);
\r
199 sdf.setTimeZone(stz);
\r
200 buf.append(sdf.format(new Date(time)));
\r
208 int hour, min, sec;
\r
212 offset = (offset - sec) / 60;
\r
214 hour = offset / 60;
\r
216 buf.append(decf.format(hour));
\r
217 buf.append(decf.format(min));
\r
218 buf.append(decf.format(sec));
\r
220 buf.append("[DST=");
\r
221 buf.append(isDst ? "1" : "0");
\r
223 return buf.toString();
\r
230 * java -cp icu4j.jar com.ibm.icu.dev.tool.timezone [-j] [-a] [-c[<low_year>,]<high_year>] [-d<dir>] [-l<sep>] [<zone_name> [<zone_name>]]
\r
233 * -j : Use JDK TimeZone. By default, ICU TimeZone is used.
\r
234 * -a : Dump all available zones.
\r
235 * -c[<low_year>,]<high_year>
\r
236 * : When specified, dump transitions starting <low_year> (inclusive) up to
\r
237 * <high_year> (exclusive). The default values are 1902(low) and 2038(high).
\r
238 * -d<dir> : When specified, write transitions in a file under the directory for each zone.
\r
239 * -l<sep> : New line code type CR/LF/CRLF.
\r
241 public static void main(String[] args) {
\r
242 boolean jdk = false;
\r
245 List idlist = new ArrayList();
\r
246 boolean all = false;
\r
248 String newLineMode = null;
\r
249 for (int i = 0; i < args.length; i++) {
\r
250 if (args[i].equals("-j")) {
\r
252 } else if (args[i].startsWith("-c")) {
\r
253 String val = args[i].substring(2);
\r
254 String[] years = val.split(",");
\r
255 if (years.length == 1) {
\r
256 high = Integer.parseInt(years[0]);
\r
257 } else if (years.length == 2) {
\r
258 low = Integer.parseInt(years[0]);
\r
259 high = Integer.parseInt(years[1]);
\r
261 } else if (args[i].equals("-a")) {
\r
263 } else if (args[i].startsWith("-d")) {
\r
264 dir = args[i].substring(2);
\r
265 } else if (args[i].startsWith("-l")) {
\r
266 newLineMode = args[i].substring(2);
\r
267 } else if (!args[i].startsWith("-")){
\r
268 idlist.add(args[i].trim());
\r
272 String lineSep = System.getProperty("line.separator");
\r
273 if (newLineMode != null && newLineMode.length() > 0) {
\r
274 if (newLineMode.equalsIgnoreCase("CR")) {
\r
276 } else if (newLineMode.equalsIgnoreCase("LF")) {
\r
278 } else if (newLineMode.equalsIgnoreCase("CRLF")) {
\r
283 String[] tzids = null;
\r
287 tzids = java.util.TimeZone.getAvailableIDs();
\r
289 tzids = com.ibm.icu.util.TimeZone.getAvailableIDs();
\r
293 TreeSet set = new TreeSet();
\r
294 for (int i = 0; i < tzids.length; i++) {
\r
297 Iterator it = set.iterator();
\r
299 while (it.hasNext()) {
\r
300 tzids[i++] = (String)it.next();
\r
303 int len = idlist.size();
\r
305 tzids = new String[1];
\r
306 tzids[0] = java.util.TimeZone.getDefault().getID();
\r
308 tzids = new String[idlist.size()];
\r
309 idlist.toArray(tzids);
\r
313 File dirfile = null;
\r
314 if (dir == null || dir.length() == 0) {
\r
315 PrintWriter pw = new PrintWriter(System.out);
\r
317 for (int i = 0; i < tzids.length; i++) {
\r
321 pw.write("ZONE: ");
\r
322 pw.write(tzids[i]);
\r
324 dumpZone(pw, lineSep, tzids[i], low, high, jdk);
\r
327 } catch (IOException ioe) {
\r
328 ioe.printStackTrace();
\r
331 dirfile = new File(dir);
\r
335 for (int i = 0; i < tzids.length; i++) {
\r
336 FileOutputStream fos = new FileOutputStream(new File(dirfile, tzids[i].replace('/', '-')));
\r
337 Writer w = new BufferedWriter(new OutputStreamWriter(fos));
\r
338 dumpZone(w, lineSep, tzids[i], low, high, jdk);
\r
341 } catch (IOException ioe) {
\r
342 ioe.printStackTrace();
\r
347 private static void dumpZone(Writer w, String lineSep, String tzid, int low, int high, boolean isJdk) throws IOException {
\r
348 ICUZDump dumper = new ICUZDump();
\r
351 tzimpl = java.util.TimeZone.getTimeZone(tzid);
\r
353 tzimpl = com.ibm.icu.util.TimeZone.getTimeZone(tzid);
\r
355 dumper.setTimeZone(tzimpl);
\r
356 dumper.setLowYear(low);
\r
357 dumper.setHighYear(high);
\r
358 dumper.setLineSeparator(lineSep);
\r