2 *******************************************************************************
\r
3 * Copyright (C) 2008-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.impl;
\r
9 import java.io.IOException;
\r
10 import java.io.ObjectInputStream;
\r
11 import java.util.Date;
\r
12 import java.util.TreeSet;
\r
14 import com.ibm.icu.util.TimeZone;
\r
17 * JavaTimeZone inherits com.ibm.icu.util.TimeZone and wraps java.util.TimeZone.
\r
18 * We used to have JDKTimeZone which wrapped Java TimeZone and used it as primary
\r
19 * TimeZone implementation until ICU4J 3.4.1. This class works exactly like
\r
20 * JDKTimeZone and allows ICU users who use ICU4J and JDK date/time/calendar
\r
21 * services in mix to maintain only JDK timezone rules.
\r
23 * This TimeZone subclass is returned by the TimeZone factory method getTimeZone(String)
\r
24 * when the default timezone type in TimeZone class is TimeZone.TIMEZONE_JDK.
\r
26 public class JavaTimeZone extends TimeZone {
\r
28 private static final long serialVersionUID = 6977448185543929364L;
\r
30 private static final TreeSet<String> AVAILABLESET;
\r
32 private java.util.TimeZone javatz;
\r
33 private transient java.util.Calendar javacal;
\r
36 AVAILABLESET = new TreeSet<String>();
\r
37 String[] availableIds = java.util.TimeZone.getAvailableIDs();
\r
38 for (int i = 0; i < availableIds.length; i++) {
\r
39 AVAILABLESET.add(availableIds[i]);
\r
44 * Constructs a JavaTimeZone with the default Java TimeZone
\r
46 public JavaTimeZone() {
\r
47 javatz = java.util.TimeZone.getDefault();
\r
48 setID(javatz.getID());
\r
49 javacal = new java.util.GregorianCalendar(javatz);
\r
53 * Constructs a JavaTimeZone with the given timezone ID.
\r
54 * @param id A timezone ID, either a system ID or a custom ID.
\r
56 public JavaTimeZone(String id) {
\r
57 if (AVAILABLESET.contains(id)) {
\r
58 javatz = java.util.TimeZone.getTimeZone(id);
\r
60 if (javatz == null) {
\r
61 // Use ICU's canonical ID mapping
\r
62 boolean[] isSystemID = new boolean[1];
\r
63 String canonicalID = TimeZone.getCanonicalID(id, isSystemID);
\r
64 if (isSystemID[0] && AVAILABLESET.contains(canonicalID)) {
\r
65 javatz = java.util.TimeZone.getTimeZone(canonicalID);
\r
69 if (javatz == null){
\r
70 int[] fields = new int[4];
\r
71 if (ZoneMeta.parseCustomID(id, fields)) {
\r
72 // JDK does not support offset seconds.
\r
73 // If custom ID, we create java.util.SimpleTimeZone here.
\r
74 id = ZoneMeta.formatCustomID(fields[1], fields[2], fields[3], fields[0] < 0);
\r
75 int offset = fields[0] * ((fields[1] * 60 + fields[2]) * 60 + fields[3]) * 1000;
\r
76 javatz = new java.util.SimpleTimeZone(offset, id);
\r
79 if (javatz == null) {
\r
82 javatz = java.util.TimeZone.getTimeZone(id);
\r
85 javacal = new java.util.GregorianCalendar(javatz);
\r
89 * @see com.ibm.icu.util.TimeZone#getOffset(int, int, int, int, int, int)
\r
91 public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {
\r
92 return javatz.getOffset(era, year, month, day, dayOfWeek, milliseconds);
\r
96 * @see com.ibm.icu.util.TimeZone#getOffset(long, boolean, int[])
\r
98 public void getOffset(long date, boolean local, int[] offsets) {
\r
99 synchronized (javacal) {
\r
101 int fields[] = new int[6];
\r
102 Grego.timeToFields(date, fields);
\r
103 int hour, min, sec, mil;
\r
104 int tmp = fields[5];
\r
112 javacal.set(fields[0], fields[1], fields[2], hour, min, sec);
\r
113 javacal.set(java.util.Calendar.MILLISECOND, mil);
\r
115 int doy1, hour1, min1, sec1, mil1;
\r
116 doy1 = javacal.get(java.util.Calendar.DAY_OF_YEAR);
\r
117 hour1 = javacal.get(java.util.Calendar.HOUR_OF_DAY);
\r
118 min1 = javacal.get(java.util.Calendar.MINUTE);
\r
119 sec1 = javacal.get(java.util.Calendar.SECOND);
\r
120 mil1 = javacal.get(java.util.Calendar.MILLISECOND);
\r
122 if (fields[4] != doy1 || hour != hour1 || min != min1 || sec != sec1 || mil != mil1) {
\r
123 // Calendar field(s) were changed due to the adjustment for non-existing time
\r
124 // Note: This code does not support non-existing local time at year boundary properly.
\r
125 // But, it should work fine for real timezones.
\r
126 int dayDelta = Math.abs(doy1 - fields[4]) > 1 ? 1 : doy1 - fields[4];
\r
127 int delta = ((((dayDelta * 24) + hour1 - hour) * 60 + min1 - min) * 60 + sec1 - sec) * 1000 + mil1 - mil;
\r
129 // In this case, we use the offsets before the transition
\r
130 javacal.setTimeInMillis(javacal.getTimeInMillis() - delta - 1);
\r
133 javacal.setTimeInMillis(date);
\r
135 offsets[0] = javacal.get(java.util.Calendar.ZONE_OFFSET);
\r
136 offsets[1] = javacal.get(java.util.Calendar.DST_OFFSET);
\r
141 * @see com.ibm.icu.util.TimeZone#getRawOffset()
\r
143 public int getRawOffset() {
\r
144 return javatz.getRawOffset();
\r
148 * @see com.ibm.icu.util.TimeZone#inDaylightTime(java.util.Date)
\r
150 public boolean inDaylightTime(Date date) {
\r
151 return javatz.inDaylightTime(date);
\r
155 * @see com.ibm.icu.util.TimeZone#setRawOffset(int)
\r
157 public void setRawOffset(int offsetMillis) {
\r
158 javatz.setRawOffset(offsetMillis);
\r
162 * @see com.ibm.icu.util.TimeZone#useDaylightTime()
\r
164 public boolean useDaylightTime() {
\r
165 return javatz.useDaylightTime();
\r
169 * @see com.ibm.icu.util.TimeZone#getDSTSavings()
\r
171 public int getDSTSavings() {
\r
172 int dstSavings = super.getDSTSavings();
\r
174 // hack so test compiles and runs in both JDK 1.3 and JDK 1.4+
\r
175 final Object[] args = new Object[0];
\r
176 final Class<?>[] argtypes = new Class[0];
\r
177 java.lang.reflect.Method m = javatz.getClass().getMethod("getDSTSavings", argtypes);
\r
178 dstSavings = ((Integer) m.invoke(javatz, args)).intValue();
\r
179 } catch (Exception e) {
\r
180 // just use the result returned by super.getDSTSavings()
\r
185 public java.util.TimeZone unwrap() {
\r
190 * @see com.ibm.icu.util.TimeZone#clone()
\r
192 public Object clone() {
\r
193 JavaTimeZone other = (JavaTimeZone)super.clone();
\r
194 other.javatz = (java.util.TimeZone)javatz.clone();
\r
199 * @see com.ibm.icu.util.TimeZone#hashCode()
\r
201 public int hashCode() {
\r
202 return super.hashCode() + javatz.hashCode();
\r
205 private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
\r
206 s.defaultReadObject();
\r
207 javacal = new java.util.GregorianCalendar(javatz);
\r