3 *******************************************************************************
4 * Copyright (C) 2008-2009, International Business Machines Corporation and *
5 * others. All Rights Reserved. *
6 *******************************************************************************
8 package com.ibm.icu.impl;
10 import java.io.IOException;
11 import java.io.ObjectInputStream;
12 import java.util.Date;
13 import java.util.TreeSet;
15 import com.ibm.icu.util.TimeZone;
18 * JavaTimeZone inherits com.ibm.icu.util.TimeZone and wraps java.util.TimeZone.
19 * We used to have JDKTimeZone which wrapped Java TimeZone and used it as primary
20 * TimeZone implementation until ICU4J 3.4.1. This class works exactly like
21 * JDKTimeZone and allows ICU users who use ICU4J and JDK date/time/calendar
22 * services in mix to maintain only JDK timezone rules.
24 * This TimeZone subclass is returned by the TimeZone factory method getTimeZone(String)
25 * when the default timezone type in TimeZone class is TimeZone.TIMEZONE_JDK.
27 public class JavaTimeZone extends TimeZone {
29 private static final long serialVersionUID = 6977448185543929364L;
31 private static final TreeSet AVAILABLESET;
33 private java.util.TimeZone javatz;
34 private transient java.util.Calendar javacal;
37 AVAILABLESET = new TreeSet();
38 String[] availableIds = java.util.TimeZone.getAvailableIDs();
39 for (int i = 0; i < availableIds.length; i++) {
40 AVAILABLESET.add(availableIds[i]);
45 * Constructs a JavaTimeZone with the default Java TimeZone
47 public JavaTimeZone() {
48 javatz = java.util.TimeZone.getDefault();
49 setID(javatz.getID());
50 javacal = new java.util.GregorianCalendar(javatz);
54 * Constructs a JavaTimeZone with the given timezone ID.
55 * @param id A timezone ID, either a system ID or a custom ID.
57 public JavaTimeZone(String id) {
58 if (AVAILABLESET.contains(id)) {
59 javatz = java.util.TimeZone.getTimeZone(id);
62 // Use ICU's canonical ID mapping
63 boolean[] isSystemID = new boolean[1];
64 String canonicalID = TimeZone.getCanonicalID(id, isSystemID);
65 if (isSystemID[0] && AVAILABLESET.contains(canonicalID)) {
66 javatz = java.util.TimeZone.getTimeZone(canonicalID);
71 int[] fields = new int[4];
72 if (ZoneMeta.parseCustomID(id, fields)) {
73 // JDK does not support offset seconds.
74 // If custom ID, we create java.util.SimpleTimeZone here.
75 id = ZoneMeta.formatCustomID(fields[1], fields[2], fields[3], fields[0] < 0);
76 int offset = fields[0] * ((fields[1] * 60 + fields[2]) * 60 + fields[3]) * 1000;
77 javatz = new java.util.SimpleTimeZone(offset, id);
83 javatz = java.util.TimeZone.getTimeZone(id);
86 javacal = new java.util.GregorianCalendar(javatz);
90 * @see com.ibm.icu.util.TimeZone#getOffset(int, int, int, int, int, int)
92 public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {
93 return javatz.getOffset(era, year, month, day, dayOfWeek, milliseconds);
97 * @see com.ibm.icu.util.TimeZone#getOffset(long, boolean, int[])
99 public void getOffset(long date, boolean local, int[] offsets) {
100 synchronized (javacal) {
102 int fields[] = new int[6];
103 Grego.timeToFields(date, fields);
104 int hour, min, sec, mil;
113 javacal.set(fields[0], fields[1], fields[2], hour, min, sec);
114 javacal.set(java.util.Calendar.MILLISECOND, mil);
116 int doy1, hour1, min1, sec1, mil1;
117 doy1 = javacal.get(java.util.Calendar.DAY_OF_YEAR);
118 hour1 = javacal.get(java.util.Calendar.HOUR_OF_DAY);
119 min1 = javacal.get(java.util.Calendar.MINUTE);
120 sec1 = javacal.get(java.util.Calendar.SECOND);
121 mil1 = javacal.get(java.util.Calendar.MILLISECOND);
123 if (fields[4] != doy1 || hour != hour1 || min != min1 || sec != sec1 || mil != mil1) {
124 // Calendar field(s) were changed due to the adjustment for non-existing time
125 // Note: This code does not support non-existing local time at year boundary properly.
126 // But, it should work fine for real timezones.
127 int dayDelta = Math.abs(doy1 - fields[4]) > 1 ? 1 : doy1 - fields[4];
128 int delta = ((((dayDelta * 24) + hour1 - hour) * 60 + min1 - min) * 60 + sec1 - sec) * 1000 + mil1 - mil;
130 // In this case, we use the offsets before the transition
131 //#if defined(FOUNDATION10) || defined(J2SE13)
132 //## javacal.setTime(new Date(javacal.getTime().getTime() - delta - 1));
134 javacal.setTimeInMillis(javacal.getTimeInMillis() - delta - 1);
138 //#if defined(FOUNDATION10) || defined(J2SE13)
139 //## javacal.setTime(new Date(date));
141 javacal.setTimeInMillis(date);
144 offsets[0] = javacal.get(java.util.Calendar.ZONE_OFFSET);
145 offsets[1] = javacal.get(java.util.Calendar.DST_OFFSET);
150 * @see com.ibm.icu.util.TimeZone#getRawOffset()
152 public int getRawOffset() {
153 return javatz.getRawOffset();
157 * @see com.ibm.icu.util.TimeZone#inDaylightTime(java.util.Date)
159 public boolean inDaylightTime(Date date) {
160 return javatz.inDaylightTime(date);
164 * @see com.ibm.icu.util.TimeZone#setRawOffset(int)
166 public void setRawOffset(int offsetMillis) {
167 javatz.setRawOffset(offsetMillis);
171 * @see com.ibm.icu.util.TimeZone#useDaylightTime()
173 public boolean useDaylightTime() {
174 return javatz.useDaylightTime();
178 * @see com.ibm.icu.util.TimeZone#getDSTSavings()
180 public int getDSTSavings() {
181 int dstSavings = super.getDSTSavings();
183 // hack so test compiles and runs in both JDK 1.3 and JDK 1.4+
184 final Object[] args = new Object[0];
185 final Class[] argtypes = new Class[0];
186 java.lang.reflect.Method m = javatz.getClass().getMethod("getDSTSavings", argtypes);
187 dstSavings = ((Integer) m.invoke(javatz, args)).intValue();
188 } catch (Exception e) {
189 // just use the result returned by super.getDSTSavings()
194 public java.util.TimeZone unwrap() {
199 * @see com.ibm.icu.util.TimeZone#clone()
201 public Object clone() {
202 JavaTimeZone other = (JavaTimeZone)super.clone();
203 other.javatz = (java.util.TimeZone)javatz.clone();
208 * @see com.ibm.icu.util.TimeZone#hashCode()
210 public int hashCode() {
211 return super.hashCode() + javatz.hashCode();
214 private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
215 s.defaultReadObject();
216 javacal = new java.util.GregorianCalendar(javatz);