| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html#License |
| /* |
| ******************************************************************************* |
| * Copyright (C) 2008-2014, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| */ |
| package com.ibm.icu.impl.icuadapter; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.GregorianCalendar; |
| import java.util.Locale; |
| import java.util.TimeZone; |
| |
| import com.ibm.icu.impl.Grego; |
| import com.ibm.icu.impl.jdkadapter.TimeZoneICU; |
| import com.ibm.icu.util.ULocale; |
| |
| /** |
| * TimeZoneJDK is an adapter class which wraps java.util.TimeZone and |
| * implements ICU4J TimeZone APIs. |
| */ |
| public class TimeZoneJDK extends com.ibm.icu.util.TimeZone { |
| |
| private static final long serialVersionUID = -1137052823551791933L; |
| |
| private TimeZone fJdkTz; |
| private transient Calendar fJdkCal; |
| private static Method mObservesDaylightTime; |
| |
| static { |
| try { |
| mObservesDaylightTime = TimeZone.class.getMethod("observesDaylightTime", (Class[]) null); |
| } catch (NoSuchMethodException e) { |
| // Java 6 or older |
| } catch (SecurityException e) { |
| // not visible |
| } |
| } |
| |
| private TimeZoneJDK(TimeZone jdkTz) { |
| fJdkTz = (TimeZone)jdkTz.clone(); |
| } |
| |
| public static com.ibm.icu.util.TimeZone wrap(TimeZone jdkTz) { |
| if (jdkTz instanceof TimeZoneICU) { |
| return ((TimeZoneICU)jdkTz).unwrap(); |
| } |
| return new TimeZoneJDK(jdkTz); |
| } |
| |
| public TimeZone unwrap() { |
| return (TimeZone)fJdkTz.clone(); |
| } |
| |
| @Override |
| public Object clone() { |
| if (isFrozen()) { |
| return this; |
| } |
| return cloneAsThawed(); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof TimeZoneJDK) { |
| return (((TimeZoneJDK)obj).fJdkTz).equals(fJdkTz); |
| } |
| return false; |
| } |
| |
| //public String getDisplayName() |
| //public String getDisplayName(boolean daylight, int style) |
| //public String getDisplayName(Locale locale) |
| //public String getDisplayName(ULocale locale) |
| @Override |
| public String getDisplayName(boolean daylight, int style, Locale locale) { |
| return fJdkTz.getDisplayName(daylight, style, locale); |
| } |
| |
| @Override |
| public String getDisplayName(boolean daylight, int style, ULocale locale) { |
| return fJdkTz.getDisplayName(daylight, style, locale.toLocale()); |
| } |
| |
| @Override |
| public int getDSTSavings() { |
| return fJdkTz.getDSTSavings(); |
| } |
| |
| @Override |
| public String getID() { |
| return fJdkTz.getID(); |
| } |
| |
| @Override |
| public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) { |
| return fJdkTz.getOffset(era, year, month, day, dayOfWeek, milliseconds); |
| } |
| |
| @Override |
| public int getOffset(long date) { |
| return fJdkTz.getOffset(date); |
| } |
| |
| @Override |
| public void getOffset(long date, boolean local, int[] offsets) { |
| synchronized(this) { |
| if (fJdkCal == null) { |
| fJdkCal = new GregorianCalendar(fJdkTz); |
| } |
| if (local) { |
| int fields[] = new int[6]; |
| Grego.timeToFields(date, fields); |
| int hour, min, sec, mil; |
| int tmp = fields[5]; |
| mil = tmp % 1000; |
| tmp /= 1000; |
| sec = tmp % 60; |
| tmp /= 60; |
| min = tmp % 60; |
| hour = tmp / 60; |
| fJdkCal.clear(); |
| fJdkCal.set(fields[0], fields[1], fields[2], hour, min, sec); |
| fJdkCal.set(java.util.Calendar.MILLISECOND, mil); |
| |
| int doy1, hour1, min1, sec1, mil1; |
| doy1 = fJdkCal.get(java.util.Calendar.DAY_OF_YEAR); |
| hour1 = fJdkCal.get(java.util.Calendar.HOUR_OF_DAY); |
| min1 = fJdkCal.get(java.util.Calendar.MINUTE); |
| sec1 = fJdkCal.get(java.util.Calendar.SECOND); |
| mil1 = fJdkCal.get(java.util.Calendar.MILLISECOND); |
| |
| if (fields[4] != doy1 || hour != hour1 || min != min1 || sec != sec1 || mil != mil1) { |
| // Calendar field(s) were changed due to the adjustment for non-existing time |
| // Note: This code does not support non-existing local time at year boundary properly. |
| // But, it should work fine for real timezones. |
| int dayDelta = Math.abs(doy1 - fields[4]) > 1 ? 1 : doy1 - fields[4]; |
| int delta = ((((dayDelta * 24) + hour1 - hour) * 60 + min1 - min) * 60 + sec1 - sec) * 1000 + mil1 - mil; |
| |
| // In this case, we use the offsets before the transition |
| fJdkCal.setTimeInMillis(fJdkCal.getTimeInMillis() - delta - 1); |
| } |
| } else { |
| fJdkCal.setTimeInMillis(date); |
| } |
| offsets[0] = fJdkCal.get(java.util.Calendar.ZONE_OFFSET); |
| offsets[1] = fJdkCal.get(java.util.Calendar.DST_OFFSET); |
| } |
| } |
| |
| @Override |
| public int getRawOffset() { |
| return fJdkTz.getRawOffset(); |
| } |
| |
| @Override |
| public int hashCode() { |
| return fJdkTz.hashCode(); |
| } |
| |
| @Override |
| public boolean hasSameRules(com.ibm.icu.util.TimeZone other) { |
| return other.hasSameRules(TimeZoneJDK.wrap(fJdkTz)); |
| } |
| |
| @Override |
| public boolean inDaylightTime(Date date) { |
| return fJdkTz.inDaylightTime(date); |
| } |
| |
| @Override |
| public void setID(String ID) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen TimeZoneJDK instance."); |
| } |
| fJdkTz.setID(ID); |
| } |
| |
| @Override |
| public void setRawOffset(int offsetMillis) { |
| if (isFrozen()) { |
| throw new UnsupportedOperationException("Attempt to modify a frozen TimeZoneJDK instance."); |
| } |
| fJdkTz.setRawOffset(offsetMillis); |
| } |
| |
| @Override |
| public boolean useDaylightTime() { |
| return fJdkTz.useDaylightTime(); |
| } |
| |
| @Override |
| public boolean observesDaylightTime() { |
| if (mObservesDaylightTime != null) { |
| // Java 7+ |
| try { |
| return (Boolean)mObservesDaylightTime.invoke(fJdkTz, (Object[]) null); |
| } catch (IllegalAccessException e) { |
| } catch (IllegalArgumentException e) { |
| } catch (InvocationTargetException e) { |
| } |
| } |
| return super.observesDaylightTime(); |
| } |
| |
| // Freezable stuffs |
| private volatile transient boolean fIsFrozen = false; |
| |
| @Override |
| public boolean isFrozen() { |
| return fIsFrozen; |
| } |
| |
| @Override |
| public com.ibm.icu.util.TimeZone freeze() { |
| fIsFrozen = true; |
| return this; |
| } |
| |
| @Override |
| public com.ibm.icu.util.TimeZone cloneAsThawed() { |
| TimeZoneJDK tz = (TimeZoneJDK)super.cloneAsThawed(); |
| tz.fJdkTz = (TimeZone)fJdkTz.clone(); |
| tz.fJdkCal = null; // To be instantiated when necessary |
| tz.fIsFrozen = false; |
| return tz; |
| } |
| |
| } |