001: /*
002: * Copyright 2000-2004 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.tools.javazic;
027:
028: import java.util.ArrayList;
029: import java.util.List;
030:
031: /**
032: * Timezone represents all information of a single point of time to
033: * generate its time zone database.
034: *
035: * @since 1.4
036: */
037: class Timezone {
038: /**
039: * zone name of this time zone
040: */
041: private String name;
042:
043: /**
044: * transition time values in UTC (millisecond)
045: */
046: private List<Long> transitions;
047:
048: /**
049: * All offset values in millisecond
050: * @see sun.util.calendar.ZoneInfo
051: */
052: private List<Integer> offsets;
053:
054: /**
055: * Indices of GMT offset values (both raw and raw+saving)
056: * at transitions
057: */
058: private List<Integer> gmtOffsets;
059:
060: /**
061: * Indices of regular or "direct" saving time values
062: * at transitions
063: */
064: private List<Integer> dstOffsets;
065:
066: /**
067: * Zone records of this time zone
068: */
069: private List<ZoneRec> usedZoneRecs;
070:
071: /**
072: * Rule records referred to by this time zone
073: */
074: private List<RuleRec> usedRuleRecs;
075:
076: /**
077: * Type of DST rules in this time zone
078: */
079: private int dstType;
080: static final int UNDEF_DST = 0; // DST type not set yet
081: static final int NO_DST = 1; // never observed DST
082: static final int LAST_DST = 2; // last rule ends in DST (all year round DST-only)
083: static final int X_DST = 3; // used to observe DST
084: static final int DST = 4; // observing DST regularly
085:
086: /**
087: * Raw GMT offset of this time zone in the last rule
088: */
089: private int rawOffset;
090:
091: /**
092: * The CRC32 value of the transitions data
093: */
094: private int crc32;
095:
096: /**
097: * The last ZoneRec
098: */
099: private ZoneRec lastZoneRec;
100:
101: /**
102: * The last DST rules. lastRules[0] is the DST start
103: * rule. lastRules[1] is the DST end rules.
104: */
105: private List<RuleRec> lastRules;
106:
107: /**
108: * The amount of DST saving value (millisecond) in the last DST
109: * rule.
110: */
111: private int lastSaving;
112:
113: /**
114: * true if the raw offset will change in the future time.
115: */
116: private boolean willRawOffsetChange = false;
117:
118: /**
119: * Constracts a Timezone object with the given zone name.
120: * @param name the zone name
121: */
122: Timezone(String name) {
123: this .name = name;
124: }
125:
126: /**
127: * @return the number of transitions
128: */
129: int getNTransitions() {
130: if (transitions == null) {
131: return 0;
132: }
133: return transitions.size();
134: }
135:
136: /**
137: * @return the zone name
138: */
139: String getName() {
140: return name;
141: }
142:
143: /**
144: * Returns the list of all rule records that have been referred to
145: * by this time zone.
146: * @return the rule records list
147: */
148: List<RuleRec> getRules() {
149: return usedRuleRecs;
150: }
151:
152: /**
153: * Returns the list of all zone records that have been referred to
154: * by this time zone.
155: * @return the zone records list
156: */
157: List<ZoneRec> getZones() {
158: return usedZoneRecs;
159: }
160:
161: /**
162: * @return the transition table (list)
163: */
164: List<Long> getTransitions() {
165: return transitions;
166: }
167:
168: /**
169: * @return the offsets list
170: */
171: List<Integer> getOffsets() {
172: return offsets;
173: }
174:
175: /**
176: * @return the DST saving offsets list
177: */
178: List<Integer> getDstOffsets() {
179: return dstOffsets;
180: }
181:
182: /**
183: * @return the GMT offsets list
184: */
185: List<Integer> getGmtOffsets() {
186: return gmtOffsets;
187: }
188:
189: /**
190: * @return the checksum (crc32) value of the trasition table
191: */
192: int getCRC32() {
193: return crc32;
194: }
195:
196: /**
197: * @return true if the GMT offset of this time zone would change
198: * after the time zone database has been generated, false, otherwise.
199: */
200: boolean willGMTOffsetChange() {
201: return willRawOffsetChange;
202: }
203:
204: /**
205: * @return the last known GMT offset value in milliseconds
206: */
207: int getRawOffset() {
208: return rawOffset;
209: }
210:
211: /**
212: * Sets time zone's GMT offset to <code>offset</code>.
213: * @param offset the GMT offset value in milliseconds
214: */
215: void setRawOffset(int offset) {
216: rawOffset = offset;
217: }
218:
219: /**
220: * Sets time zone's GMT offset value to <code>offset</code>. If
221: * <code>startTime</code> is future time, then the {@link
222: * #willRawOffsetChange} value is set to true.
223: * @param offset the GMT offset value in milliseconds
224: * @param startTime the UTC time at which the GMT offset is in effective
225: */
226: void setRawOffset(int offset, long startTime) {
227: // if this rawOffset is for the future time, let the run-time
228: // look for the current GMT offset.
229: if (startTime > Time.getCurrentTime()) {
230: willRawOffsetChange = true;
231: }
232: setRawOffset(offset);
233: }
234:
235: /**
236: * Adds the specified transition information to the end of the transition table.
237: * @param time the UTC time at which this transition happens
238: * @param offset the total amount of the offset from GMT in milliseconds
239: * @param dstOffset the amount of time in milliseconds saved at this transition
240: */
241: void addTransition(long time, int offset, int dstOffset) {
242: if (transitions == null) {
243: transitions = new ArrayList<Long>();
244: offsets = new ArrayList<Integer>();
245: dstOffsets = new ArrayList<Integer>();
246: }
247: transitions.add(time);
248: offsets.add(offset);
249: dstOffsets.add(dstOffset);
250: }
251:
252: /**
253: * Sets the type of historical daylight saving time
254: * observation. For example, China used to observed daylight
255: * saving time, but it no longer does. Then, X_DST is set to the
256: * China time zone.
257: * @param type the type of daylight saving time
258: */
259: void setDSTType(int type) {
260: dstType = type;
261: }
262:
263: /**
264: * @return the type of historical daylight saving time
265: * observation.
266: */
267: int getDSTType() {
268: return dstType;
269: }
270:
271: /**
272: * Adds the specified zone record to the zone records list.
273: * @param rec the zone record
274: */
275: void addUsedRec(ZoneRec rec) {
276: if (usedZoneRecs == null) {
277: usedZoneRecs = new ArrayList<ZoneRec>();
278: }
279: usedZoneRecs.add(rec);
280: }
281:
282: /**
283: * Adds the specified rule record to the rule records list.
284: * @param rec the rule record
285: */
286: void addUsedRec(RuleRec rec) {
287: if (usedRuleRecs == null) {
288: usedRuleRecs = new ArrayList<RuleRec>();
289: }
290: // if the last used rec is the same as the given rec, avoid
291: // putting the same rule.
292: int n = usedRuleRecs.size();
293: for (int i = 0; i < n; i++) {
294: if (usedRuleRecs.get(i).equals(rec)) {
295: return;
296: }
297: }
298: usedRuleRecs.add(rec);
299: }
300:
301: /**
302: * Sets the last zone record for this time zone.
303: * @param the last zone record
304: */
305: void setLastZoneRec(ZoneRec zrec) {
306: lastZoneRec = zrec;
307: }
308:
309: /**
310: * @return the last zone record for this time zone.
311: */
312: ZoneRec getLastZoneRec() {
313: return lastZoneRec;
314: }
315:
316: /**
317: * Sets the last rule records for this time zone. Those are used
318: * for generating SimpleTimeZone parameters.
319: * @param rules the last rule records
320: */
321: void setLastRules(List<RuleRec> rules) {
322: int n = rules.size();
323: if (n > 0) {
324: lastRules = rules;
325: RuleRec rec = rules.get(0);
326: int offset = rec.getSave();
327: if (offset > 0) {
328: setLastDSTSaving(offset);
329: } else {
330: System.err
331: .println("\t No DST starting rule in the last rules.");
332: }
333: }
334: }
335:
336: /**
337: * @return the last rule records for this time zone.
338: */
339: List<RuleRec> getLastRules() {
340: return lastRules;
341: }
342:
343: /**
344: * Sets the last daylight saving amount.
345: * @param the daylight saving amount
346: */
347: void setLastDSTSaving(int offset) {
348: lastSaving = offset;
349: }
350:
351: /**
352: * @return the last daylight saving amount.
353: */
354: int getLastDSTSaving() {
355: return lastSaving;
356: }
357:
358: /**
359: * Calculates the CRC32 value from the transition table and sets
360: * the value to <code>crc32</code>.
361: */
362: void checksum() {
363: if (transitions == null) {
364: crc32 = 0;
365: return;
366: }
367: Checksum sum = new Checksum();
368: for (int i = 0; i < transitions.size(); i++) {
369: int offset = offsets.get(i);
370: // adjust back to make the transition in local time
371: sum.update(transitions.get(i) + offset);
372: sum.update(offset);
373: sum.update(dstOffsets.get(i));
374: }
375: crc32 = (int) sum.getValue();
376: }
377:
378: /**
379: * Removes unnecessary transitions for Java time zone support.
380: */
381: void optimize() {
382: // if there is only one offset, delete all transitions. This
383: // could happen if only time zone abbreviations changed.
384: if (gmtOffsets.size() == 1) {
385: transitions = null;
386: usedRuleRecs = null;
387: setDSTType(NO_DST);
388: return;
389: }
390: for (int i = 0; i < (transitions.size() - 2); i++) { // don't remove the last one
391: if (transitions.get(i) == transitions.get(i + 1)) {
392: transitions.remove(i);
393: offsets.remove(i);
394: dstOffsets.remove(i);
395: i--;
396: }
397: }
398:
399: for (int i = 0; i < (transitions.size() - 2); i++) { // don't remove the last one
400: if (offsets.get(i) == offsets.get(i + 1)
401: && dstOffsets.get(i) == dstOffsets.get(i + 1)) {
402: transitions.remove(i + 1);
403: offsets.remove(i + 1);
404: dstOffsets.remove(i + 1);
405: i--;
406: }
407: }
408: }
409:
410: /**
411: * Stores the specified offset value from GMT in the GMT offsets
412: * table and returns its index. The offset value includes the base
413: * GMT offset and any additional daylight saving if applicable. If
414: * the same value as the specified offset is already in the table,
415: * its index is returned.
416: * @param offset the offset value in milliseconds
417: * @return the index to the offset value in the GMT offsets table.
418: */
419: int getOffsetIndex(int offset) {
420: return getOffsetIndex(offset, 0);
421: }
422:
423: /**
424: * Stores the specified daylight saving value in the GMT offsets
425: * table and returns its index. If the same value as the specified
426: * offset is already in the table, its index is returned. If 0 is
427: * specified, it's not stored in the table and -1 is returned.
428: * @param offset the offset value in milliseconds
429: * @return the index to the specified offset value in the GMT
430: * offsets table, or -1 if 0 is specified.
431: */
432: int getDstOffsetIndex(int offset) {
433: if (offset == 0) {
434: return -1;
435: }
436: return getOffsetIndex(offset, 1);
437: }
438:
439: private int getOffsetIndex(int offset, int index) {
440: if (gmtOffsets == null) {
441: gmtOffsets = new ArrayList<Integer>();
442: }
443: for (int i = index; i < gmtOffsets.size(); i++) {
444: if (offset == gmtOffsets.get(i)) {
445: return i;
446: }
447: }
448: if (gmtOffsets.size() < index) {
449: gmtOffsets.add(0);
450: }
451: gmtOffsets.add(offset);
452: return gmtOffsets.size() - 1;
453: }
454: }
|