blob: d0fb9d78b71e74edf82bef0db7b55d9b03e1cba3 [file] [log] [blame]
/*
*******************************************************************************
* 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;
}
}