diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/AliasDateTimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/AliasDateTimeZone.java new file mode 100644 index 000000000..d88d3ae1d --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/AliasDateTimeZone.java @@ -0,0 +1,62 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.impl.tz; + +import org.teavm.classlib.impl.Base46; + +/** + * + * @author Alexey Andreev + */ +public class AliasDateTimeZone extends StorableDateTimeZone { + private DateTimeZone innerZone; + + public AliasDateTimeZone(String id, DateTimeZone innerZone) { + super(id); + this.innerZone = innerZone; + } + + @Override + public int getOffset(long instant) { + return innerZone.getOffset(instant); + } + + @Override + public int getStandardOffset(long instant) { + return innerZone.getStandardOffset(instant); + } + + @Override + public boolean isFixed() { + return innerZone.isFixed(); + } + + @Override + public long nextTransition(long instant) { + return innerZone.nextTransition(instant); + } + + @Override + public long previousTransition(long instant) { + return innerZone.previousTransition(instant); + } + + @Override + public void write(StringBuilder sb) { + Base46.encode(sb, ALIAS); + sb.append(innerZone.getID()); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZoneProvider.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZoneProvider.java index f96ec401d..c4400c147 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZoneProvider.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/DateTimeZoneProvider.java @@ -52,7 +52,7 @@ public class DateTimeZoneProvider { CharFlow flow = new CharFlow(data.toCharArray()); if (Base46.decode(flow) == StorableDateTimeZone.ALIAS) { String aliasId = data.substring(flow.pointer); - return getTimeZone(aliasId); + return new AliasDateTimeZone(id, getTimeZone(aliasId)); } else { return StorableDateTimeZone.read(id, data); } @@ -173,11 +173,11 @@ public class DateTimeZoneProvider { areaName = ""; locationName = id; } - ResourceMap area = getResource().get(areaName); - if (area == null) { + if (!getResource().has(areaName)) { return null; } - return area.get(locationName); + ResourceMap area = getResource().get(areaName); + return area.has(locationName) ? area.get(locationName) : null; } @JSBody(params = "instant", script = "return new Date(instant).getTimezoneOffset();") diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/TimeZoneGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/TimeZoneGenerator.java index 4a96e4f18..b8fb6d8ef 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/TimeZoneGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/TimeZoneGenerator.java @@ -19,11 +19,9 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.HashMap; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.teavm.classlib.impl.Base46; import org.teavm.model.MethodReference; import org.teavm.platform.metadata.MetadataGenerator; import org.teavm.platform.metadata.MetadataGeneratorContext; @@ -72,7 +70,6 @@ public class TimeZoneGenerator implements MetadataGenerator { } Map zoneMap = compiler.compile(); - Map zones = new HashMap<>(); for (String id : zoneMap.keySet()) { int sepIndex = id.indexOf('/'); String areaName; @@ -93,14 +90,7 @@ public class TimeZoneGenerator implements MetadataGenerator { StorableDateTimeZone tz = zoneMap.get(id); TimeZoneResource tzRes = context.createResource(TimeZoneResource.class); StringBuilder data = new StringBuilder(); - String knownId = zones.get(tz); - if (knownId == null) { - tz.write(data); - zones.put(tz, id); - } else { - Base46.encode(data, StorableDateTimeZone.ALIAS); - data.append(knownId); - } + tz.write(data); tzRes.setData(data.toString()); area.put(locationName, tzRes); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/ZoneInfoCompiler.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/ZoneInfoCompiler.java index abb7445c9..df59f31b9 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/ZoneInfoCompiler.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/tz/ZoneInfoCompiler.java @@ -262,7 +262,7 @@ public class ZoneInfoCompiler { alias + "' to"); }*/ } else { - map.put(alias, tz); + map.put(alias, new AliasDateTimeZone(alias, tz)); } } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TIANATimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TIANATimeZone.java new file mode 100644 index 000000000..e6eb6e7f3 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TIANATimeZone.java @@ -0,0 +1,75 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.util; + +import org.teavm.classlib.impl.tz.DateTimeZone; + +/** + * + * @author Alexey Andreev + */ +class TIANATimeZone extends TTimeZone { + private static final long serialVersionUID = -8196006595542230951L; + private DateTimeZone underlyingZone; + private int rawOffset; + + public TIANATimeZone(DateTimeZone underlyingZone) { + super(underlyingZone.getID()); + this.underlyingZone = underlyingZone; + } + + @Override + public int getOffset(int era, int year, int month, int day, int dayOfWeek, int time) { + TCalendar calendar = new TGregorianCalendar(year, month, day); + calendar.set(TCalendar.ERA, era); + calendar.set(TCalendar.DAY_OF_WEEK, dayOfWeek); + calendar.add(TCalendar.MILLISECOND, time); + return getOffset(calendar.getTimeInMillis()); + } + + @Override + public int getOffset(long time) { + return rawOffset + underlyingZone.getOffset(time); + } + + @Override + public int getRawOffset() { + return rawOffset; + } + + @Override + public boolean inDaylightTime(TDate time) { + return underlyingZone.getOffset(time.getTime()) != underlyingZone.getStandardOffset(time.getTime()); + } + + @Override + public void setRawOffset(int offset) { + this.rawOffset = offset; + } + + @Override + public boolean useDaylightTime() { + return true; + } + + @Override + public TIANATimeZone clone() { + TIANATimeZone copy = (TIANATimeZone)super.clone(); + copy.rawOffset = rawOffset; + copy.underlyingZone = underlyingZone; + return copy; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTimeZone.java new file mode 100644 index 000000000..0cfa7bf23 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTimeZone.java @@ -0,0 +1,473 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.teavm.classlib.java.util; + +import java.io.Serializable; +import java.util.Arrays; +import org.teavm.classlib.impl.tz.DateTimeZone; +import org.teavm.classlib.impl.tz.DateTimeZoneProvider; +import org.teavm.classlib.impl.tz.FixedDateTimeZone; + +/** + * {@code TimeZone} represents a time zone offset, taking into account + * daylight savings. + *

+ * Typically, you get a {@code TimeZone} using {@code getDefault} + * which creates a {@code TimeZone} based on the time zone where the + * program is running. For example, for a program running in Japan, + * {@code getDefault} creates a {@code TimeZone} object based on + * Japanese Standard Time. + *

+ * You can also get a {@code TimeZone} using {@code getTimeZone} + * along with a time zone ID. For instance, the time zone ID for the U.S. + * Pacific Time zone is "America/Los_Angeles". So, you can get a U.S. Pacific + * Time {@code TimeZone} object with the following:

+ * + *
+ * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
+ * 
+ * + *
You can use the {@code getAvailableIDs} method to iterate + * through all the supported time zone IDs. You can then choose a supported ID + * to get a {@code TimeZone}. If the time zone you want is not + * represented by one of the supported IDs, then you can create a custom time + * zone ID with the following syntax:
+ * + *
+ * GMT[+|-]hh[[:]mm]
+ * 
+ * + *
For example, you might specify GMT+14:00 as a custom time zone + * ID. The {@code TimeZone} that is returned when you specify a custom + * time zone ID does not include daylight savings time. + *

+ * For compatibility with JDK 1.1.x, some other three-letter time zone IDs (such + * as "PST", "CTT", "AST") are also supported. However, their use is + * deprecated because the same abbreviation is often used for multiple + * time zones (for example, "CST" could be U.S. "Central Standard Time" and + * "China Standard Time"), and the Java platform can then only recognize one of + * them. + *

+ * Please note the type returned by factory methods, i.e. {@code getDefault()} + * and {@code getTimeZone(String)}, is implementation dependent, so it may + * introduce serialization incompatibility issues between different + * implementations. + * + * @see GregorianCalendar + * @see TSimpleTimeZone + */ +public abstract class TTimeZone implements Serializable, Cloneable { + private static final long serialVersionUID = 3581463369166924961L; + + /** + * The SHORT display name style. + */ + public static final int SHORT = 0; + + /** + * The LONG display name style. + */ + public static final int LONG = 1; + + private static TTimeZone Default; + + static TTimeZone GMT = new TIANATimeZone(new FixedDateTimeZone("GMT", 0, 0)); + + private String ID; + + /** + * Constructs a new instance of this class. + */ + public TTimeZone() { + } + + TTimeZone(String id) { + this.ID = id; + } + + /** + * Returns a new {@code TimeZone} with the same ID, {@code rawOffset} and daylight savings + * time rules as this {@code TimeZone}. + * + * @return a shallow copy of this {@code TimeZone}. + * @see java.lang.Cloneable + */ + @Override + public Object clone() { + try { + TTimeZone zone = (TTimeZone) super.clone(); + return zone; + } catch (CloneNotSupportedException e) { + return null; + } + } + + /** + * Gets the available time zone IDs. Any one of these IDs can be passed to + * {@code get()} to create the corresponding {@code TimeZone} instance. + * + * @return an array of time zone ID strings. + */ + public static String[] getAvailableIDs() { + return DateTimeZoneProvider.getIds(); + } + + /** + * Gets the available time zone IDs which match the specified offset from + * GMT. Any one of these IDs can be passed to {@code get()} to create the corresponding + * {@code TimeZone} instance. + * + * @param offset + * the offset from GMT in milliseconds. + * @return an array of time zone ID strings. + */ + public static String[] getAvailableIDs(int offset) { + String[] all = DateTimeZoneProvider.getIds(); + String[] result = new String[all.length]; + int i = 0; + for (String id : all) { + DateTimeZone jodaTz = DateTimeZoneProvider.getTimeZone(id); + if (jodaTz.getStandardOffset(System.currentTimeMillis()) == offset) { + result[i++] = id; + } + } + return Arrays.copyOf(result, i); + } + + /** + * Gets the default time zone. + * + * @return the default time zone. + */ + public static TTimeZone getDefault() { + if (Default == null) { + Default = new TIANATimeZone(DateTimeZoneProvider.detectTimezone()); + } + return (TTimeZone) Default.clone(); + } + + /** + * Gets the LONG name for this {@code TimeZone} for the default {@code Locale} in standard + * time. If the name is not available, the result is in the format + * {@code GMT[+-]hh:mm}. + * + * @return the {@code TimeZone} name. + */ + public final String getDisplayName() { + return getDisplayName(false, LONG, TLocale.getDefault()); + } + + /** + * Gets the LONG name for this {@code TimeZone} for the specified {@code Locale} in standard + * time. If the name is not available, the result is in the format + * {@code GMT[+-]hh:mm}. + * + * @param locale + * the {@code Locale}. + * @return the {@code TimeZone} name. + */ + public final String getDisplayName(TLocale locale) { + return getDisplayName(false, LONG, locale); + } + + /** + * Gets the specified style of name ({@code LONG} or {@code SHORT}) for this {@code TimeZone} for + * the default {@code Locale} in either standard or daylight time as specified. If + * the name is not available, the result is in the format {@code GMT[+-]hh:mm}. + * + * @param daylightTime + * {@code true} for daylight time, {@code false} for standard + * time. + * @param style + * either {@code LONG} or {@code SHORT}. + * @return the {@code TimeZone} name. + */ + public final String getDisplayName(boolean daylightTime, int style) { + return getDisplayName(daylightTime, style, TLocale.getDefault()); + } + + /** + * Gets the specified style of name ({@code LONG} or {@code SHORT}) for this {@code TimeZone} for + * the specified {@code Locale} in either standard or daylight time as specified. If + * the name is not available, the result is in the format {@code GMT[+-]hh:mm}. + * + * @param daylightTime + * {@code true} for daylight time, {@code false} for standard + * time. + * @param style + * either LONG or SHORT. + * @param locale + * either {@code LONG} or {@code SHORT}. + * @return the {@code TimeZone} name. + */ + public String getDisplayName(boolean daylightTime, int style, TLocale locale) { + // TODO: implement via CLDR + return null; + } + + /** + * Gets the ID of this {@code TimeZone}. + * + * @return the time zone ID string. + */ + public String getID() { + return ID; + } + + /** + * Gets the daylight savings offset in milliseconds for this {@code TimeZone}. + *

+ * This implementation returns 3600000 (1 hour), or 0 if the time zone does + * not observe daylight savings. + *

+ * Subclasses may override to return daylight savings values other than 1 + * hour. + *

+ * + * @return the daylight savings offset in milliseconds if this {@code TimeZone} + * observes daylight savings, zero otherwise. + */ + public int getDSTSavings() { + if (useDaylightTime()) { + return 3600000; + } + return 0; + } + + /** + * Gets the offset from GMT of this {@code TimeZone} for the specified date. The + * offset includes daylight savings time if the specified date is within the + * daylight savings time period. + * + * @param time + * the date in milliseconds since January 1, 1970 00:00:00 GMT + * @return the offset from GMT in milliseconds. + */ + public int getOffset(long time) { + return inDaylightTime(new TDate(time)) ? getRawOffset() + getDSTSavings() : getRawOffset(); + } + + /** + * Gets the offset from GMT of this {@code TimeZone} for the specified date and + * time. The offset includes daylight savings time if the specified date and + * time are within the daylight savings time period. + * + * @param era + * the {@code GregorianCalendar} era, either {@code GregorianCalendar.BC} or + * {@code GregorianCalendar.AD}. + * @param year + * the year. + * @param month + * the {@code Calendar} month. + * @param day + * the day of the month. + * @param dayOfWeek + * the {@code Calendar} day of the week. + * @param time + * the time of day in milliseconds. + * @return the offset from GMT in milliseconds. + */ + abstract public int getOffset(int era, int year, int month, int day, + int dayOfWeek, int time); + + /** + * Gets the offset for standard time from GMT for this {@code TimeZone}. + * + * @return the offset from GMT in milliseconds. + */ + abstract public int getRawOffset(); + + /** + * Gets the {@code TimeZone} with the specified ID. + * + * @param name + * a time zone string ID. + * @return the {@code TimeZone} with the specified ID or null if no {@code TimeZone} with + * the specified ID exists. + */ + public static TTimeZone getTimeZone(String name) { + DateTimeZone jodaZone = DateTimeZoneProvider.getTimeZone(name); + if (jodaZone != null) { + return new TIANATimeZone(jodaZone); + } + if (name.startsWith("GMT") && name.length() > 3) { + char sign = name.charAt(3); + if (sign == '+' || sign == '-') { + int[] position = new int[1]; + String formattedName = formatTimeZoneName(name, 4); + int hour = parseNumber(formattedName, 4, position); + if (hour < 0 || hour > 23) { + return (TTimeZone) GMT.clone(); + } + int index = position[0]; + if (index != -1) { + int raw = hour * 3600000; + if (index < formattedName.length() + && formattedName.charAt(index) == ':') { + int minute = parseNumber(formattedName, index + 1, + position); + if (position[0] == -1 || minute < 0 || minute > 59) { + return (TTimeZone) GMT.clone(); + } + raw += minute * 60000; + } else if (hour >= 30 || index > 6) { + raw = (hour / 100 * 3600000) + (hour % 100 * 60000); + } + if (sign == '-') { + raw = -raw; + } + return new TIANATimeZone(new FixedDateTimeZone(formattedName, raw, raw)); + } + } + } + + return (TTimeZone) GMT.clone(); + } + + private static String formatTimeZoneName(String name, int offset) { + StringBuilder buf = new StringBuilder(); + int index = offset, length = name.length(); + buf.append(name.substring(0, offset)); + + while (index < length) { + if (Character.digit(name.charAt(index), 10) != -1) { + buf.append(name.charAt(index)); + if ((length - (index + 1)) == 2) { + buf.append(':'); + } + } else if (name.charAt(index) == ':') { + buf.append(':'); + } + index++; + } + + if (buf.toString().indexOf(":") == -1) { + buf.append(':'); + buf.append("00"); + } + + if (buf.toString().indexOf(":") == 5) { + buf.insert(4, '0'); + } + + return buf.toString(); + } + + /** + * Returns whether the specified {@code TimeZone} has the same raw offset as this + * {@code TimeZone}. + * + * @param zone + * a {@code TimeZone}. + * @return {@code true} when the {@code TimeZone} have the same raw offset, {@code false} + * otherwise. + */ + public boolean hasSameRules(TTimeZone zone) { + if (zone == null) { + return false; + } + return getRawOffset() == zone.getRawOffset(); + } + + /** + * Returns whether the specified {@code Date} is in the daylight savings time period for + * this {@code TimeZone}. + * + * @param time + * a {@code Date}. + * @return {@code true} when the {@code Date} is in the daylight savings time period, {@code false} + * otherwise. + */ + abstract public boolean inDaylightTime(TDate time); + + private static int parseNumber(String string, int offset, int[] position) { + int index = offset, length = string.length(), digit, result = 0; + while (index < length + && (digit = Character.digit(string.charAt(index), 10)) != -1) { + index++; + result = result * 10 + digit; + } + position[0] = index == offset ? -1 : index; + return result; + } + + /** + * Sets the default time zone. If passed {@code null}, then the next + * time {@link #getDefault} is called, the default time zone will be + * determined. This behavior is slightly different than the canonical + * description of this method, but it follows the spirit of it. + * + * @param timezone + * a {@code TimeZone} object. + */ + public static void setDefault(TTimeZone timezone) { + Default = timezone != null ? (TTimeZone)timezone.clone() : null; + } + + /** + * Sets the ID of this {@code TimeZone}. + * + * @param name + * a string which is the time zone ID. + */ + public void setID(String name) { + if (name == null) { + throw new NullPointerException(); + } + ID = name; + } + + /** + * Sets the offset for standard time from GMT for this {@code TimeZone}. + * + * @param offset + * the offset from GMT in milliseconds. + */ + abstract public void setRawOffset(int offset); + + /** + * Returns whether this {@code TimeZone} has a daylight savings time period. + * + * @return {@code true} if this {@code TimeZone} has a daylight savings time period, {@code false} + * otherwise. + */ + abstract public boolean useDaylightTime(); + + /** + * Gets the name and the details of the user-selected TimeZone on the + * device. + * + * @param tzinfo + * int array of 10 elements to be filled with the TimeZone + * information. Once filled, the contents of the array are + * formatted as follows: tzinfo[0] -> the timezone offset; + * tzinfo[1] -> the dst adjustment; tzinfo[2] -> the dst start + * hour; tzinfo[3] -> the dst start day of week; tzinfo[4] -> the + * dst start week of month; tzinfo[5] -> the dst start month; + * tzinfo[6] -> the dst end hour; tzinfo[7] -> the dst end day of + * week; tzinfo[8] -> the dst end week of month; tzinfo[9] -> the + * dst end month; + * @param isCustomTimeZone + * boolean array of size 1 that indicates if a timezone match is + * found + * @return the name of the TimeZone or null if error occurs in native + * method. + */ + private static native String getCustomTimeZone(int[] tzinfo, + boolean[] isCustomTimeZone); +} diff --git a/teavm-tests/src/test/java/org/teavm/classlib/java/util/TimeZoneTest.java b/teavm-tests/src/test/java/org/teavm/classlib/java/util/TimeZoneTest.java index ab677dbcf..5e4025350 100644 --- a/teavm-tests/src/test/java/org/teavm/classlib/java/util/TimeZoneTest.java +++ b/teavm-tests/src/test/java/org/teavm/classlib/java/util/TimeZoneTest.java @@ -1,21 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.teavm.classlib.java.util; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; import org.junit.Test; -import org.teavm.classlib.impl.tz.DateTimeZone; -import org.teavm.classlib.impl.tz.DateTimeZoneProvider; /** * * @author Alexey Andreev */ public class TimeZoneTest { + private static final int ONE_HOUR = 3600000; + @Test - public void resourceProvided() { - DateTimeZone tz = DateTimeZoneProvider.getTimeZone("Europe/Moscow"); - assertEquals(1414274399999L, tz.previousTransition(1431781727159L)); - assertEquals(1301183999999L, tz.previousTransition(1414274399999L)); - assertEquals(1288479599999L, tz.previousTransition(1301183999999L)); - System.out.println(DateTimeZoneProvider.detectTimezone().getID()); + public void test_getDefault() { + assertNotSame("returns identical", TimeZone.getDefault(), TimeZone.getDefault()); + } + + @Test + public void test_getOffset_long() { + // Test for method int java.util.TimeZone.getOffset(long time) + + // test on subclass SimpleTimeZone + TimeZone st1 = TimeZone.getTimeZone("EST"); + long time1 = new GregorianCalendar(1998, Calendar.NOVEMBER, 11).getTimeInMillis(); + assertEquals("T1. Incorrect offset returned", -(5 * ONE_HOUR), st1.getOffset(time1)); + + long time2 = new GregorianCalendar(1998, Calendar.JUNE, 11).getTimeInMillis(); + st1 = TimeZone.getTimeZone("EST"); + assertEquals("T2. Incorrect offset returned", -(5 * ONE_HOUR), st1.getOffset(time2)); + } + + @Test + public void test_getTimeZoneLjava_lang_String() { + assertEquals("Must return GMT when given an invalid TimeZone id SMT-8.", "GMT", TimeZone.getTimeZone("SMT-8") + .getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+28:70.", "GMT", + TimeZone.getTimeZone("GMT+28:70").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+28:30.", "GMT", + TimeZone.getTimeZone("GMT+28:30").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+8:70.", "GMT", + TimeZone.getTimeZone("GMT+8:70").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+3:.", "GMT", + TimeZone.getTimeZone("GMT+3:").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+3:0.", "GMT", + TimeZone.getTimeZone("GMT+3:0").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+2360.", "GMT", + TimeZone.getTimeZone("GMT+2360").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+892.", "GMT", + TimeZone.getTimeZone("GMT+892").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+082.", "GMT", + TimeZone.getTimeZone("GMT+082").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+28.", "GMT", + TimeZone.getTimeZone("GMT+28").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT+30.", "GMT", + TimeZone.getTimeZone("GMT+30").getID()); + assertEquals("Must return GMT when given TimeZone GMT.", "GMT", TimeZone.getTimeZone("GMT").getID()); + assertEquals("Must return GMT when given TimeZone GMT+.", "GMT", TimeZone.getTimeZone("GMT+").getID()); + assertEquals("Must return GMT when given TimeZone GMT-.", "GMT", TimeZone.getTimeZone("GMT-").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT-8.45.", "GMT", + TimeZone.getTimeZone("GMT-8.45").getID()); + assertEquals("Must return GMT when given an invalid TimeZone time GMT-123:23.", "GMT", + TimeZone.getTimeZone("GMT-123:23").getID()); + assertEquals("Must return proper GMT formatted string for GMT+8:30 (eg. GMT+08:20).", "GMT+08:30", TimeZone + .getTimeZone("GMT+8:30").getID()); + assertEquals("Must return proper GMT formatted string for GMT+3 (eg. GMT+08:20).", "GMT+03:00", TimeZone + .getTimeZone("GMT+3").getID()); + assertEquals("Must return proper GMT formatted string for GMT+3:02 (eg. GMT+08:20).", "GMT+03:02", TimeZone + .getTimeZone("GMT+3:02").getID()); + assertEquals("Must return proper GMT formatted string for GMT+2359 (eg. GMT+08:20).", "GMT+23:59", TimeZone + .getTimeZone("GMT+2359").getID()); + assertEquals("Must return proper GMT formatted string for GMT+520 (eg. GMT+08:20).", "GMT+05:20", TimeZone + .getTimeZone("GMT+520").getID()); + assertEquals("Must return proper GMT formatted string for GMT+052 (eg. GMT+08:20).", "GMT+00:52", TimeZone + .getTimeZone("GMT+052").getID()); + // GMT-0 is an available ID in ICU, so replace it with GMT-00 + assertEquals("Must return proper GMT formatted string for GMT-00 (eg. GMT+08:20).", "GMT-00:00", TimeZone + .getTimeZone("GMT-00").getID()); + } + + @Test + public void test_getDisplayNameLjava_util_Locale() { + TimeZone timezone = TimeZone.getTimeZone("Asia/Shanghai"); + assertEquals("\u4e2d\u56fd\u6807\u51c6\u65f6\u95f4", timezone.getDisplayName(Locale.CHINA)); + } + + @Test + public void test_GetTimezoneOffset() { + TimeZone tz = TimeZone.getTimeZone("America/Toronto"); + Date date = new GregorianCalendar(2006, 2, 24).getTime(); + assertEquals(-300 * 60_000, tz.getOffset(date.getTime())); + date = new GregorianCalendar(1999, 8, 1).getTime(); + assertEquals(-240 * 60_000, tz.getOffset(date.getTime())); + } + + @Test + public void test_getDisplayName() { + TimeZone defaultZone = TimeZone.getDefault(); + Locale defaulLocal = Locale.getDefault(); + String defaultName = defaultZone.getDisplayName(); + String expectedName = defaultZone.getDisplayName(defaulLocal); + assertEquals("getDispalyName() did not return the default Locale suitable name", expectedName, defaultName); + } + + @Test + public void test_getDisplayName_ZI() { + TimeZone defaultZone = TimeZone.getDefault(); + Locale defaultLocale = Locale.getDefault(); + String actualName = defaultZone.getDisplayName(false, TimeZone.LONG); + String expectedName = defaultZone.getDisplayName(false, TimeZone.LONG, defaultLocale); + assertEquals("getDisplayName(daylight,style) did not return the default locale suitable name", expectedName, + actualName); } }