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