Home | History | Annotate | Download | only in icuadapter
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 /*
      4  *******************************************************************************
      5  * Copyright (C) 2008-2014, International Business Machines Corporation and    *
      6  * others. All Rights Reserved.                                                *
      7  *******************************************************************************
      8  */
      9 package com.ibm.icu.impl.icuadapter;
     10 
     11 import java.lang.reflect.InvocationTargetException;
     12 import java.lang.reflect.Method;
     13 import java.util.Calendar;
     14 import java.util.Date;
     15 import java.util.GregorianCalendar;
     16 import java.util.Locale;
     17 import java.util.TimeZone;
     18 
     19 import com.ibm.icu.impl.Grego;
     20 import com.ibm.icu.impl.jdkadapter.TimeZoneICU;
     21 import com.ibm.icu.util.ULocale;
     22 
     23 /**
     24  * TimeZoneJDK is an adapter class which wraps java.util.TimeZone and
     25  * implements ICU4J TimeZone APIs.
     26  */
     27 public class TimeZoneJDK extends com.ibm.icu.util.TimeZone {
     28 
     29     private static final long serialVersionUID = -1137052823551791933L;
     30 
     31     private TimeZone fJdkTz;
     32     private transient Calendar fJdkCal;
     33     private static Method mObservesDaylightTime;
     34 
     35     static {
     36         try {
     37             mObservesDaylightTime = TimeZone.class.getMethod("observesDaylightTime", (Class[]) null);
     38         } catch (NoSuchMethodException e) {
     39             // Java 6 or older
     40         } catch (SecurityException e) {
     41             // not visible
     42         }
     43     }
     44 
     45     private TimeZoneJDK(TimeZone jdkTz) {
     46         fJdkTz = (TimeZone)jdkTz.clone();
     47     }
     48 
     49     public static com.ibm.icu.util.TimeZone wrap(TimeZone jdkTz) {
     50         if (jdkTz instanceof TimeZoneICU) {
     51             return ((TimeZoneICU)jdkTz).unwrap();
     52         }
     53         return new TimeZoneJDK(jdkTz);
     54     }
     55 
     56     public TimeZone unwrap() {
     57         return (TimeZone)fJdkTz.clone();
     58     }
     59 
     60     @Override
     61     public Object clone() {
     62         if (isFrozen()) {
     63             return this;
     64         }
     65         return cloneAsThawed();
     66     }
     67 
     68     @Override
     69     public boolean equals(Object obj) {
     70         if (obj instanceof TimeZoneJDK) {
     71             return (((TimeZoneJDK)obj).fJdkTz).equals(fJdkTz);
     72         }
     73         return false;
     74     }
     75 
     76     //public String getDisplayName()
     77     //public String getDisplayName(boolean daylight, int style)
     78     //public String getDisplayName(Locale locale)
     79     //public String getDisplayName(ULocale locale)
     80     @Override
     81     public String getDisplayName(boolean daylight, int style, Locale locale) {
     82         return fJdkTz.getDisplayName(daylight, style, locale);
     83     }
     84 
     85     @Override
     86     public String getDisplayName(boolean daylight, int style, ULocale locale) {
     87         return fJdkTz.getDisplayName(daylight, style, locale.toLocale());
     88     }
     89 
     90     @Override
     91     public int getDSTSavings() {
     92         return fJdkTz.getDSTSavings();
     93     }
     94 
     95     @Override
     96     public String getID() {
     97         return fJdkTz.getID();
     98     }
     99 
    100     @Override
    101     public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {
    102         return fJdkTz.getOffset(era, year, month, day, dayOfWeek, milliseconds);
    103     }
    104 
    105     @Override
    106     public int getOffset(long date) {
    107         return fJdkTz.getOffset(date);
    108     }
    109 
    110     @Override
    111     public void getOffset(long date, boolean local, int[] offsets) {
    112         synchronized(this) {
    113             if (fJdkCal == null) {
    114                 fJdkCal = new GregorianCalendar(fJdkTz);
    115             }
    116             if (local) {
    117                 int fields[] = new int[6];
    118                 Grego.timeToFields(date, fields);
    119                 int hour, min, sec, mil;
    120                 int tmp = fields[5];
    121                 mil = tmp % 1000;
    122                 tmp /= 1000;
    123                 sec = tmp % 60;
    124                 tmp /= 60;
    125                 min = tmp % 60;
    126                 hour = tmp / 60;
    127                 fJdkCal.clear();
    128                 fJdkCal.set(fields[0], fields[1], fields[2], hour, min, sec);
    129                 fJdkCal.set(java.util.Calendar.MILLISECOND, mil);
    130 
    131                 int doy1, hour1, min1, sec1, mil1;
    132                 doy1 = fJdkCal.get(java.util.Calendar.DAY_OF_YEAR);
    133                 hour1 = fJdkCal.get(java.util.Calendar.HOUR_OF_DAY);
    134                 min1 = fJdkCal.get(java.util.Calendar.MINUTE);
    135                 sec1 = fJdkCal.get(java.util.Calendar.SECOND);
    136                 mil1 = fJdkCal.get(java.util.Calendar.MILLISECOND);
    137 
    138                 if (fields[4] != doy1 || hour != hour1 || min != min1 || sec != sec1 || mil != mil1) {
    139                     // Calendar field(s) were changed due to the adjustment for non-existing time
    140                     // Note: This code does not support non-existing local time at year boundary properly.
    141                     // But, it should work fine for real timezones.
    142                     int dayDelta = Math.abs(doy1 - fields[4]) > 1 ? 1 : doy1 - fields[4];
    143                     int delta = ((((dayDelta * 24) + hour1 - hour) * 60 + min1 - min) * 60 + sec1 - sec) * 1000 + mil1 - mil;
    144 
    145                     // In this case, we use the offsets before the transition
    146                     fJdkCal.setTimeInMillis(fJdkCal.getTimeInMillis() - delta - 1);
    147                 }
    148             } else {
    149                 fJdkCal.setTimeInMillis(date);
    150             }
    151             offsets[0] = fJdkCal.get(java.util.Calendar.ZONE_OFFSET);
    152             offsets[1] = fJdkCal.get(java.util.Calendar.DST_OFFSET);
    153         }
    154     }
    155 
    156     @Override
    157     public int getRawOffset() {
    158         return fJdkTz.getRawOffset();
    159     }
    160 
    161     @Override
    162     public int hashCode() {
    163         return fJdkTz.hashCode();
    164     }
    165 
    166     @Override
    167     public boolean hasSameRules(com.ibm.icu.util.TimeZone other) {
    168         return other.hasSameRules(TimeZoneJDK.wrap(fJdkTz));
    169     }
    170 
    171     @Override
    172     public boolean inDaylightTime(Date date) {
    173         return fJdkTz.inDaylightTime(date);
    174     }
    175 
    176     @Override
    177     public void setID(String ID) {
    178         if (isFrozen()) {
    179             throw new UnsupportedOperationException("Attempt to modify a frozen TimeZoneJDK instance.");
    180         }
    181         fJdkTz.setID(ID);
    182     }
    183 
    184     @Override
    185     public void setRawOffset(int offsetMillis) {
    186         if (isFrozen()) {
    187             throw new UnsupportedOperationException("Attempt to modify a frozen TimeZoneJDK instance.");
    188         }
    189         fJdkTz.setRawOffset(offsetMillis);
    190     }
    191 
    192     @Override
    193     public boolean useDaylightTime() {
    194         return fJdkTz.useDaylightTime();
    195     }
    196 
    197     @Override
    198     public boolean observesDaylightTime() {
    199         if (mObservesDaylightTime != null) {
    200             // Java 7+
    201             try {
    202                 return (Boolean)mObservesDaylightTime.invoke(fJdkTz, (Object[]) null);
    203             } catch (IllegalAccessException e) {
    204             } catch (IllegalArgumentException e) {
    205             } catch (InvocationTargetException e) {
    206             }
    207         }
    208         return super.observesDaylightTime();
    209     }
    210 
    211     // Freezable stuffs
    212     private volatile transient boolean fIsFrozen = false;
    213 
    214     @Override
    215     public boolean isFrozen() {
    216         return fIsFrozen;
    217     }
    218 
    219     @Override
    220     public com.ibm.icu.util.TimeZone freeze() {
    221         fIsFrozen = true;
    222         return this;
    223     }
    224 
    225     @Override
    226     public com.ibm.icu.util.TimeZone cloneAsThawed() {
    227         TimeZoneJDK tz = (TimeZoneJDK)super.cloneAsThawed();
    228         tz.fJdkTz = (TimeZone)fJdkTz.clone();
    229         tz.fJdkCal = null;  // To be instantiated when necessary
    230         tz.fIsFrozen = false;
    231         return tz;
    232     }
    233 
    234 }
    235