From 2817f7603debbd6d68cc928c76e8d57b97b74bc0 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 15 May 2014 17:40:20 +0400 Subject: [PATCH 1/4] Adds initial implementations of date-relates classes --- .../teavm/classlib/java/util/Calendar.java | 1166 +++++++++++++ .../org/teavm/classlib/java/util/Date.java | 814 ++++++++++ .../classlib/java/util/GregorianCalendar.java | 1439 +++++++++++++++++ .../classlib/java/util/SimpleTimeZone.java | 873 ++++++++++ .../teavm/classlib/java/util/TimeZone.java | 509 ++++++ .../teavm/classlib/java/util/TimeZones.java | 707 ++++++++ 6 files changed, 5508 insertions(+) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZones.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java new file mode 100644 index 000000000..51a587807 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java @@ -0,0 +1,1166 @@ +/* + * Copyright 2014 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. + */ +/* + * 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; + +public abstract class Calendar implements TSerializable, TCloneable, TComparable { + + private static final long serialVersionUID = -1807547505821590642L; + + /** + * Set to {@code true} when the calendar fields have been set from the time, set to + * {@code false} when a field is changed and the fields must be recomputed. + */ + protected boolean areFieldsSet; + + /** + * An integer array of calendar fields. The length is {@code FIELD_COUNT}. + */ + protected int[] fields; + + /** + * A boolean array. Each element indicates if the corresponding field has + * been set. The length is {@code FIELD_COUNT}. + */ + protected boolean[] isSet; + + /** + * Set to {@code true} when the time has been set, set to {@code false} when a field is + * changed and the time must be recomputed. + */ + protected boolean isTimeSet; + + /** + * The time in milliseconds since January 1, 1970. + */ + protected long time; + + transient int lastTimeFieldSet; + + transient int lastDateFieldSet; + + private boolean lenient; + + private int firstDayOfWeek; + + private int minimalDaysInFirstWeek; + + private TimeZone zone; + + /** + * Value of the {@code MONTH} field indicating the first month of the + * year. + */ + public static final int JANUARY = 0; + + /** + * Value of the {@code MONTH} field indicating the second month of + * the year. + */ + public static final int FEBRUARY = 1; + + /** + * Value of the {@code MONTH} field indicating the third month of the + * year. + */ + public static final int MARCH = 2; + + /** + * Value of the {@code MONTH} field indicating the fourth month of + * the year. + */ + public static final int APRIL = 3; + + /** + * Value of the {@code MONTH} field indicating the fifth month of the + * year. + */ + public static final int MAY = 4; + + /** + * Value of the {@code MONTH} field indicating the sixth month of the + * year. + */ + public static final int JUNE = 5; + + /** + * Value of the {@code MONTH} field indicating the seventh month of + * the year. + */ + public static final int JULY = 6; + + /** + * Value of the {@code MONTH} field indicating the eighth month of + * the year. + */ + public static final int AUGUST = 7; + + /** + * Value of the {@code MONTH} field indicating the ninth month of the + * year. + */ + public static final int SEPTEMBER = 8; + + /** + * Value of the {@code MONTH} field indicating the tenth month of the + * year. + */ + public static final int OCTOBER = 9; + + /** + * Value of the {@code MONTH} field indicating the eleventh month of + * the year. + */ + public static final int NOVEMBER = 10; + + /** + * Value of the {@code MONTH} field indicating the twelfth month of + * the year. + */ + public static final int DECEMBER = 11; + + /** + * Value of the {@code MONTH} field indicating the thirteenth month + * of the year. Although {@code GregorianCalendar} does not use this + * value, lunar calendars do. + */ + public static final int UNDECIMBER = 12; + + /** + * Value of the {@code DAY_OF_WEEK} field indicating Sunday. + */ + public static final int SUNDAY = 1; + + /** + * Value of the {@code DAY_OF_WEEK} field indicating Monday. + */ + public static final int MONDAY = 2; + + /** + * Value of the {@code DAY_OF_WEEK} field indicating Tuesday. + */ + public static final int TUESDAY = 3; + + /** + * Value of the {@code DAY_OF_WEEK} field indicating Wednesday. + */ + public static final int WEDNESDAY = 4; + + /** + * Value of the {@code DAY_OF_WEEK} field indicating Thursday. + */ + public static final int THURSDAY = 5; + + /** + * Value of the {@code DAY_OF_WEEK} field indicating Friday. + */ + public static final int FRIDAY = 6; + + /** + * Value of the {@code DAY_OF_WEEK} field indicating Saturday. + */ + public static final int SATURDAY = 7; + + /** + * Field number for {@code get} and {@code set} indicating the + * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific + * value; see subclass documentation. + * + * @see GregorianCalendar#AD + * @see GregorianCalendar#BC + */ + public static final int ERA = 0; + + /** + * Field number for {@code get} and {@code set} indicating the + * year. This is a calendar-specific value; see subclass documentation. + */ + public static final int YEAR = 1; + + /** + * Field number for {@code get} and {@code set} indicating the + * month. This is a calendar-specific value. The first month of the year is + * {@code JANUARY}; the last depends on the number of months in a + * year. + * + * @see #JANUARY + * @see #FEBRUARY + * @see #MARCH + * @see #APRIL + * @see #MAY + * @see #JUNE + * @see #JULY + * @see #AUGUST + * @see #SEPTEMBER + * @see #OCTOBER + * @see #NOVEMBER + * @see #DECEMBER + * @see #UNDECIMBER + */ + public static final int MONTH = 2; + + /** + * Field number for {@code get} and {@code set} indicating the + * week number within the current year. The first week of the year, as + * defined by {@code getFirstDayOfWeek()} and + * {@code getMinimalDaysInFirstWeek()}, has value 1. Subclasses + * define the value of {@code WEEK_OF_YEAR} for days before the first + * week of the year. + * + * @see #getFirstDayOfWeek + * @see #getMinimalDaysInFirstWeek + */ + public static final int WEEK_OF_YEAR = 3; + + /** + * Field number for {@code get} and {@code set} indicating the + * week number within the current month. The first week of the month, as + * defined by {@code getFirstDayOfWeek()} and + * {@code getMinimalDaysInFirstWeek()}, has value 1. Subclasses + * define the value of {@code WEEK_OF_MONTH} for days before the + * first week of the month. + * + * @see #getFirstDayOfWeek + * @see #getMinimalDaysInFirstWeek + */ + public static final int WEEK_OF_MONTH = 4; + + /** + * Field number for {@code get} and {@code set} indicating the + * day of the month. This is a synonym for {@code DAY_OF_MONTH}. The + * first day of the month has value 1. + * + * @see #DAY_OF_MONTH + */ + public static final int DATE = 5; + + /** + * Field number for {@code get} and {@code set} indicating the + * day of the month. This is a synonym for {@code DATE}. The first + * day of the month has value 1. + * + * @see #DATE + */ + public static final int DAY_OF_MONTH = 5; + + /** + * Field number for {@code get} and {@code set} indicating the + * day number within the current year. The first day of the year has value + * 1. + */ + public static final int DAY_OF_YEAR = 6; + + /** + * Field number for {@code get} and {@code set} indicating the + * day of the week. This field takes values {@code SUNDAY}, + * {@code MONDAY}, {@code TUESDAY}, {@code WEDNESDAY}, + * {@code THURSDAY}, {@code FRIDAY}, and + * {@code SATURDAY}. + * + * @see #SUNDAY + * @see #MONDAY + * @see #TUESDAY + * @see #WEDNESDAY + * @see #THURSDAY + * @see #FRIDAY + * @see #SATURDAY + */ + public static final int DAY_OF_WEEK = 7; + + /** + * Field number for {@code get} and {@code set} indicating the + * ordinal number of the day of the week within the current month. Together + * with the {@code DAY_OF_WEEK} field, this uniquely specifies a day + * within a month. Unlike {@code WEEK_OF_MONTH} and + * {@code WEEK_OF_YEAR}, this field's value does not + * depend on {@code getFirstDayOfWeek()} or + * {@code getMinimalDaysInFirstWeek()}. {@code DAY_OF_MONTH 1} + * through {@code 7} always correspond to DAY_OF_WEEK_IN_MONTH + * 1; + * {@code 8} through {@code 15} correspond to + * {@code DAY_OF_WEEK_IN_MONTH 2}, and so on. + * {@code DAY_OF_WEEK_IN_MONTH 0} indicates the week before + * {@code DAY_OF_WEEK_IN_MONTH 1}. Negative values count back from + * the end of the month, so the last Sunday of a month is specified as + * {@code DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1}. Because + * negative values count backward they will usually be aligned differently + * within the month than positive values. For example, if a month has 31 + * days, {@code DAY_OF_WEEK_IN_MONTH -1} will overlap + * {@code DAY_OF_WEEK_IN_MONTH 5} and the end of {@code 4}. + * + * @see #DAY_OF_WEEK + * @see #WEEK_OF_MONTH + */ + public static final int DAY_OF_WEEK_IN_MONTH = 8; + + /** + * Field number for {@code get} and {@code set} indicating + * whether the {@code HOUR} is before or after noon. E.g., at + * 10:04:15.250 PM the {@code AM_PM} is {@code PM}. + * + * @see #AM + * @see #PM + * @see #HOUR + */ + public static final int AM_PM = 9; + + /** + * Field number for {@code get} and {@code set} indicating the + * hour of the morning or afternoon. {@code HOUR} is used for the + * 12-hour clock. E.g., at 10:04:15.250 PM the {@code HOUR} is 10. + * + * @see #AM_PM + * @see #HOUR_OF_DAY + */ + public static final int HOUR = 10; + + /** + * Field number for {@code get} and {@code set} indicating the + * hour of the day. {@code HOUR_OF_DAY} is used for the 24-hour + * clock. E.g., at 10:04:15.250 PM the {@code HOUR_OF_DAY} is 22. + * + * @see #HOUR + */ + public static final int HOUR_OF_DAY = 11; + + /** + * Field number for {@code get} and {@code set} indicating the + * minute within the hour. E.g., at 10:04:15.250 PM the {@code MINUTE} + * is 4. + */ + public static final int MINUTE = 12; + + /** + * Field number for {@code get} and {@code set} indicating the + * second within the minute. E.g., at 10:04:15.250 PM the + * {@code SECOND} is 15. + */ + public static final int SECOND = 13; + + /** + * Field number for {@code get} and {@code set} indicating the + * millisecond within the second. E.g., at 10:04:15.250 PM the + * {@code MILLISECOND} is 250. + */ + public static final int MILLISECOND = 14; + + /** + * Field number for {@code get} and {@code set} indicating the + * raw offset from GMT in milliseconds. + */ + public static final int ZONE_OFFSET = 15; + + /** + * Field number for {@code get} and {@code set} indicating the + * daylight savings offset in milliseconds. + */ + public static final int DST_OFFSET = 16; + + /** + * This is the total number of fields in this calendar. + */ + public static final int FIELD_COUNT = 17; + + /** + * Value of the {@code AM_PM} field indicating the period of the day + * from midnight to just before noon. + */ + public static final int AM = 0; + + /** + * Value of the {@code AM_PM} field indicating the period of the day + * from noon to just before midnight. + */ + public static final int PM = 1; + + @SuppressWarnings("nls") + private static String[] fieldNames = { "ERA=", "YEAR=", "MONTH=", + "WEEK_OF_YEAR=", "WEEK_OF_MONTH=", "DAY_OF_MONTH=", "DAY_OF_YEAR=", + "DAY_OF_WEEK=", "DAY_OF_WEEK_IN_MONTH=", "AM_PM=", "HOUR=", + "HOUR_OF_DAY", "MINUTE=", "SECOND=", "MILLISECOND=", + "ZONE_OFFSET=", "DST_OFFSET=" }; + + /** + * Constructs a {@code Calendar} instance using the default {@code TimeZone} and {@code Locale}. + */ + protected Calendar() { + this(TimeZone.getDefault(), Locale.getDefault()); + } + + Calendar(TimeZone timezone) { + fields = new int[FIELD_COUNT]; + isSet = new boolean[FIELD_COUNT]; + areFieldsSet = isTimeSet = false; + setLenient(true); + setTimeZone(timezone); + } + + /** + * Constructs a {@code Calendar} instance using the specified {@code TimeZone} and {@code Locale}. + * + * @param timezone + * the timezone. + * @param locale + * the locale. + */ + protected Calendar(TimeZone timezone, Locale locale) { + this(timezone); + com.ibm.icu.util.Calendar icuCalendar = com.ibm.icu.util.Calendar + .getInstance(com.ibm.icu.util.SimpleTimeZone + .getTimeZone(timezone.getID()), locale); + setFirstDayOfWeek(icuCalendar.getFirstDayOfWeek()); + setMinimalDaysInFirstWeek(icuCalendar.getMinimalDaysInFirstWeek()); + } + + + /** + * Adds the specified amount to a {@code Calendar} field. + * + * @param field + * the {@code Calendar} field to modify. + * @param value + * the amount to add to the field. + * @throws IllegalArgumentException + * if {@code field} is {@code DST_OFFSET} or {@code + * ZONE_OFFSET}. + */ + abstract public void add(int field, int value); + + /** + * Returns whether the {@code Date} specified by this {@code Calendar} instance is after the {@code Date} + * specified by the parameter. The comparison is not dependent on the time + * zones of the {@code Calendar}. + * + * @param calendar + * the {@code Calendar} instance to compare. + * @return {@code true} when this Calendar is after calendar, {@code false} otherwise. + * @throws IllegalArgumentException + * if the time is not set and the time cannot be computed + * from the current field values. + */ + public boolean after(Object calendar) { + if (!(calendar instanceof Calendar)) { + return false; + } + return getTimeInMillis() > ((Calendar) calendar).getTimeInMillis(); + } + + /** + * Returns whether the {@code Date} specified by this {@code Calendar} instance is before the + * {@code Date} specified by the parameter. The comparison is not dependent on the + * time zones of the {@code Calendar}. + * + * @param calendar + * the {@code Calendar} instance to compare. + * @return {@code true} when this Calendar is before calendar, {@code false} otherwise. + * @throws IllegalArgumentException + * if the time is not set and the time cannot be computed + * from the current field values. + */ + public boolean before(Object calendar) { + if (!(calendar instanceof Calendar)) { + return false; + } + return getTimeInMillis() < ((Calendar) calendar).getTimeInMillis(); + } + + /** + * Clears all of the fields of this {@code Calendar}. All fields are initialized to + * zero. + */ + public final void clear() { + for (int i = 0; i < FIELD_COUNT; i++) { + fields[i] = 0; + isSet[i] = false; + } + areFieldsSet = isTimeSet = false; + } + + /** + * Clears the specified field to zero and sets the isSet flag to {@code false}. + * + * @param field + * the field to clear. + */ + public final void clear(int field) { + fields[field] = 0; + isSet[field] = false; + areFieldsSet = isTimeSet = false; + } + + /** + * Returns a new {@code Calendar} with the same properties. + * + * @return a shallow copy of this {@code Calendar}. + * + * @see java.lang.Cloneable + */ + @Override + public Object clone() { + try { + Calendar clone = (Calendar) super.clone(); + clone.fields = fields.clone(); + clone.isSet = isSet.clone(); + clone.zone = (TimeZone) zone.clone(); + return clone; + } catch (CloneNotSupportedException e) { + return null; + } + } + + /** + * Computes the time from the fields if the time has not already been set. + * Computes the fields from the time if the fields are not already set. + * + * @throws IllegalArgumentException + * if the time is not set and the time cannot be computed + * from the current field values. + */ + protected void complete() { + if (!isTimeSet) { + computeTime(); + isTimeSet = true; + } + if (!areFieldsSet) { + computeFields(); + areFieldsSet = true; + } + } + + /** + * Computes the {@code Calendar} fields from {@code time}. + */ + protected abstract void computeFields(); + + /** + * Computes {@code time} from the Calendar fields. + * + * @throws IllegalArgumentException + * if the time cannot be computed from the current field + * values. + */ + protected abstract void computeTime(); + + /** + * Compares the specified object to this {@code Calendar} and returns whether they are + * equal. The object must be an instance of {@code Calendar} and have the same + * properties. + * + * @param object + * the object to compare with this object. + * @return {@code true} if the specified object is equal to this {@code Calendar}, {@code false} + * otherwise. + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof Calendar)) { + return false; + } + Calendar cal = (Calendar) object; + return getTimeInMillis() == cal.getTimeInMillis() + && isLenient() == cal.isLenient() + && getFirstDayOfWeek() == cal.getFirstDayOfWeek() + && getMinimalDaysInFirstWeek() == cal + .getMinimalDaysInFirstWeek() + && getTimeZone().equals(cal.getTimeZone()); + } + + /** + * Gets the value of the specified field after computing the field values by + * calling {@code complete()} first. + * + * @param field + * the field to get. + * @return the value of the specified field. + * + * @throws IllegalArgumentException + * if the fields are not set, the time is not set, and the + * time cannot be computed from the current field values. + * @throws ArrayIndexOutOfBoundsException + * if the field is not inside the range of possible fields. + * The range is starting at 0 up to {@code FIELD_COUNT}. + */ + public int get(int field) { + complete(); + return fields[field]; + } + + /** + * Gets the maximum value of the specified field for the current date. + * + * @param field + * the field. + * @return the maximum value of the specified field. + */ + public int getActualMaximum(int field) { + int value, next; + if (getMaximum(field) == (next = getLeastMaximum(field))) { + return next; + } + complete(); + long orgTime = time; + set(field, next); + do { + value = next; + roll(field, true); + next = get(field); + } while (next > value); + time = orgTime; + areFieldsSet = false; + return value; + } + + /** + * Gets the minimum value of the specified field for the current date. + * + * @param field + * the field. + * @return the minimum value of the specified field. + */ + public int getActualMinimum(int field) { + int value, next; + if (getMinimum(field) == (next = getGreatestMinimum(field))) { + return next; + } + complete(); + long orgTime = time; + set(field, next); + do { + value = next; + roll(field, false); + next = get(field); + } while (next < value); + time = orgTime; + areFieldsSet = false; + return value; + } + + /** + * Gets the list of installed {@code Locale}s which support {@code Calendar}. + * + * @return an array of {@code Locale}. + */ + public static synchronized Locale[] getAvailableLocales() { + return Locale.getAvailableLocales(); + } + + /** + * Gets the first day of the week for this {@code Calendar}. + * + * @return the first day of the week. + */ + public int getFirstDayOfWeek() { + return firstDayOfWeek; + } + + /** + * Gets the greatest minimum value of the specified field. This is the + * biggest value that {@code getActualMinimum} can return for any possible + * time. + * + * @param field + * the field. + * @return the greatest minimum value of the specified field. + */ + abstract public int getGreatestMinimum(int field); + + /** + * Constructs a new instance of the {@code Calendar} subclass appropriate for the + * default {@code Locale}. + * + * @return a {@code Calendar} subclass instance set to the current date and time in + * the default {@code Timezone}. + */ + public static synchronized Calendar getInstance() { + return new GregorianCalendar(); + } + + /** + * Constructs a new instance of the {@code Calendar} subclass appropriate for the + * specified {@code Locale}. + * + * @param locale + * the locale to use. + * @return a {@code Calendar} subclass instance set to the current date and time. + */ + public static synchronized Calendar getInstance(Locale locale) { + return new GregorianCalendar(locale); + } + + /** + * Constructs a new instance of the {@code Calendar} subclass appropriate for the + * default {@code Locale}, using the specified {@code TimeZone}. + * + * @param timezone + * the {@code TimeZone} to use. + * @return a {@code Calendar} subclass instance set to the current date and time in + * the specified timezone. + */ + public static synchronized Calendar getInstance(TimeZone timezone) { + return new GregorianCalendar(timezone); + } + + /** + * Constructs a new instance of the {@code Calendar} subclass appropriate for the + * specified {@code Locale}. + * + * @param timezone + * the {@code TimeZone} to use. + * @param locale + * the {@code Locale} to use. + * @return a {@code Calendar} subclass instance set to the current date and time in + * the specified timezone. + */ + public static synchronized Calendar getInstance(TimeZone timezone, + Locale locale) { + return new GregorianCalendar(timezone, locale); + } + + /** + * Gets the smallest maximum value of the specified field. This is the + * smallest value that {@code getActualMaximum()} can return for any + * possible time. + * + * @param field + * the field number. + * @return the smallest maximum value of the specified field. + */ + abstract public int getLeastMaximum(int field); + + /** + * Gets the greatest maximum value of the specified field. This returns the + * biggest value that {@code get} can return for the specified field. + * + * @param field + * the field. + * @return the greatest maximum value of the specified field. + */ + abstract public int getMaximum(int field); + + /** + * Gets the minimal days in the first week of the year. + * + * @return the minimal days in the first week of the year. + */ + public int getMinimalDaysInFirstWeek() { + return minimalDaysInFirstWeek; + } + + /** + * Gets the smallest minimum value of the specified field. this returns the + * smallest value thet {@code get} can return for the specified field. + * + * @param field + * the field number. + * @return the smallest minimum value of the specified field. + */ + abstract public int getMinimum(int field); + + /** + * Gets the time of this {@code Calendar} as a {@code Date} object. + * + * @return a new {@code Date} initialized to the time of this {@code Calendar}. + * + * @throws IllegalArgumentException + * if the time is not set and the time cannot be computed + * from the current field values. + */ + public final Date getTime() { + return new Date(getTimeInMillis()); + } + + /** + * Computes the time from the fields if required and returns the time. + * + * @return the time of this {@code Calendar}. + * + * @throws IllegalArgumentException + * if the time is not set and the time cannot be computed + * from the current field values. + */ + public long getTimeInMillis() { + if (!isTimeSet) { + computeTime(); + isTimeSet = true; + } + return time; + } + + /** + * Gets the timezone of this {@code Calendar}. + * + * @return the {@code TimeZone} used by this {@code Calendar}. + */ + public TimeZone getTimeZone() { + return zone; + } + + /** + * Returns an integer hash code for the receiver. Objects which are equal + * return the same value for this method. + * + * @return the receiver's hash. + * + * @see #equals + */ + @Override + public int hashCode() { + return (isLenient() ? 1237 : 1231) + getFirstDayOfWeek() + + getMinimalDaysInFirstWeek() + getTimeZone().hashCode(); + } + + /** + * Gets the value of the specified field without recomputing. + * + * @param field + * the field. + * @return the value of the specified field. + */ + protected final int internalGet(int field) { + return fields[field]; + } + + /** + * Returns if this {@code Calendar} accepts field values which are outside the valid + * range for the field. + * + * @return {@code true} if this {@code Calendar} is lenient, {@code false} otherwise. + */ + public boolean isLenient() { + return lenient; + } + + /** + * Returns whether the specified field is set. + * + * @param field + * a {@code Calendar} field number. + * @return {@code true} if the specified field is set, {@code false} otherwise. + */ + public final boolean isSet(int field) { + return isSet[field]; + } + + /** + * Adds the specified amount to the specified field and wraps the value of + * the field when it goes beyond the maximum or minimum value for the + * current date. Other fields will be adjusted as required to maintain a + * consistent date. + * + * @param field + * the field to roll. + * @param value + * the amount to add. + */ + public void roll(int field, int value) { + boolean increment = value >= 0; + int count = increment ? value : -value; + for (int i = 0; i < count; i++) { + roll(field, increment); + } + } + + /** + * Increment or decrement the specified field and wrap the value of the + * field when it goes beyond the maximum or minimum value for the current + * date. Other fields will be adjusted as required to maintain a consistent + * date. + * + * @param field + * the number indicating the field to roll. + * @param increment + * {@code true} to increment the field, {@code false} to decrement. + */ + abstract public void roll(int field, boolean increment); + + /** + * Sets a field to the specified value. + * + * @param field + * the code indicating the {@code Calendar} field to modify. + * @param value + * the value. + */ + public void set(int field, int value) { + fields[field] = value; + isSet[field] = true; + areFieldsSet = isTimeSet = false; + if (field > MONTH && field < AM_PM) { + lastDateFieldSet = field; + } + if (field == HOUR || field == HOUR_OF_DAY) { + lastTimeFieldSet = field; + } + if (field == AM_PM) { + lastTimeFieldSet = HOUR; + } + } + + /** + * Sets the year, month and day of the month fields. Other fields are not + * changed. + * + * @param year + * the year. + * @param month + * the month. + * @param day + * the day of the month. + */ + public final void set(int year, int month, int day) { + set(YEAR, year); + set(MONTH, month); + set(DATE, day); + } + + /** + * Sets the year, month, day of the month, hour of day and minute fields. + * Other fields are not changed. + * + * @param year + * the year. + * @param month + * the month. + * @param day + * the day of the month. + * @param hourOfDay + * the hour of day. + * @param minute + * the minute. + */ + public final void set(int year, int month, int day, int hourOfDay, + int minute) { + set(year, month, day); + set(HOUR_OF_DAY, hourOfDay); + set(MINUTE, minute); + } + + /** + * Sets the year, month, day of the month, hour of day, minute and second + * fields. Other fields are not changed. + * + * @param year + * the year. + * @param month + * the month. + * @param day + * the day of the month. + * @param hourOfDay + * the hour of day. + * @param minute + * the minute. + * @param second + * the second. + */ + public final void set(int year, int month, int day, int hourOfDay, + int minute, int second) { + set(year, month, day, hourOfDay, minute); + set(SECOND, second); + } + + /** + * Sets the first day of the week for this {@code Calendar}. + * + * @param value + * a {@code Calendar} day of the week. + */ + public void setFirstDayOfWeek(int value) { + firstDayOfWeek = value; + } + + /** + * Sets this {@code Calendar} to accept field values which are outside the valid + * range for the field. + * + * @param value + * a boolean value. + */ + public void setLenient(boolean value) { + lenient = value; + } + + /** + * Sets the minimal days in the first week of the year. + * + * @param value + * the minimal days in the first week of the year. + */ + public void setMinimalDaysInFirstWeek(int value) { + minimalDaysInFirstWeek = value; + } + + /** + * Sets the time of this {@code Calendar}. + * + * @param date + * a {@code Date} object. + */ + public final void setTime(Date date) { + setTimeInMillis(date.getTime()); + } + + /** + * Sets the time of this {@code Calendar}. + * + * @param milliseconds + * the time as the number of milliseconds since Jan. 1, 1970. + */ + public void setTimeInMillis(long milliseconds) { + if (!isTimeSet || !areFieldsSet || time != milliseconds) { + time = milliseconds; + isTimeSet = true; + areFieldsSet = false; + complete(); + } + } + + /** + * Sets the {@code TimeZone} used by this Calendar. + * + * @param timezone + * a {@code TimeZone}. + */ + public void setTimeZone(TimeZone timezone) { + zone = timezone; + areFieldsSet = false; + } + + /** + * Returns the string representation of this {@code Calendar}. + * + * @return the string representation of this {@code Calendar}. + */ + @Override + @SuppressWarnings("nls") + public String toString() { + StringBuilder result = new StringBuilder(getClass().getName() + "[time=" + + (isTimeSet ? String.valueOf(time) : "?") + + ",areFieldsSet=" + + areFieldsSet + + // ",areAllFieldsSet=" + areAllFieldsSet + + ",lenient=" + lenient + ",zone=" + zone + ",firstDayOfWeek=" + + firstDayOfWeek + ",minimalDaysInFirstWeek=" + + minimalDaysInFirstWeek); + for (int i = 0; i < FIELD_COUNT; i++) { + result.append(','); + result.append(fieldNames[i]); + result.append('='); + if (isSet[i]) { + result.append(fields[i]); + } else { + result.append('?'); + } + } + result.append(']'); + return result.toString(); + } + + /** + * Compares the times of the two {@code Calendar}, which represent the milliseconds + * from the January 1, 1970 00:00:00.000 GMT (Gregorian). + * + * @param anotherCalendar + * another calendar that this one is compared with. + * @return 0 if the times of the two {@code Calendar}s are equal, -1 if the time of + * this {@code Calendar} is before the other one, 1 if the time of this + * {@code Calendar} is after the other one. + * @throws NullPointerException + * if the argument is null. + * @throws IllegalArgumentException + * if the argument does not include a valid time + * value. + */ + public int compareTo(Calendar anotherCalendar) { + if (null == anotherCalendar) { + throw new NullPointerException(); + } + long timeInMillis = getTimeInMillis(); + long anotherTimeInMillis = anotherCalendar.getTimeInMillis(); + if (timeInMillis > anotherTimeInMillis) { + return 1; + } + if (timeInMillis == anotherTimeInMillis) { + return 0; + } + return -1; + } + + @SuppressWarnings("nls") + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("areFieldsSet", Boolean.TYPE), + new ObjectStreamField("fields", int[].class), + new ObjectStreamField("firstDayOfWeek", Integer.TYPE), + new ObjectStreamField("isSet", boolean[].class), + new ObjectStreamField("isTimeSet", Boolean.TYPE), + new ObjectStreamField("lenient", Boolean.TYPE), + new ObjectStreamField("minimalDaysInFirstWeek", Integer.TYPE), + new ObjectStreamField("nextStamp", Integer.TYPE), + new ObjectStreamField("serialVersionOnStream", Integer.TYPE), + new ObjectStreamField("time", Long.TYPE), + new ObjectStreamField("zone", TimeZone.class), }; + + @SuppressWarnings("nls") + private void writeObject(ObjectOutputStream stream) throws IOException { + complete(); + ObjectOutputStream.PutField putFields = stream.putFields(); + putFields.put("areFieldsSet", areFieldsSet); + putFields.put("fields", this.fields); + putFields.put("firstDayOfWeek", firstDayOfWeek); + putFields.put("isSet", isSet); + putFields.put("isTimeSet", isTimeSet); + putFields.put("lenient", lenient); + putFields.put("minimalDaysInFirstWeek", minimalDaysInFirstWeek); + putFields.put("nextStamp", 2 /* MINIMUM_USER_STAMP */); + putFields.put("serialVersionOnStream", 1); + putFields.put("time", time); + putFields.put("zone", zone); + stream.writeFields(); + } + + @SuppressWarnings("nls") + private void readObject(ObjectInputStream stream) throws IOException, + ClassNotFoundException { + ObjectInputStream.GetField readFields = stream.readFields(); + areFieldsSet = readFields.get("areFieldsSet", false); + this.fields = (int[]) readFields.get("fields", null); + firstDayOfWeek = readFields.get("firstDayOfWeek", Calendar.SUNDAY); + isSet = (boolean[]) readFields.get("isSet", null); + isTimeSet = readFields.get("isTimeSet", false); + lenient = readFields.get("lenient", true); + minimalDaysInFirstWeek = readFields.get("minimalDaysInFirstWeek", 1); + time = readFields.get("time", 0L); + zone = (TimeZone) readFields.get("zone", null); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java new file mode 100644 index 000000000..dd8b4a915 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java @@ -0,0 +1,814 @@ +/* + * Copyright 2014 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. + */ +/* + * 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.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TCloneable; +import org.teavm.classlib.java.lang.TComparable; + +public class Date implements TSerializable, TCloneable, TComparable { + + // Used by parse() + private static int creationYear = new Date().getYear(); + + private transient long milliseconds; + + @SuppressWarnings("nls") + private static String[] dayOfWeekNames = { "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" }; + + @SuppressWarnings("nls") + private static String[] monthNames = { "Jan", "Feb", "Mar", "Apr", "May", + "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + /** + * Initializes this {@code Date} instance to the current date and time. + */ + public Date() { + this(System.currentTimeMillis()); + } + + /** + * Constructs a new {@code Date} initialized to midnight in the default {@code TimeZone} on + * the specified date. + * + * @param year + * the year, 0 is 1900. + * @param month + * the month, 0 - 11. + * @param day + * the day of the month, 1 - 31. + * + * @deprecated use + * {@link GregorianCalendar#GregorianCalendar(int, int, int)} + */ + @Deprecated + public Date(int year, int month, int day) { + GregorianCalendar cal = new GregorianCalendar(false); + cal.set(1900 + year, month, day); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Constructs a new {@code Date} initialized to the specified date and time in the + * default {@code TimeZone}. + * + * @param year + * the year, 0 is 1900. + * @param month + * the month, 0 - 11. + * @param day + * the day of the month, 1 - 31. + * @param hour + * the hour of day, 0 - 23. + * @param minute + * the minute of the hour, 0 - 59. + * + * @deprecated use + * {@link GregorianCalendar#GregorianCalendar(int, int, int, int, int)} + */ + @Deprecated + public Date(int year, int month, int day, int hour, int minute) { + GregorianCalendar cal = new GregorianCalendar(false); + cal.set(1900 + year, month, day, hour, minute); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Constructs a new {@code Date} initialized to the specified date and time in the + * default {@code TimeZone}. + * + * @param year + * the year, 0 is 1900. + * @param month + * the month, 0 - 11. + * @param day + * the day of the month, 1 - 31. + * @param hour + * the hour of day, 0 - 23. + * @param minute + * the minute of the hour, 0 - 59. + * @param second + * the second of the minute, 0 - 59. + * + * @deprecated use + * {@link GregorianCalendar#GregorianCalendar(int, int, int, int, int, int)} + */ + @Deprecated + public Date(int year, int month, int day, int hour, int minute, int second) { + GregorianCalendar cal = new GregorianCalendar(false); + cal.set(1900 + year, month, day, hour, minute, second); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Initializes this {@code Date} instance using the specified millisecond value. The + * value is the number of milliseconds since Jan. 1, 1970 GMT. + * + * @param milliseconds + * the number of milliseconds since Jan. 1, 1970 GMT. + */ + public Date(long milliseconds) { + this.milliseconds = milliseconds; + } + + /** + * Constructs a new {@code Date} initialized to the date and time parsed from the + * specified String. + * + * @param string + * the String to parse. + * + * @deprecated use {@link DateFormat} + */ + @Deprecated + public Date(String string) { + milliseconds = parse(string); + } + + /** + * Returns if this {@code Date} is after the specified Date. + * + * @param date + * a Date instance to compare. + * @return {@code true} if this {@code Date} is after the specified {@code Date}, + * {@code false} otherwise. + */ + public boolean after(Date date) { + return milliseconds > date.milliseconds; + } + + /** + * Returns if this {@code Date} is before the specified Date. + * + * @param date + * a {@code Date} instance to compare. + * @return {@code true} if this {@code Date} is before the specified {@code Date}, + * {@code false} otherwise. + */ + public boolean before(Date date) { + return milliseconds < date.milliseconds; + } + + /** + * Returns a new {@code Date} with the same millisecond value as this {@code Date}. + * + * @return a shallow copy of this {@code Date}. + * + * @see java.lang.Cloneable + */ + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + /** + * Compare the receiver to the specified {@code Date} to determine the relative + * ordering. + * + * @param date + * a {@code Date} to compare against. + * @return an {@code int < 0} if this {@code Date} is less than the specified {@code Date}, {@code 0} if + * they are equal, and an {@code int > 0} if this {@code Date} is greater. + */ + public int compareTo(Date date) { + if (milliseconds < date.milliseconds) { + return -1; + } + if (milliseconds == date.milliseconds) { + return 0; + } + return 1; + } + + /** + * Compares the specified object to this {@code Date} and returns if they are equal. + * To be equal, the object must be an instance of {@code Date} and have the same millisecond + * value. + * + * @param object + * the object to compare with this object. + * @return {@code true} if the specified object is equal to this {@code Date}, {@code false} + * otherwise. + * + * @see #hashCode + */ + @Override + public boolean equals(Object object) { + return (object == this) || (object instanceof Date) + && (milliseconds == ((Date) object).milliseconds); + } + + /** + * Returns the gregorian calendar day of the month for this {@code Date} object. + * + * @return the day of the month. + * + * @deprecated use {@code Calendar.get(Calendar.DATE)} + */ + @Deprecated + public int getDate() { + return new GregorianCalendar(milliseconds).get(Calendar.DATE); + } + + /** + * Returns the gregorian calendar day of the week for this {@code Date} object. + * + * @return the day of the week. + * + * @deprecated use {@code Calendar.get(Calendar.DAY_OF_WEEK)} + */ + @Deprecated + public int getDay() { + return new GregorianCalendar(milliseconds).get(Calendar.DAY_OF_WEEK) - 1; + } + + /** + * Returns the gregorian calendar hour of the day for this {@code Date} object. + * + * @return the hour of the day. + * + * @deprecated use {@code Calendar.get(Calendar.HOUR_OF_DAY)} + */ + @Deprecated + public int getHours() { + return new GregorianCalendar(milliseconds).get(Calendar.HOUR_OF_DAY); + } + + /** + * Returns the gregorian calendar minute of the hour for this {@code Date} object. + * + * @return the minutes. + * + * @deprecated use {@code Calendar.get(Calendar.MINUTE)} + */ + @Deprecated + public int getMinutes() { + return new GregorianCalendar(milliseconds).get(Calendar.MINUTE); + } + + /** + * Returns the gregorian calendar month for this {@code Date} object. + * + * @return the month. + * + * @deprecated use {@code Calendar.get(Calendar.MONTH)} + */ + @Deprecated + public int getMonth() { + return new GregorianCalendar(milliseconds).get(Calendar.MONTH); + } + + /** + * Returns the gregorian calendar second of the minute for this {@code Date} object. + * + * @return the seconds. + * + * @deprecated use {@code Calendar.get(Calendar.SECOND)} + */ + @Deprecated + public int getSeconds() { + return new GregorianCalendar(milliseconds).get(Calendar.SECOND); + } + + /** + * Returns this {@code Date} as a millisecond value. The value is the number of + * milliseconds since Jan. 1, 1970, midnight GMT. + * + * @return the number of milliseconds since Jan. 1, 1970, midnight GMT. + */ + public long getTime() { + return milliseconds; + } + + /** + * Returns the timezone offset in minutes of the default {@code TimeZone}. + * + * @return the timezone offset in minutes of the default {@code TimeZone}. + * + * @deprecated use + * {@code (Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / 60000} + */ + @Deprecated + public int getTimezoneOffset() { + GregorianCalendar cal = new GregorianCalendar(milliseconds); + return -(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / 60000; + } + + /** + * Returns the gregorian calendar year since 1900 for this {@code Date} object. + * + * @return the year - 1900. + * + * @deprecated use {@code Calendar.get(Calendar.YEAR) - 1900} + */ + @Deprecated + public int getYear() { + return new GregorianCalendar(milliseconds).get(Calendar.YEAR) - 1900; + } + + /** + * Returns an integer hash code for the receiver. Objects which are equal + * return the same value for this method. + * + * @return this {@code Date}'s hash. + * + * @see #equals + */ + @Override + public int hashCode() { + return (int) (milliseconds >>> 32) ^ (int) milliseconds; + } + + private static int parse(String string, String[] array) { + for (int i = 0, alength = array.length, slength = string.length(); i < alength; i++) { + if (string.regionMatches(true, 0, array[i], 0, slength)) { + return i; + } + } + return -1; + } + + /** + * Returns the millisecond value of the date and time parsed from the + * specified {@code String}. Many date/time formats are recognized, including IETF + * standard syntax, i.e. Tue, 22 Jun 1999 12:16:00 GMT-0500 + * + * @param string + * the String to parse. + * @return the millisecond value parsed from the String. + * + * @deprecated use {@link DateFormat} + */ + @Deprecated + public static long parse(String string) { + + if (string == null) { + // luni.06=The string argument is null + throw new IllegalArgumentException(Messages.getString("luni.06")); //$NON-NLS-1$ + } + + char sign = 0; + int commentLevel = 0; + int offset = 0, length = string.length(), state = 0; + int year = -1, month = -1, date = -1; + int hour = -1, minute = -1, second = -1, zoneOffset = 0, minutesOffset = 0; + boolean zone = false; + final int PAD = 0, LETTERS = 1, NUMBERS = 2; + StringBuilder buffer = new StringBuilder(); + + while (offset <= length) { + char next = offset < length ? string.charAt(offset) : '\r'; + offset++; + + if (next == '(') { + commentLevel++; + } + if (commentLevel > 0) { + if (next == ')') { + commentLevel--; + } + if (commentLevel == 0) { + next = ' '; + } else { + continue; + } + } + + int nextState = PAD; + if ('a' <= next && next <= 'z' || 'A' <= next && next <= 'Z') { + nextState = LETTERS; + } else if ('0' <= next && next <= '9') { + nextState = NUMBERS; + } else if (!Character.isSpace(next) && ",+-:/".indexOf(next) == -1) { //$NON-NLS-1$ + throw new IllegalArgumentException(); + } + + if (state == NUMBERS && nextState != NUMBERS) { + int digit = Integer.parseInt(buffer.toString()); + buffer.setLength(0); + if (sign == '+' || sign == '-') { + if (zoneOffset == 0) { + zone = true; + if (next == ':') { + minutesOffset = sign == '-' ? -Integer + .parseInt(string.substring(offset, + offset + 2)) : Integer + .parseInt(string.substring(offset, + offset + 2)); + offset += 2; + } + zoneOffset = sign == '-' ? -digit : digit; + sign = 0; + } else { + throw new IllegalArgumentException(); + } + } else if (digit >= 70) { + if (year == -1 + && (Character.isSpace(next) || next == ',' + || next == '/' || next == '\r')) { + year = digit; + } else { + throw new IllegalArgumentException(); + } + } else if (next == ':') { + if (hour == -1) { + hour = digit; + } else if (minute == -1) { + minute = digit; + } else { + throw new IllegalArgumentException(); + } + } else if (next == '/') { + if (month == -1) { + month = digit - 1; + } else if (date == -1) { + date = digit; + } else { + throw new IllegalArgumentException(); + } + } else if (Character.isSpace(next) || next == ',' + || next == '-' || next == '\r') { + if (hour != -1 && minute == -1) { + minute = digit; + } else if (minute != -1 && second == -1) { + second = digit; + } else if (date == -1) { + date = digit; + } else if (year == -1) { + year = digit; + } else { + throw new IllegalArgumentException(); + } + } else if (year == -1 && month != -1 && date != -1) { + year = digit; + } else { + throw new IllegalArgumentException(); + } + } else if (state == LETTERS && nextState != LETTERS) { + String text = buffer.toString().toUpperCase(); + buffer.setLength(0); + if (text.length() == 1) { + throw new IllegalArgumentException(); + } + if (text.equals("AM")) { //$NON-NLS-1$ + if (hour == 12) { + hour = 0; + } else if (hour < 1 || hour > 12) { + throw new IllegalArgumentException(); + } + } else if (text.equals("PM")) { //$NON-NLS-1$ + if (hour == 12) { + hour = 0; + } else if (hour < 1 || hour > 12) { + throw new IllegalArgumentException(); + } + hour += 12; + } else { + DateFormatSymbols symbols = new DateFormatSymbols(Locale.US); + String[] weekdays = symbols.getWeekdays(), months = symbols + .getMonths(); + int value; + if (parse(text, weekdays) != -1) {/* empty */ + } else if (month == -1 + && (month = parse(text, months)) != -1) {/* empty */ + } else if (text.equals("GMT") || text.equals("UT") //$NON-NLS-1$ //$NON-NLS-2$ + || text.equals("UTC")) { //$NON-NLS-1$ + zone = true; + zoneOffset = 0; + } else if ((value = zone(text)) != 0) { + zone = true; + zoneOffset = value; + } else { + throw new IllegalArgumentException(); + } + } + } + + if (next == '+' || (year != -1 && next == '-')) { + sign = next; + } else if (!Character.isSpace(next) && next != ',' + && nextState != NUMBERS) { + sign = 0; + } + + if (nextState == LETTERS || nextState == NUMBERS) { + buffer.append(next); + } + state = nextState; + } + + if (year != -1 && month != -1 && date != -1) { + if (hour == -1) { + hour = 0; + } + if (minute == -1) { + minute = 0; + } + if (second == -1) { + second = 0; + } + if (year < (creationYear - 80)) { + year += 2000; + } else if (year < 100) { + year += 1900; + } + minute -= minutesOffset; + if (zone) { + if (zoneOffset >= 24 || zoneOffset <= -24) { + hour -= zoneOffset / 100; + minute -= zoneOffset % 100; + } else { + hour -= zoneOffset; + } + return UTC(year - 1900, month, date, hour, minute, second); + } + return new Date(year - 1900, month, date, hour, minute, second) + .getTime(); + } + throw new IllegalArgumentException(); + } + + /** + * Sets the gregorian calendar day of the month for this {@code Date} object. + * + * @param day + * the day of the month. + * + * @deprecated use {@code Calendar.set(Calendar.DATE, day)} + */ + @Deprecated + public void setDate(int day) { + GregorianCalendar cal = new GregorianCalendar(milliseconds); + cal.set(Calendar.DATE, day); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Sets the gregorian calendar hour of the day for this {@code Date} object. + * + * @param hour + * the hour of the day. + * + * @deprecated use {@code Calendar.set(Calendar.HOUR_OF_DAY, hour)} + */ + @Deprecated + public void setHours(int hour) { + GregorianCalendar cal = new GregorianCalendar(milliseconds); + cal.set(Calendar.HOUR_OF_DAY, hour); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Sets the gregorian calendar minute of the hour for this {@code Date} object. + * + * @param minute + * the minutes. + * + * @deprecated use {@code Calendar.set(Calendar.MINUTE, minute)} + */ + @Deprecated + public void setMinutes(int minute) { + GregorianCalendar cal = new GregorianCalendar(milliseconds); + cal.set(Calendar.MINUTE, minute); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Sets the gregorian calendar month for this {@code Date} object. + * + * @param month + * the month. + * + * @deprecated use {@code Calendar.set(Calendar.MONTH, month)} + */ + @Deprecated + public void setMonth(int month) { + GregorianCalendar cal = new GregorianCalendar(milliseconds); + cal.set(Calendar.MONTH, month); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Sets the gregorian calendar second of the minute for this {@code Date} object. + * + * @param second + * the seconds. + * + * @deprecated use {@code Calendar.set(Calendar.SECOND, second)} + */ + @Deprecated + public void setSeconds(int second) { + GregorianCalendar cal = new GregorianCalendar(milliseconds); + cal.set(Calendar.SECOND, second); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Sets this {@code Date} to the specified millisecond value. The value is the + * number of milliseconds since Jan. 1, 1970 GMT. + * + * @param milliseconds + * the number of milliseconds since Jan. 1, 1970 GMT. + */ + public void setTime(long milliseconds) { + this.milliseconds = milliseconds; + } + + /** + * Sets the gregorian calendar year since 1900 for this {@code Date} object. + * + * @param year + * the year since 1900. + * + * @deprecated use {@code Calendar.set(Calendar.YEAR, year + 1900)} + */ + @Deprecated + public void setYear(int year) { + GregorianCalendar cal = new GregorianCalendar(milliseconds); + cal.set(Calendar.YEAR, year + 1900); + milliseconds = cal.getTimeInMillis(); + } + + /** + * Returns the string representation of this {@code Date} in GMT in the format: 22 + * Jun 1999 13:02:00 GMT + * + * @return the string representation of this {@code Date} in GMT. + * + * @deprecated use {@link DateFormat} + */ + @Deprecated + public String toGMTString() { + SimpleDateFormat format1 = new SimpleDateFormat("d MMM ", Locale.US); //$NON-NLS-1$ + SimpleDateFormat format2 = new SimpleDateFormat( + " HH:mm:ss 'GMT'", Locale.US); //$NON-NLS-1$ + TimeZone gmtZone = TimeZone.getTimeZone("GMT"); //$NON-NLS-1$ + format1.setTimeZone(gmtZone); + format2.setTimeZone(gmtZone); + GregorianCalendar gc = new GregorianCalendar(gmtZone); + gc.setTimeInMillis(milliseconds); + return format1.format(this) + gc.get(Calendar.YEAR) + + format2.format(this); + } + + /** + * Returns the string representation of this {@code Date} for the default {@code Locale}. + * + * @return the string representation of this {@code Date} for the default {@code Locale}. + * + * @deprecated use {@link DateFormat} + */ + @Deprecated + public String toLocaleString() { + return DateFormat.getDateTimeInstance().format(this); + } + + /** + * Returns the string representation of this {@code Date} in the format: Tue Jun 22 + * 13:07:00 GMT 1999 + * + * @return the string representation of this {@code Date}. + */ + @Override + public String toString() { + Calendar cal = new GregorianCalendar(milliseconds); + TimeZone zone = cal.getTimeZone(); + String zoneName = zone.getDisplayName(zone.inDaylightTime(this), + TimeZone.SHORT, Locale.getDefault()); + + StringBuilder sb = new StringBuilder(34); + sb.append(dayOfWeekNames[cal.get(Calendar.DAY_OF_WEEK) - 1]); + sb.append(' '); + sb.append(monthNames[cal.get(Calendar.MONTH)]); + sb.append(' '); + sb.append(toTwoDigits(cal.get(Calendar.DAY_OF_MONTH))); + sb.append(' '); + sb.append(toTwoDigits(cal.get(Calendar.HOUR_OF_DAY))); + sb.append(':'); + sb.append(toTwoDigits(cal.get(Calendar.MINUTE))); + sb.append(':'); + sb.append(toTwoDigits(cal.get(Calendar.SECOND))); + sb.append(' '); + sb.append(zoneName); + sb.append(' '); + sb.append(cal.get(Calendar.YEAR)); + + return sb.toString(); + } + + private String toTwoDigits(int digit) { + if(digit >= 10) { + return "" + digit;//$NON-NLS-1$ + } else { + return "0" + digit;//$NON-NLS-1$ + } + } + + /** + * Returns the millisecond value of the specified date and time in GMT. + * + * @param year + * the year, 0 is 1900. + * @param month + * the month, 0 - 11. + * @param day + * the day of the month, 1 - 31. + * @param hour + * the hour of day, 0 - 23. + * @param minute + * the minute of the hour, 0 - 59. + * @param second + * the second of the minute, 0 - 59. + * @return the date and time in GMT in milliseconds. + * + * @deprecated use: + * Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); + * cal.set(year + 1900, month, day, hour, minute, second); + * cal.getTime().getTime(); + */ + @Deprecated + public static long UTC(int year, int month, int day, int hour, int minute, + int second) { + GregorianCalendar cal = new GregorianCalendar(false); + cal.setTimeZone(TimeZone.getTimeZone("GMT")); //$NON-NLS-1$ + cal.set(1900 + year, month, day, hour, minute, second); + return cal.getTimeInMillis(); + } + + private static int zone(String text) { + if (text.equals("EST")) { //$NON-NLS-1$ + return -5; + } + if (text.equals("EDT")) { //$NON-NLS-1$ + return -4; + } + if (text.equals("CST")) { //$NON-NLS-1$ + return -6; + } + if (text.equals("CDT")) { //$NON-NLS-1$ + return -5; + } + if (text.equals("MST")) { //$NON-NLS-1$ + return -7; + } + if (text.equals("MDT")) { //$NON-NLS-1$ + return -6; + } + if (text.equals("PST")) { //$NON-NLS-1$ + return -8; + } + if (text.equals("PDT")) { //$NON-NLS-1$ + return -7; + } + return 0; + } + + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.defaultWriteObject(); + stream.writeLong(getTime()); + } + + private void readObject(ObjectInputStream stream) throws IOException, + ClassNotFoundException { + stream.defaultReadObject(); + setTime(stream.readLong()); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java new file mode 100644 index 000000000..90ab6a763 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java @@ -0,0 +1,1439 @@ +/* + * 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.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +/** + * {@code GregorianCalendar} is a concrete subclass of {@link Calendar} + * and provides the standard calendar used by most of the world. + * + *

+ * The standard (Gregorian) calendar has 2 eras, BC and AD. + * + *

+ * This implementation handles a single discontinuity, which corresponds by + * default to the date the Gregorian calendar was instituted (October 15, 1582 + * in some countries, later in others). The cutover date may be changed by the + * caller by calling {@code setGregorianChange()}. + * + *

+ * Historically, in those countries which adopted the Gregorian calendar first, + * October 4, 1582 was thus followed by October 15, 1582. This calendar models + * this correctly. Before the Gregorian cutover, {@code GregorianCalendar} + * implements the Julian calendar. The only difference between the Gregorian and + * the Julian calendar is the leap year rule. The Julian calendar specifies leap + * years every four years, whereas the Gregorian calendar omits century years + * which are not divisible by 400. + * + *

+ * {@code GregorianCalendar} implements proleptic Gregorian + * and Julian calendars. That is, dates are computed by extrapolating the + * current rules indefinitely far backward and forward in time. As a result, + * {@code GregorianCalendar} may be used for all years to generate + * meaningful and consistent results. However, dates obtained using + * {@code GregorianCalendar} are historically accurate only from March 1, + * 4 AD onward, when modern Julian calendar rules were adopted. Before this + * date, leap year rules were applied irregularly, and before 45 BC the Julian + * calendar did not even exist. + * + *

+ * Prior to the institution of the Gregorian calendar, New Year's Day was March + * 25. To avoid confusion, this calendar always uses January 1. A manual + * adjustment may be made if desired for dates that are prior to the Gregorian + * changeover and which fall between January 1 and March 24. + * + *

+ * Values calculated for the {@code WEEK_OF_YEAR} field range from 1 to + * 53. Week 1 for a year is the earliest seven day period starting on + * {@code getFirstDayOfWeek()} that contains at least + * {@code getMinimalDaysInFirstWeek()} days from that year. It thus + * depends on the values of {@code getMinimalDaysInFirstWeek()}, + * {@code getFirstDayOfWeek()}, and the day of the week of January 1. + * Weeks between week 1 of one year and week 1 of the following year are + * numbered sequentially from 2 to 52 or 53 (as needed). + * + *

+ * For example, January 1, 1998 was a Thursday. If + * {@code getFirstDayOfWeek()} is {@code MONDAY} and + * {@code getMinimalDaysInFirstWeek()} is 4 (these are the values + * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts + * on December 29, 1997, and ends on January 4, 1998. If, however, + * {@code getFirstDayOfWeek()} is {@code SUNDAY}, then week 1 of + * 1998 starts on January 4, 1998, and ends on January 10, 1998; the first three + * days of 1998 then are part of week 53 of 1997. + * + *

+ * Values calculated for the {@code WEEK_OF_MONTH} field range from 0 or + * 1 to 4 or 5. Week 1 of a month (the days with WEEK_OF_MONTH = + * 1) + * is the earliest set of at least {@code getMinimalDaysInFirstWeek()} + * contiguous days in that month, ending on the day before + * {@code getFirstDayOfWeek()}. Unlike week 1 of a year, week 1 of a + * month may be shorter than 7 days, need not start on + * {@code getFirstDayOfWeek()}, and will not include days of the + * previous month. Days of a month before week 1 have a + * {@code WEEK_OF_MONTH} of 0. + * + *

+ * For example, if {@code getFirstDayOfWeek()} is {@code SUNDAY} + * and {@code getMinimalDaysInFirstWeek()} is 4, then the first week of + * January 1998 is Sunday, January 4 through Saturday, January 10. These days + * have a {@code WEEK_OF_MONTH} of 1. Thursday, January 1 through + * Saturday, January 3 have a {@code WEEK_OF_MONTH} of 0. If + * {@code getMinimalDaysInFirstWeek()} is changed to 3, then January 1 + * through January 3 have a {@code WEEK_OF_MONTH} of 1. + * + *

+ * Example:

+ * + *
+ * // get the supported ids for GMT-08:00 (Pacific Standard Time)
+ * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
+ * // if no ids were returned, something is wrong. get out.
+ * if (ids.length == 0)
+ *     System.exit(0);
+ *
+ *  // begin output
+ * System.out.println("Current Time");
+ *
+ * // create a Pacific Standard Time time zone
+ * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
+ *
+ * // set up rules for daylight savings time
+ * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
+ * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
+ *
+ * // create a GregorianCalendar with the Pacific Daylight time zone
+ * // and the current date and time
+ * Calendar calendar = new GregorianCalendar(pdt);
+ * Date trialTime = new Date();
+ * calendar.setTime(trialTime);
+ *
+ * // print out a bunch of interesting things
+ * System.out.println("ERA: " + calendar.get(Calendar.ERA));
+ * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
+ * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
+ * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
+ * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
+ * System.out.println("DATE: " + calendar.get(Calendar.DATE));
+ * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
+ * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
+ * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
+ * System.out.println("DAY_OF_WEEK_IN_MONTH: "
+ *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
+ * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
+ * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
+ * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
+ * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
+ * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
+ * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
+ * System.out.println("ZONE_OFFSET: "
+ *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
+ * System.out.println("DST_OFFSET: "
+ *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
+
+ * System.out.println("Current Time, with hour reset to 3");
+ * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
+ * calendar.set(Calendar.HOUR, 3);
+ * System.out.println("ERA: " + calendar.get(Calendar.ERA));
+ * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
+ * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
+ * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
+ * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
+ * System.out.println("DATE: " + calendar.get(Calendar.DATE));
+ * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
+ * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
+ * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
+ * System.out.println("DAY_OF_WEEK_IN_MONTH: "
+ *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
+ * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
+ * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
+ * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
+ * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
+ * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
+ * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
+ * System.out.println("ZONE_OFFSET: "
+ *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
+ * System.out.println("DST_OFFSET: "
+ *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
+ * 
+ * + *
+ * + * @see Calendar + * @see TimeZone + */ +public class GregorianCalendar extends Calendar { + + private static final long serialVersionUID = -8125100834729963327L; + + /** + * Value for the BC era. + */ + public static final int BC = 0; + + /** + * Value for the AD era. + */ + public static final int AD = 1; + + private static final long defaultGregorianCutover = -12219292800000l; + + private long gregorianCutover = defaultGregorianCutover; + + private transient int changeYear = 1582; + + private transient int julianSkew = ((changeYear - 2000) / 400) + + julianError() - ((changeYear - 2000) / 100); + + static byte[] DaysInMonth = new byte[] { 31, 28, 31, 30, 31, 30, 31, 31, + 30, 31, 30, 31 }; + + private static int[] DaysInYear = new int[] { 0, 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334 }; + + private static int[] maximums = new int[] { 1, 292278994, 11, 53, 6, 31, + 366, 7, 6, 1, 11, 23, 59, 59, 999, 14 * 3600 * 1000, 7200000 }; + + private static int[] minimums = new int[] { 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, -13 * 3600 * 1000, 0 }; + + private static int[] leastMaximums = new int[] { 1, 292269054, 11, 50, 3, + 28, 355, 7, 3, 1, 11, 23, 59, 59, 999, 50400000, 1200000 }; + + private boolean isCached; + + private int cachedFields[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + private long nextMidnightMillis = 0L; + + private long lastMidnightMillis = 0L; + + private int currentYearSkew = 10; + + private int lastYearSkew = 0; + + /** + * Constructs a new {@code GregorianCalendar} initialized to the current date and + * time with the default {@code Locale} and {@code TimeZone}. + */ + public GregorianCalendar() { + this(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Constructs a new {@code GregorianCalendar} initialized to midnight in the default + * {@code TimeZone} and {@code Locale} on the specified date. + * + * @param year + * the year. + * @param month + * the month. + * @param day + * the day of the month. + */ + public GregorianCalendar(int year, int month, int day) { + super(TimeZone.getDefault(), Locale.getDefault()); + set(year, month, day); + } + + /** + * Constructs a new {@code GregorianCalendar} initialized to the specified date and + * time in the default {@code TimeZone} and {@code Locale}. + * + * @param year + * the year. + * @param month + * the month. + * @param day + * the day of the month. + * @param hour + * the hour. + * @param minute + * the minute. + */ + public GregorianCalendar(int year, int month, int day, int hour, int minute) { + super(TimeZone.getDefault(), Locale.getDefault()); + set(year, month, day, hour, minute); + } + + /** + * Constructs a new {@code GregorianCalendar} initialized to the specified date and + * time in the default {@code TimeZone} and {@code Locale}. + * + * @param year + * the year. + * @param month + * the month. + * @param day + * the day of the month. + * @param hour + * the hour. + * @param minute + * the minute. + * @param second + * the second. + */ + public GregorianCalendar(int year, int month, int day, int hour, + int minute, int second) { + super(TimeZone.getDefault(), Locale.getDefault()); + set(year, month, day, hour, minute, second); + } + + GregorianCalendar(long milliseconds) { + this(false); + setTimeInMillis(milliseconds); + } + + /** + * Constructs a new {@code GregorianCalendar} initialized to the current date and + * time and using the specified {@code Locale} and the default {@code TimeZone}. + * + * @param locale + * the {@code Locale}. + */ + public GregorianCalendar(Locale locale) { + this(TimeZone.getDefault(), locale); + } + + /** + * Constructs a new {@code GregorianCalendar} initialized to the current date and + * time and using the specified {@code TimeZone} and the default {@code Locale}. + * + * @param timezone + * the {@code TimeZone}. + */ + public GregorianCalendar(TimeZone timezone) { + this(timezone, Locale.getDefault()); + } + + /** + * Constructs a new {@code GregorianCalendar} initialized to the current date and + * time and using the specified {@code TimeZone} and {@code Locale}. + * + * @param timezone + * the {@code TimeZone}. + * @param locale + * the {@code Locale}. + */ + public GregorianCalendar(TimeZone timezone, Locale locale) { + super(timezone, locale); + setTimeInMillis(System.currentTimeMillis()); + } + + GregorianCalendar(boolean ignored) { + super(TimeZone.getDefault()); + setFirstDayOfWeek(SUNDAY); + setMinimalDaysInFirstWeek(1); + } + + /** + * Adds the specified amount to a {@code Calendar} field. + * + * @param field + * the {@code Calendar} field to modify. + * @param value + * the amount to add to the field. + * + * @throws IllegalArgumentException + * if the specified field is DST_OFFSET or ZONE_OFFSET. + */ + @Override + public void add(int field, int value) { + if (value == 0) { + return; + } + if (field < 0 || field >= ZONE_OFFSET) { + throw new IllegalArgumentException(); + } + + isCached = false; + + if (field == ERA) { + complete(); + if (fields[ERA] == AD) { + if (value >= 0) { + return; + } + set(ERA, BC); + } else { + if (value <= 0) { + return; + } + set(ERA, AD); + } + complete(); + return; + } + + if (field == YEAR || field == MONTH) { + complete(); + if (field == MONTH) { + int month = fields[MONTH] + value; + if (month < 0) { + value = (month - 11) / 12; + month = 12 + (month % 12); + } else { + value = month / 12; + } + set(MONTH, month % 12); + } + set(YEAR, fields[YEAR] + value); + int days = daysInMonth(isLeapYear(fields[YEAR]), fields[MONTH]); + if (fields[DATE] > days) { + set(DATE, days); + } + complete(); + return; + } + + long multiplier = 0; + getTimeInMillis(); // Update the time + switch (field) { + case MILLISECOND: + time += value; + break; + case SECOND: + time += value * 1000L; + break; + case MINUTE: + time += value * 60000L; + break; + case HOUR: + case HOUR_OF_DAY: + time += value * 3600000L; + break; + case AM_PM: + multiplier = 43200000L; + break; + case DATE: + case DAY_OF_YEAR: + case DAY_OF_WEEK: + multiplier = 86400000L; + break; + case WEEK_OF_YEAR: + case WEEK_OF_MONTH: + case DAY_OF_WEEK_IN_MONTH: + multiplier = 604800000L; + break; + } + if (multiplier > 0) { + int zoneOffset = getTimeZone().getRawOffset(); + int offset = getOffset(time + zoneOffset); + time += value * multiplier; + int newOffset = getOffset(time + zoneOffset); + // Adjust for moving over a DST boundary + if (newOffset != offset) { + time += offset - newOffset; + } + } + areFieldsSet = false; + complete(); + } + + /** + * Creates new instance of {@code GregorianCalendar} with the same properties. + * + * @return a shallow copy of this {@code GregorianCalendar}. + */ + @Override + public Object clone() { + GregorianCalendar thisClone = (GregorianCalendar) super.clone(); + thisClone.cachedFields = cachedFields.clone(); + return thisClone; + } + + private final void fullFieldsCalc(long timeVal, int millis, int zoneOffset) { + long days = timeVal / 86400000; + + if (millis < 0) { + millis += 86400000; + days--; + } + // Cannot add ZONE_OFFSET to time as it might overflow + millis += zoneOffset; + while (millis < 0) { + millis += 86400000; + days--; + } + while (millis >= 86400000) { + millis -= 86400000; + days++; + } + + int dayOfYear = computeYearAndDay(days, timeVal + zoneOffset); + fields[DAY_OF_YEAR] = dayOfYear; + if(fields[YEAR] == changeYear && gregorianCutover <= timeVal + zoneOffset){ + dayOfYear += currentYearSkew; + } + int month = dayOfYear / 32; + boolean leapYear = isLeapYear(fields[YEAR]); + int date = dayOfYear - daysInYear(leapYear, month); + if (date > daysInMonth(leapYear, month)) { + date -= daysInMonth(leapYear, month); + month++; + } + fields[DAY_OF_WEEK] = mod7(days - 3) + 1; + int dstOffset = fields[YEAR] <= 0 ? 0 : getTimeZone().getOffset(AD, + fields[YEAR], month, date, fields[DAY_OF_WEEK], millis); + if (fields[YEAR] > 0) { + dstOffset -= zoneOffset; + } + fields[DST_OFFSET] = dstOffset; + if (dstOffset != 0) { + long oldDays = days; + millis += dstOffset; + if (millis < 0) { + millis += 86400000; + days--; + } else if (millis >= 86400000) { + millis -= 86400000; + days++; + } + if (oldDays != days) { + dayOfYear = computeYearAndDay(days, timeVal - zoneOffset + + dstOffset); + fields[DAY_OF_YEAR] = dayOfYear; + if(fields[YEAR] == changeYear && gregorianCutover <= timeVal - zoneOffset + dstOffset){ + dayOfYear += currentYearSkew; + } + month = dayOfYear / 32; + leapYear = isLeapYear(fields[YEAR]); + date = dayOfYear - daysInYear(leapYear, month); + if (date > daysInMonth(leapYear, month)) { + date -= daysInMonth(leapYear, month); + month++; + } + fields[DAY_OF_WEEK] = mod7(days - 3) + 1; + } + } + + fields[MILLISECOND] = (millis % 1000); + millis /= 1000; + fields[SECOND] = (millis % 60); + millis /= 60; + fields[MINUTE] = (millis % 60); + millis /= 60; + fields[HOUR_OF_DAY] = (millis % 24); + fields[AM_PM] = fields[HOUR_OF_DAY] > 11 ? 1 : 0; + fields[HOUR] = fields[HOUR_OF_DAY] % 12; + + if (fields[YEAR] <= 0) { + fields[ERA] = BC; + fields[YEAR] = -fields[YEAR] + 1; + } else { + fields[ERA] = AD; + } + fields[MONTH] = month; + fields[DATE] = date; + fields[DAY_OF_WEEK_IN_MONTH] = (date - 1) / 7 + 1; + fields[WEEK_OF_MONTH] = (date - 1 + mod7(days - date - 2 + - (getFirstDayOfWeek() - 1))) / 7 + 1; + int daysFromStart = mod7(days - 3 - (fields[DAY_OF_YEAR] - 1) + - (getFirstDayOfWeek() - 1)); + int week = (fields[DAY_OF_YEAR] - 1 + daysFromStart) / 7 + + (7 - daysFromStart >= getMinimalDaysInFirstWeek() ? 1 : 0); + if (week == 0) { + fields[WEEK_OF_YEAR] = 7 - mod7(daysFromStart + - (isLeapYear(fields[YEAR] - 1) ? 2 : 1)) >= getMinimalDaysInFirstWeek() ? 53 + : 52; + } else if (fields[DAY_OF_YEAR] >= (leapYear ? 367 : 366) + - mod7(daysFromStart + (leapYear ? 2 : 1))) { + fields[WEEK_OF_YEAR] = 7 - mod7(daysFromStart + (leapYear ? 2 : 1)) >= getMinimalDaysInFirstWeek() ? 1 + : week; + } else { + fields[WEEK_OF_YEAR] = week; + } + } + + private final void cachedFieldsCheckAndGet(long timeVal, + long newTimeMillis, long newTimeMillisAdjusted, int millis, + int zoneOffset) { + int dstOffset = fields[DST_OFFSET]; + if (!isCached + || newTimeMillis >= nextMidnightMillis + || newTimeMillis <= lastMidnightMillis + || cachedFields[4] != zoneOffset + || (dstOffset == 0 && (newTimeMillisAdjusted >= nextMidnightMillis)) + || (dstOffset != 0 && (newTimeMillisAdjusted <= lastMidnightMillis))) { + fullFieldsCalc(timeVal, millis, zoneOffset); + isCached = false; + } else { + fields[YEAR] = cachedFields[0]; + fields[MONTH] = cachedFields[1]; + fields[DATE] = cachedFields[2]; + fields[DAY_OF_WEEK] = cachedFields[3]; + fields[ERA] = cachedFields[5]; + fields[WEEK_OF_YEAR] = cachedFields[6]; + fields[WEEK_OF_MONTH] = cachedFields[7]; + fields[DAY_OF_YEAR] = cachedFields[8]; + fields[DAY_OF_WEEK_IN_MONTH] = cachedFields[9]; + } + } + + @Override + protected void computeFields() { + int zoneOffset = getTimeZone().getRawOffset(); + + if(!isSet[ZONE_OFFSET]) { + fields[ZONE_OFFSET] = zoneOffset; + } + + int millis = (int) (time % 86400000); + int savedMillis = millis; + int dstOffset = fields[DST_OFFSET]; + // compute without a change in daylight saving time + int offset = zoneOffset + dstOffset; + long newTime = time + offset; + + if (time > 0L && newTime < 0L && offset > 0) { + newTime = 0x7fffffffffffffffL; + } else if (time < 0L && newTime > 0L && offset < 0) { + newTime = 0x8000000000000000L; + } + + if (isCached) { + if (millis < 0) { + millis += 86400000; + } + + // Cannot add ZONE_OFFSET to time as it might overflow + millis += zoneOffset; + millis += dstOffset; + + if (millis < 0) { + millis += 86400000; + } else if (millis >= 86400000) { + millis -= 86400000; + } + + fields[MILLISECOND] = (millis % 1000); + millis /= 1000; + fields[SECOND] = (millis % 60); + millis /= 60; + fields[MINUTE] = (millis % 60); + millis /= 60; + fields[HOUR_OF_DAY] = (millis % 24); + millis /= 24; + fields[AM_PM] = fields[HOUR_OF_DAY] > 11 ? 1 : 0; + fields[HOUR] = fields[HOUR_OF_DAY] % 12; + + long newTimeAdjusted = newTime; + if (getTimeZone().useDaylightTime()) { + int dstSavings = ((SimpleTimeZone) getTimeZone()) + .getDSTSavings(); + newTimeAdjusted += (dstOffset == 0) ? dstSavings : -dstSavings; + } + + if (newTime > 0L && newTimeAdjusted < 0L && dstOffset == 0) { + newTimeAdjusted = 0x7fffffffffffffffL; + } else if (newTime < 0L && newTimeAdjusted > 0L && dstOffset != 0) { + newTimeAdjusted = 0x8000000000000000L; + } + + cachedFieldsCheckAndGet(time, newTime, newTimeAdjusted, + savedMillis, zoneOffset); + } else { + fullFieldsCalc(time, savedMillis, zoneOffset); + } + + for (int i = 0; i < FIELD_COUNT; i++) { + isSet[i] = true; + } + + // Caching + if (!isCached + && newTime != 0x7fffffffffffffffL + && newTime != 0x8000000000000000L + && (!getTimeZone().useDaylightTime() || getTimeZone() instanceof SimpleTimeZone)) { + int cacheMillis = 0; + + cachedFields[0] = fields[YEAR]; + cachedFields[1] = fields[MONTH]; + cachedFields[2] = fields[DATE]; + cachedFields[3] = fields[DAY_OF_WEEK]; + cachedFields[4] = zoneOffset; + cachedFields[5] = fields[ERA]; + cachedFields[6] = fields[WEEK_OF_YEAR]; + cachedFields[7] = fields[WEEK_OF_MONTH]; + cachedFields[8] = fields[DAY_OF_YEAR]; + cachedFields[9] = fields[DAY_OF_WEEK_IN_MONTH]; + + cacheMillis += (23 - fields[HOUR_OF_DAY]) * 60 * 60 * 1000; + cacheMillis += (59 - fields[MINUTE]) * 60 * 1000; + cacheMillis += (59 - fields[SECOND]) * 1000; + nextMidnightMillis = newTime + cacheMillis; + + cacheMillis = fields[HOUR_OF_DAY] * 60 * 60 * 1000; + cacheMillis += fields[MINUTE] * 60 * 1000; + cacheMillis += fields[SECOND] * 1000; + lastMidnightMillis = newTime - cacheMillis; + + isCached = true; + } + } + + @Override + protected void computeTime() { + if (!isLenient()) { + if (isSet[HOUR_OF_DAY]) { + if (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23) { + throw new IllegalArgumentException(); + } + } else if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) { + throw new IllegalArgumentException(); + } + if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59)) { + throw new IllegalArgumentException(); + } + if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59)) { + throw new IllegalArgumentException(); + } + if (isSet[MILLISECOND] + && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) { + throw new IllegalArgumentException(); + } + if (isSet[WEEK_OF_YEAR] + && (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > 53)) { + throw new IllegalArgumentException(); + } + if (isSet[DAY_OF_WEEK] + && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) { + throw new IllegalArgumentException(); + } + if (isSet[DAY_OF_WEEK_IN_MONTH] + && (fields[DAY_OF_WEEK_IN_MONTH] < 1 || fields[DAY_OF_WEEK_IN_MONTH] > 6)) { + throw new IllegalArgumentException(); + } + if (isSet[WEEK_OF_MONTH] + && (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > 6)) { + throw new IllegalArgumentException(); + } + if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM) { + throw new IllegalArgumentException(); + } + if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) { + throw new IllegalArgumentException(); + } + if (isSet[YEAR]) { + if (isSet[ERA] && fields[ERA] == BC + && (fields[YEAR] < 1 || fields[YEAR] > 292269054)) { + throw new IllegalArgumentException(); + } else if (fields[YEAR] < 1 || fields[YEAR] > 292278994) { + throw new IllegalArgumentException(); + } + } + if (isSet[MONTH] && (fields[MONTH] < 0 || fields[MONTH] > 11)) { + throw new IllegalArgumentException(); + } + } + + long timeVal; + long hour = 0; + if (isSet[HOUR_OF_DAY] && lastTimeFieldSet != HOUR) { + hour = fields[HOUR_OF_DAY]; + } else if (isSet[HOUR]) { + hour = (fields[AM_PM] * 12) + fields[HOUR]; + } + timeVal = hour * 3600000; + + if (isSet[MINUTE]) { + timeVal += ((long) fields[MINUTE]) * 60000; + } + if (isSet[SECOND]) { + timeVal += ((long) fields[SECOND]) * 1000; + } + if (isSet[MILLISECOND]) { + timeVal += fields[MILLISECOND]; + } + + long days; + int year = isSet[YEAR] ? fields[YEAR] : 1970; + if (isSet[ERA]) { + // Always test for valid ERA, even if the Calendar is lenient + if (fields[ERA] != BC && fields[ERA] != AD) { + throw new IllegalArgumentException(); + } + if (fields[ERA] == BC) { + year = 1 - year; + } + } + + boolean weekMonthSet = isSet[WEEK_OF_MONTH] + || isSet[DAY_OF_WEEK_IN_MONTH]; + boolean useMonth = (isSet[DATE] || isSet[MONTH] || weekMonthSet) + && lastDateFieldSet != DAY_OF_YEAR; + if (useMonth + && (lastDateFieldSet == DAY_OF_WEEK || lastDateFieldSet == WEEK_OF_YEAR)) { + if (isSet[WEEK_OF_YEAR] && isSet[DAY_OF_WEEK]) { + useMonth = lastDateFieldSet != WEEK_OF_YEAR && weekMonthSet + && isSet[DAY_OF_WEEK]; + } else if (isSet[DAY_OF_YEAR]) { + useMonth = isSet[DATE] && isSet[MONTH]; + } + } + + if (useMonth) { + int month = fields[MONTH]; + year += month / 12; + month %= 12; + if (month < 0) { + year--; + month += 12; + } + boolean leapYear = isLeapYear(year); + days = daysFromBaseYear(year) + daysInYear(leapYear, month); + boolean useDate = isSet[DATE]; + if (useDate + && (lastDateFieldSet == DAY_OF_WEEK + || lastDateFieldSet == WEEK_OF_MONTH || lastDateFieldSet == DAY_OF_WEEK_IN_MONTH)) { + useDate = !(isSet[DAY_OF_WEEK] && weekMonthSet); + } + if (useDate) { + if (!isLenient() + && (fields[DATE] < 1 || fields[DATE] > daysInMonth( + leapYear, month))) { + throw new IllegalArgumentException(); + } + days += fields[DATE] - 1; + } else { + int dayOfWeek; + if (isSet[DAY_OF_WEEK]) { + dayOfWeek = fields[DAY_OF_WEEK] - 1; + } else { + dayOfWeek = getFirstDayOfWeek() - 1; + } + if (isSet[WEEK_OF_MONTH] + && lastDateFieldSet != DAY_OF_WEEK_IN_MONTH) { + int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1)); + days += (fields[WEEK_OF_MONTH] - 1) * 7 + + mod7(skew + dayOfWeek - (days - 3)) - skew; + } else if (isSet[DAY_OF_WEEK_IN_MONTH]) { + if (fields[DAY_OF_WEEK_IN_MONTH] >= 0) { + days += mod7(dayOfWeek - (days - 3)) + + (fields[DAY_OF_WEEK_IN_MONTH] - 1) * 7; + } else { + days += daysInMonth(leapYear, month) + + mod7(dayOfWeek + - (days + daysInMonth(leapYear, month) - 3)) + + fields[DAY_OF_WEEK_IN_MONTH] * 7; + } + } else if (isSet[DAY_OF_WEEK]) { + int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1)); + days += mod7(mod7(skew + dayOfWeek - (days - 3)) - skew); + } + } + } else { + boolean useWeekYear = isSet[WEEK_OF_YEAR] + && lastDateFieldSet != DAY_OF_YEAR; + if (useWeekYear && isSet[DAY_OF_YEAR]) { + useWeekYear = isSet[DAY_OF_WEEK]; + } + days = daysFromBaseYear(year); + if (useWeekYear) { + int dayOfWeek; + if (isSet[DAY_OF_WEEK]) { + dayOfWeek = fields[DAY_OF_WEEK] - 1; + } else { + dayOfWeek = getFirstDayOfWeek() - 1; + } + int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1)); + days += (fields[WEEK_OF_YEAR] - 1) * 7 + + mod7(skew + dayOfWeek - (days - 3)) - skew; + if (7 - skew < getMinimalDaysInFirstWeek()) { + days += 7; + } + } else if (isSet[DAY_OF_YEAR]) { + if (!isLenient() + && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > (365 + (isLeapYear(year) ? 1 + : 0)))) { + throw new IllegalArgumentException(); + } + days += fields[DAY_OF_YEAR] - 1; + } else if (isSet[DAY_OF_WEEK]) { + days += mod7(fields[DAY_OF_WEEK] - 1 - (days - 3)); + } + } + lastDateFieldSet = 0; + + timeVal += days * 86400000; + // Use local time to compare with the gregorian change + if (year == changeYear + && timeVal >= gregorianCutover + julianError() * 86400000L) { + timeVal -= julianError() * 86400000L; + } + + // It is not possible to simply subtract getOffset(timeVal) from timeVal + // to get UTC. + // The trick is needed for the moment when DST transition occurs, + // say 1:00 is a transition time when DST offset becomes +1 hour, + // then wall time in the interval 1:00 - 2:00 is invalid and is + // treated as UTC time. + long timeValWithoutDST = timeVal - getOffset(timeVal) + + getTimeZone().getRawOffset(); + timeVal -= getOffset(timeValWithoutDST); + // Need to update wall time in fields, since it was invalid due to DST + // transition + this.time = timeVal; + if (timeValWithoutDST != timeVal) { + computeFields(); + areFieldsSet = true; + } + } + + private int computeYearAndDay(long dayCount, long localTime) { + int year = 1970; + long days = dayCount; + if (localTime < gregorianCutover) { + days -= julianSkew; + } + int approxYears; + + while ((approxYears = (int) (days / 365)) != 0) { + year = year + approxYears; + days = dayCount - daysFromBaseYear(year); + } + if (days < 0) { + year = year - 1; + days = days + daysInYear(year); + } + fields[YEAR] = year; + return (int) days + 1; + } + + private long daysFromBaseYear(int iyear) { + long year = iyear; + + if (year >= 1970) { + long days = (year - 1970) * 365 + ((year - 1969) / 4); + if (year > changeYear) { + days -= ((year - 1901) / 100) - ((year - 1601) / 400); + } else { + if(year == changeYear){ + days += currentYearSkew; + }else if(year == changeYear -1){ + days += lastYearSkew; + }else{ + days += julianSkew; + } + } + return days; + } else if (year <= changeYear) { + return (year - 1970) * 365 + ((year - 1972) / 4) + julianSkew; + } + return (year - 1970) * 365 + ((year - 1972) / 4) + - ((year - 2000) / 100) + ((year - 2000) / 400); + } + + private int daysInMonth() { + return daysInMonth(isLeapYear(fields[YEAR]), fields[MONTH]); + } + + private int daysInMonth(boolean leapYear, int month) { + if (leapYear && month == FEBRUARY) { + return DaysInMonth[month] + 1; + } + + return DaysInMonth[month]; + } + + private int daysInYear(int year) { + int daysInYear = isLeapYear(year) ? 366 : 365; + if (year == changeYear) { + daysInYear -= currentYearSkew; + } + if (year == changeYear - 1) { + daysInYear -= lastYearSkew; + } + return daysInYear; + } + + private int daysInYear(boolean leapYear, int month) { + if (leapYear && month > FEBRUARY) { + return DaysInYear[month] + 1; + } + + return DaysInYear[month]; + } + + /** + * Compares the specified {@code Object} to this {@code GregorianCalendar} and returns whether + * they are equal. To be equal, the {@code Object} must be an instance of {@code GregorianCalendar} and + * have the same properties. + * + * @param object + * the {@code Object} to compare with this {@code GregorianCalendar}. + * @return {@code true} if {@code object} is equal to this + * {@code GregorianCalendar}, {@code false} otherwise. + * @throws IllegalArgumentException + * if the time is not set and the time cannot be computed + * from the current field values. + * @see #hashCode + */ + @Override + public boolean equals(Object object) { + return super.equals(object) + && gregorianCutover == ((GregorianCalendar) object).gregorianCutover; + } + + /** + * Gets the maximum value of the specified field for the current date. For + * example, the maximum number of days in the current month. + * + * @param field + * the field. + * @return the maximum value of the specified field. + */ + @Override + public int getActualMaximum(int field) { + int value; + if ((value = maximums[field]) == leastMaximums[field]) { + return value; + } + + switch (field) { + case WEEK_OF_YEAR: + case WEEK_OF_MONTH: + isCached = false; + break; + } + + complete(); + long orgTime = time; + int result = 0; + switch (field) { + case WEEK_OF_YEAR: + set(DATE, 31); + set(MONTH, DECEMBER); + result = get(WEEK_OF_YEAR); + if (result == 1) { + set(DATE, 31 - 7); + result = get(WEEK_OF_YEAR); + } + areFieldsSet = false; + break; + case WEEK_OF_MONTH: + set(DATE, daysInMonth()); + result = get(WEEK_OF_MONTH); + areFieldsSet = false; + break; + case DATE: + return daysInMonth(); + case DAY_OF_YEAR: + return daysInYear(fields[YEAR]); + case DAY_OF_WEEK_IN_MONTH: + result = get(DAY_OF_WEEK_IN_MONTH) + + ((daysInMonth() - get(DATE)) / 7); + break; + case YEAR: + GregorianCalendar clone = (GregorianCalendar) clone(); + if (get(ERA) == AD) { + clone.setTimeInMillis(Long.MAX_VALUE); + } else { + clone.setTimeInMillis(Long.MIN_VALUE); + } + result = clone.get(YEAR); + clone.set(YEAR, get(YEAR)); + if (clone.before(this)) { + result--; + } + break; + case DST_OFFSET: + result = getMaximum(DST_OFFSET); + break; + } + time = orgTime; + return result; + } + + /** + * Gets the minimum value of the specified field for the current date. For + * the gregorian calendar, this value is the same as + * {@code getMinimum()}. + * + * @param field + * the field. + * @return the minimum value of the specified field. + */ + @Override + public int getActualMinimum(int field) { + return getMinimum(field); + } + + /** + * Gets the greatest minimum value of the specified field. For the gregorian + * calendar, this value is the same as {@code getMinimum()}. + * + * @param field + * the field. + * @return the greatest minimum value of the specified field. + */ + @Override + public int getGreatestMinimum(int field) { + return minimums[field]; + } + + /** + * Returns the gregorian change date of this calendar. This is the date on + * which the gregorian calendar came into effect. + * + * @return a {@code Date} which represents the gregorian change date. + */ + public final Date getGregorianChange() { + return new Date(gregorianCutover); + } + + /** + * Gets the smallest maximum value of the specified field. For example, 28 + * for the day of month field. + * + * @param field + * the field. + * @return the smallest maximum value of the specified field. + */ + @Override + public int getLeastMaximum(int field) { + // return value for WEEK_OF_YEAR should make corresponding changes when + // the gregorian change date have been reset. + if (gregorianCutover != defaultGregorianCutover + && field == WEEK_OF_YEAR) { + long currentTimeInMillis = time; + setTimeInMillis(gregorianCutover); + int actual = getActualMaximum(field); + setTimeInMillis(currentTimeInMillis); + return actual; + } + return leastMaximums[field]; + } + + /** + * Gets the greatest maximum value of the specified field. For example, 31 + * for the day of month field. + * + * @param field + * the field. + * @return the greatest maximum value of the specified field. + */ + @Override + public int getMaximum(int field) { + return maximums[field]; + } + + /** + * Gets the smallest minimum value of the specified field. + * + * @param field + * the field. + * @return the smallest minimum value of the specified field. + */ + @Override + public int getMinimum(int field) { + return minimums[field]; + } + + int getOffset(long localTime) { + TimeZone timeZone = getTimeZone(); + if (!timeZone.useDaylightTime()) { + return timeZone.getRawOffset(); + } + + long dayCount = localTime / 86400000; + int millis = (int) (localTime % 86400000); + if (millis < 0) { + millis += 86400000; + dayCount--; + } + + int year = 1970; + long days = dayCount; + if (localTime < gregorianCutover) { + days -= julianSkew; + } + int approxYears; + + while ((approxYears = (int) (days / 365)) != 0) { + year = year + approxYears; + days = dayCount - daysFromBaseYear(year); + } + if (days < 0) { + year = year - 1; + days = days + 365 + (isLeapYear(year) ? 1 : 0); + if (year == changeYear && localTime < gregorianCutover) { + days -= julianError(); + } + } + if (year <= 0) { + return timeZone.getRawOffset(); + } + int dayOfYear = (int) days + 1; + + int month = dayOfYear / 32; + boolean leapYear = isLeapYear(year); + int date = dayOfYear - daysInYear(leapYear, month); + if (date > daysInMonth(leapYear, month)) { + date -= daysInMonth(leapYear, month); + month++; + } + int dayOfWeek = mod7(dayCount - 3) + 1; + int offset = timeZone.getOffset(AD, year, month, date, dayOfWeek, + millis); + return offset; + } + + /** + * Returns an integer hash code for the receiver. Objects which are equal + * return the same value for this method. + * + * @return the receiver's hash. + * + * @see #equals + */ + @Override + public int hashCode() { + return super.hashCode() + + ((int) (gregorianCutover >>> 32) ^ (int) gregorianCutover); + } + + /** + * Returns whether the specified year is a leap year. + * + * @param year + * the year. + * @return {@code true} if the specified year is a leap year, {@code false} + * otherwise. + */ + public boolean isLeapYear(int year) { + if (year > changeYear) { + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + } + + return year % 4 == 0; + } + + private int julianError() { + return changeYear / 100 - changeYear / 400 - 2; + } + + private int mod(int value, int mod) { + int rem = value % mod; + if (value < 0 && rem < 0) { + return rem + mod; + } + return rem; + } + + private int mod7(long num1) { + int rem = (int) (num1 % 7); + if (num1 < 0 && rem < 0) { + return rem + 7; + } + return rem; + } + + /** + * Adds the specified amount the specified field and wraps the value of the + * field when it goes beyond the maximum or minimum value for the current + * date. Other fields will be adjusted as required to maintain a consistent + * date. + * + * @param field + * the field to roll. + * @param value + * the amount to add. + * + * @throws IllegalArgumentException + * if an invalid field is specified. + */ + @Override + public void roll(int field, int value) { + if (value == 0) { + return; + } + if (field < 0 || field >= ZONE_OFFSET) { + throw new IllegalArgumentException(); + } + + isCached = false; + + complete(); + int days, day, mod, maxWeeks, newWeek; + int max = -1; + switch (field) { + case YEAR: + max = maximums[field]; + break; + case WEEK_OF_YEAR: + days = daysInYear(fields[YEAR]); + day = DAY_OF_YEAR; + mod = mod7(fields[DAY_OF_WEEK] - fields[day] + - (getFirstDayOfWeek() - 1)); + maxWeeks = (days - 1 + mod) / 7 + 1; + newWeek = mod(fields[field] - 1 + value, maxWeeks) + 1; + if (newWeek == maxWeeks) { + int addDays = (newWeek - fields[field]) * 7; + if (fields[day] > addDays && fields[day] + addDays > days) { + set(field, 1); + } else { + set(field, newWeek - 1); + } + } else if (newWeek == 1) { + int week = (fields[day] - ((fields[day] - 1) / 7 * 7) - 1 + mod) / 7 + 1; + if (week > 1) { + set(field, 1); + } else { + set(field, newWeek); + } + } else { + set(field, newWeek); + } + break; + case WEEK_OF_MONTH: + days = daysInMonth(); + day = DATE; + mod = mod7(fields[DAY_OF_WEEK] - fields[day] + - (getFirstDayOfWeek() - 1)); + maxWeeks = (days - 1 + mod) / 7 + 1; + newWeek = mod(fields[field] - 1 + value, maxWeeks) + 1; + if (newWeek == maxWeeks) { + if (fields[day] + (newWeek - fields[field]) * 7 > days) { + set(day, days); + } else { + set(field, newWeek); + } + } else if (newWeek == 1) { + int week = (fields[day] - ((fields[day] - 1) / 7 * 7) - 1 + mod) / 7 + 1; + if (week > 1) { + set(day, 1); + } else { + set(field, newWeek); + } + } else { + set(field, newWeek); + } + break; + case DATE: + max = daysInMonth(); + break; + case DAY_OF_YEAR: + max = daysInYear(fields[YEAR]); + break; + case DAY_OF_WEEK: + max = maximums[field]; + lastDateFieldSet = WEEK_OF_MONTH; + break; + case DAY_OF_WEEK_IN_MONTH: + max = (fields[DATE] + ((daysInMonth() - fields[DATE]) / 7 * 7) - 1) / 7 + 1; + break; + + case ERA: + case MONTH: + case AM_PM: + case HOUR: + case HOUR_OF_DAY: + case MINUTE: + case SECOND: + case MILLISECOND: + set(field, mod(fields[field] + value, maximums[field] + 1)); + if (field == MONTH && fields[DATE] > daysInMonth()) { + set(DATE, daysInMonth()); + } else if (field == AM_PM) { + lastTimeFieldSet = HOUR; + } + break; + } + if (max != -1) { + set(field, mod(fields[field] - 1 + value, max) + 1); + } + complete(); + } + + /** + * Increments or decrements the specified field and wraps the value of the + * field when it goes beyond the maximum or minimum value for the current + * date. Other fields will be adjusted as required to maintain a consistent + * date. For example, March 31 will roll to April 30 when rolling the month + * field. + * + * @param field + * the field to roll. + * @param increment + * {@code true} to increment the field, {@code false} to + * decrement. + * @throws IllegalArgumentException + * if an invalid field is specified. + */ + @Override + public void roll(int field, boolean increment) { + roll(field, increment ? 1 : -1); + } + + /** + * Sets the gregorian change date of this calendar. + * + * @param date + * a {@code Date} which represents the gregorian change date. + */ + public void setGregorianChange(Date date) { + gregorianCutover = date.getTime(); + GregorianCalendar cal = new GregorianCalendar(TimeZone.GMT); + cal.setTime(date); + changeYear = cal.get(YEAR); + if (cal.get(ERA) == BC) { + changeYear = 1 - changeYear; + } + julianSkew = ((changeYear - 2000) / 400) + julianError() + - ((changeYear - 2000) / 100); + isCached = false; + int dayOfYear = cal.get(DAY_OF_YEAR); + if (dayOfYear < julianSkew) { + currentYearSkew = dayOfYear-1; + lastYearSkew = julianSkew - dayOfYear + 1; + } else { + lastYearSkew = 0; + currentYearSkew = julianSkew; + } + isCached = false; + } + + private void writeObject(ObjectOutputStream stream) throws IOException { + stream.defaultWriteObject(); + } + + private void readObject(ObjectInputStream stream) throws IOException, + ClassNotFoundException { + + stream.defaultReadObject(); + setGregorianChange(new Date(gregorianCutover)); + isCached = false; + } + + @Override + public void setFirstDayOfWeek(int value) { + super.setFirstDayOfWeek(value); + isCached = false; + } + + @Override + public void setMinimalDaysInFirstWeek(int value) { + super.setMinimalDaysInFirstWeek(value); + isCached = false; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java new file mode 100644 index 000000000..98a7f288e --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java @@ -0,0 +1,873 @@ +/* + * 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.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.apache.harmony.luni.internal.nls.Messages; + +/** + * {@code SimpleTimeZone} is a concrete subclass of {@code TimeZone} + * that represents a time zone for use with a Gregorian calendar. This class + * does not handle historical changes. + *

+ * Use a negative value for {@code dayOfWeekInMonth} to indicate that + * {@code SimpleTimeZone} should count from the end of the month + * backwards. For example, Daylight Savings Time ends at the last + * (dayOfWeekInMonth = -1) Sunday in October, at 2 AM in standard time. + * + * @see Calendar + * @see GregorianCalendar + * @see TimeZone + */ +public class SimpleTimeZone extends TimeZone { + + private static final long serialVersionUID = -403250971215465050L; + + private int rawOffset; + + private int startYear, startMonth, startDay, startDayOfWeek, startTime; + + private int endMonth, endDay, endDayOfWeek, endTime; + + private int startMode, endMode; + + private static final int DOM_MODE = 1, DOW_IN_MONTH_MODE = 2, + DOW_GE_DOM_MODE = 3, DOW_LE_DOM_MODE = 4; + + /** + * The constant for representing a start or end time in GMT time mode. + */ + public static final int UTC_TIME = 2; + + /** + * The constant for representing a start or end time in standard local time mode, + * based on timezone's raw offset from GMT; does not include Daylight + * savings. + */ + public static final int STANDARD_TIME = 1; + + /** + * The constant for representing a start or end time in local wall clock time + * mode, based on timezone's adjusted offset from GMT; includes + * Daylight savings. + */ + public static final int WALL_TIME = 0; + + private boolean useDaylight; + + private GregorianCalendar daylightSavings; + + private int dstSavings = 3600000; + + private final transient com.ibm.icu.util.TimeZone icuTZ; + + private final transient boolean isSimple; + + /** + * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT + * and time zone ID. Timezone IDs can be obtained from + * {@code TimeZone.getAvailableIDs}. Normally you should use {@code TimeZone.getDefault} to + * construct a {@code TimeZone}. + * + * @param offset + * the given base time zone offset to GMT. + * @param name + * the time zone ID which is obtained from + * {@code TimeZone.getAvailableIDs}. + */ + public SimpleTimeZone(int offset, final String name) { + setID(name); + rawOffset = offset; + icuTZ = getICUTimeZone(name); + if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) { + isSimple = true; + icuTZ.setRawOffset(offset); + } else { + isSimple = false; + } + useDaylight = icuTZ.useDaylightTime(); + } + + /** + * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT, + * time zone ID, and times to start and end the daylight savings time. Timezone IDs can + * be obtained from {@code TimeZone.getAvailableIDs}. Normally you should use + * {@code TimeZone.getDefault} to create a {@code TimeZone}. For a time zone that does not + * use daylight saving time, do not use this constructor; instead you should + * use {@code SimpleTimeZone(rawOffset, ID)}. + *

+ * By default, this constructor specifies day-of-week-in-month rules. That + * is, if the {@code startDay} is 1, and the {@code startDayOfWeek} is {@code SUNDAY}, then this + * indicates the first Sunday in the {@code startMonth}. A {@code startDay} of -1 likewise + * indicates the last Sunday. However, by using negative or zero values for + * certain parameters, other types of rules can be specified. + *

+ * Day of month: To specify an exact day of the month, such as March 1, set + * {@code startDayOfWeek} to zero. + *

+ * Day of week after day of month: To specify the first day of the week + * occurring on or after an exact day of the month, make the day of the week + * negative. For example, if {@code startDay} is 5 and {@code startDayOfWeek} is {@code -MONDAY}, + * this indicates the first Monday on or after the 5th day of the + * {@code startMonth}. + *

+ * Day of week before day of month: To specify the last day of the week + * occurring on or before an exact day of the month, make the day of the + * week and the day of the month negative. For example, if {@code startDay} is {@code -21} + * and {@code startDayOfWeek} is {@code -WEDNESDAY}, this indicates the last Wednesday on or + * before the 21st of the {@code startMonth}. + *

+ * The above examples refer to the {@code startMonth}, {@code startDay}, and {@code startDayOfWeek}; + * the same applies for the {@code endMonth}, {@code endDay}, and {@code endDayOfWeek}. + *

+ * The daylight savings time difference is set to the default value: one hour. + * + * @param offset + * the given base time zone offset to GMT. + * @param name + * the time zone ID which is obtained from + * {@code TimeZone.getAvailableIDs}. + * @param startMonth + * the daylight savings starting month. The month indexing is 0-based. eg, 0 + * for January. + * @param startDay + * the daylight savings starting day-of-week-in-month. Please see + * the member description for an example. + * @param startDayOfWeek + * the daylight savings starting day-of-week. Please see the + * member description for an example. + * @param startTime + * the daylight savings starting time in local wall time, which + * is standard time in this case. Please see the member + * description for an example. + * @param endMonth + * the daylight savings ending month. The month indexing is 0-based. eg, 0 for + * January. + * @param endDay + * the daylight savings ending day-of-week-in-month. Please see + * the member description for an example. + * @param endDayOfWeek + * the daylight savings ending day-of-week. Please see the member + * description for an example. + * @param endTime + * the daylight savings ending time in local wall time, which is + * daylight time in this case. Please see the member description + * for an example. + * @throws IllegalArgumentException + * if the month, day, dayOfWeek, or time parameters are out of + * range for the start or end rule. + */ + public SimpleTimeZone(int offset, String name, int startMonth, + int startDay, int startDayOfWeek, int startTime, int endMonth, + int endDay, int endDayOfWeek, int endTime) { + this(offset, name, startMonth, startDay, startDayOfWeek, startTime, + endMonth, endDay, endDayOfWeek, endTime, 3600000); + } + + /** + * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT, + * time zone ID, times to start and end the daylight savings time, and + * the daylight savings time difference in milliseconds. + * + * @param offset + * the given base time zone offset to GMT. + * @param name + * the time zone ID which is obtained from + * {@code TimeZone.getAvailableIDs}. + * @param startMonth + * the daylight savings starting month. Month is 0-based. eg, 0 + * for January. + * @param startDay + * the daylight savings starting day-of-week-in-month. Please see + * the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. + * @param startDayOfWeek + * the daylight savings starting day-of-week. Please see the + * description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. + * @param startTime + * The daylight savings starting time in local wall time, which + * is standard time in this case. Please see the description of + * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. + * @param endMonth + * the daylight savings ending month. Month is 0-based. eg, 0 for + * January. + * @param endDay + * the daylight savings ending day-of-week-in-month. Please see + * the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. + * @param endDayOfWeek + * the daylight savings ending day-of-week. Please see the description of + * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. + * @param endTime + * the daylight savings ending time in local wall time, which is + * daylight time in this case. Please see the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} + * for an example. + * @param daylightSavings + * the daylight savings time difference in milliseconds. + * @throws IllegalArgumentException + * if the month, day, dayOfWeek, or time parameters are out of + * range for the start or end rule. + */ + public SimpleTimeZone(int offset, String name, int startMonth, + int startDay, int startDayOfWeek, int startTime, int endMonth, + int endDay, int endDayOfWeek, int endTime, int daylightSavings) { + icuTZ = getICUTimeZone(name); + if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) { + isSimple = true; + com.ibm.icu.util.SimpleTimeZone tz = (com.ibm.icu.util.SimpleTimeZone)icuTZ; + tz.setRawOffset(offset); + tz.setStartRule(startMonth, startDay, startDayOfWeek, startTime); + tz.setEndRule(endMonth, endDay, endDayOfWeek, endTime); + tz.setDSTSavings(daylightSavings); + } else { + isSimple = false; + } + setID(name); + rawOffset = offset; + if (daylightSavings <= 0) { + throw new IllegalArgumentException(Messages.getString( + "luni.3B", daylightSavings)); //$NON-NLS-1$ + } + dstSavings = daylightSavings; + + setStartRule(startMonth, startDay, startDayOfWeek, startTime); + setEndRule(endMonth, endDay, endDayOfWeek, endTime); + + useDaylight = daylightSavings > 0 || icuTZ.useDaylightTime(); + } + + /** + * Construct a {@code SimpleTimeZone} with the given base time zone offset from GMT, + * time zone ID, times to start and end the daylight savings time including a + * mode specifier, the daylight savings time difference in milliseconds. + * The mode specifies either {@link #WALL_TIME}, {@link #STANDARD_TIME}, or + * {@link #UTC_TIME}. + * + * @param offset + * the given base time zone offset to GMT. + * @param name + * the time zone ID which is obtained from + * {@code TimeZone.getAvailableIDs}. + * @param startMonth + * the daylight savings starting month. The month indexing is 0-based. eg, 0 + * for January. + * @param startDay + * the daylight savings starting day-of-week-in-month. Please see + * the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. + * @param startDayOfWeek + * the daylight savings starting day-of-week. Please see the + * description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. + * @param startTime + * the time of day in milliseconds on which daylight savings + * time starts, based on the {@code startTimeMode}. + * @param startTimeMode + * the mode (UTC, standard, or wall time) of the start time + * value. + * @param endDay + * the day of the week on which daylight savings time ends. + * @param endMonth + * the daylight savings ending month. The month indexing is 0-based. eg, 0 for + * January. + * @param endDayOfWeek + * the daylight savings ending day-of-week. Please see the description of + * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. + * @param endTime + * the time of day in milliseconds on which daylight savings + * time ends, based on the {@code endTimeMode}. + * @param endTimeMode + * the mode (UTC, standard, or wall time) of the end time value. + * @param daylightSavings + * the daylight savings time difference in milliseconds. + * @throws IllegalArgumentException + * if the month, day, dayOfWeek, or time parameters are out of + * range for the start or end rule. + */ + public SimpleTimeZone(int offset, String name, int startMonth, + int startDay, int startDayOfWeek, int startTime, int startTimeMode, + int endMonth, int endDay, int endDayOfWeek, int endTime, + int endTimeMode, int daylightSavings) { + + this(offset, name, startMonth, startDay, startDayOfWeek, startTime, + endMonth, endDay, endDayOfWeek, endTime, daylightSavings); + startMode = startTimeMode; + endMode = endTimeMode; + } + + /** + * Returns a new {@code SimpleTimeZone} with the same ID, {@code rawOffset} and daylight + * savings time rules as this SimpleTimeZone. + * + * @return a shallow copy of this {@code SimpleTimeZone}. + * @see java.lang.Cloneable + */ + @Override + public Object clone() { + SimpleTimeZone zone = (SimpleTimeZone) super.clone(); + if (daylightSavings != null) { + zone.daylightSavings = (GregorianCalendar) daylightSavings.clone(); + } + return zone; + } + + /** + * Compares the specified object to this {@code SimpleTimeZone} and returns whether they + * are equal. The object must be an instance of {@code SimpleTimeZone} and have the + * same internal data. + * + * @param object + * the object to compare with this object. + * @return {@code true} if the specified object is equal to this + * {@code SimpleTimeZone}, {@code false} otherwise. + * @see #hashCode + */ + @Override + public boolean equals(Object object) { + if (!(object instanceof SimpleTimeZone)) { + return false; + } + SimpleTimeZone tz = (SimpleTimeZone) object; + return getID().equals(tz.getID()) + && rawOffset == tz.rawOffset + && useDaylight == tz.useDaylight + && (!useDaylight || (startYear == tz.startYear + && startMonth == tz.startMonth + && startDay == tz.startDay && startMode == tz.startMode + && startDayOfWeek == tz.startDayOfWeek + && startTime == tz.startTime && endMonth == tz.endMonth + && endDay == tz.endDay + && endDayOfWeek == tz.endDayOfWeek + && endTime == tz.endTime && endMode == tz.endMode && dstSavings == tz.dstSavings)); + } + + @Override + public int getDSTSavings() { + if (!useDaylight) { + return 0; + } + return dstSavings; + } + + @Override + public int getOffset(int era, int year, int month, int day, int dayOfWeek, + int time) { + if (era != GregorianCalendar.BC && era != GregorianCalendar.AD) { + throw new IllegalArgumentException(Messages.getString("luni.3C", era)); //$NON-NLS-1$ + } + checkRange(month, dayOfWeek, time); + if (month != Calendar.FEBRUARY || day != 29 || !isLeapYear(year)) { + checkDay(month, day); + } + return icuTZ.getOffset(era, year, month, day, dayOfWeek, time); + } + + @Override + public int getOffset(long time) { + return icuTZ.getOffset(time); + } + + @Override + public int getRawOffset() { + return rawOffset; + } + + /** + * Returns an integer hash code for the receiver. Objects which are equal + * return the same value for this method. + * + * @return the receiver's hash. + * @see #equals + */ + @Override + public synchronized int hashCode() { + int hashCode = getID().hashCode() + rawOffset; + if (useDaylight) { + hashCode += startYear + startMonth + startDay + startDayOfWeek + + startTime + startMode + endMonth + endDay + endDayOfWeek + + endTime + endMode + dstSavings; + } + return hashCode; + } + + @Override + public boolean hasSameRules(TimeZone zone) { + if (!(zone instanceof SimpleTimeZone)) { + return false; + } + SimpleTimeZone tz = (SimpleTimeZone) zone; + if (useDaylight != tz.useDaylight) { + return false; + } + if (!useDaylight) { + return rawOffset == tz.rawOffset; + } + return rawOffset == tz.rawOffset && dstSavings == tz.dstSavings + && startYear == tz.startYear && startMonth == tz.startMonth + && startDay == tz.startDay && startMode == tz.startMode + && startDayOfWeek == tz.startDayOfWeek + && startTime == tz.startTime && endMonth == tz.endMonth + && endDay == tz.endDay && endDayOfWeek == tz.endDayOfWeek + && endTime == tz.endTime && endMode == tz.endMode; + } + + @Override + public boolean inDaylightTime(Date time) { + return icuTZ.inDaylightTime(time); + } + + private boolean isLeapYear(int year) { + if (year > 1582) { + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); + } + return year % 4 == 0; + } + + /** + * Sets the daylight savings offset in milliseconds for this {@code SimpleTimeZone}. + * + * @param milliseconds + * the daylight savings offset in milliseconds. + */ + public void setDSTSavings(int milliseconds) { + if (milliseconds > 0) { + dstSavings = milliseconds; + } else { + throw new IllegalArgumentException(); + } + } + + private void checkRange(int month, int dayOfWeek, int time) { + if (month < Calendar.JANUARY || month > Calendar.DECEMBER) { + throw new IllegalArgumentException(Messages.getString("luni.3D", month)); //$NON-NLS-1$ + } + if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) { + throw new IllegalArgumentException(Messages + .getString("luni.48", dayOfWeek)); //$NON-NLS-1$ + } + if (time < 0 || time >= 24 * 3600000) { + throw new IllegalArgumentException(Messages.getString("luni.3E", time)); //$NON-NLS-1$ + } + } + + private void checkDay(int month, int day) { + if (day <= 0 || day > GregorianCalendar.DaysInMonth[month]) { + throw new IllegalArgumentException(Messages.getString("luni.3F", day)); //$NON-NLS-1$ + } + } + + private void setEndMode() { + if (endDayOfWeek == 0) { + endMode = DOM_MODE; + } else if (endDayOfWeek < 0) { + endDayOfWeek = -endDayOfWeek; + if (endDay < 0) { + endDay = -endDay; + endMode = DOW_LE_DOM_MODE; + } else { + endMode = DOW_GE_DOM_MODE; + } + } else { + endMode = DOW_IN_MONTH_MODE; + } + useDaylight = startDay != 0 && endDay != 0; + if (endDay != 0) { + checkRange(endMonth, endMode == DOM_MODE ? 1 : endDayOfWeek, + endTime); + if (endMode != DOW_IN_MONTH_MODE) { + checkDay(endMonth, endDay); + } else { + if (endDay < -5 || endDay > 5) { + throw new IllegalArgumentException(Messages.getString( + "luni.40", endDay)); //$NON-NLS-1$ + } + } + } + if (endMode != DOM_MODE) { + endDayOfWeek--; + } + } + + /** + * Sets the rule which specifies the end of daylight savings time. + * + * @param month + * the {@code Calendar} month in which daylight savings time ends. + * @param dayOfMonth + * the {@code Calendar} day of the month on which daylight savings time + * ends. + * @param time + * the time of day in milliseconds standard time on which + * daylight savings time ends. + */ + public void setEndRule(int month, int dayOfMonth, int time) { + endMonth = month; + endDay = dayOfMonth; + endDayOfWeek = 0; // Initialize this value for hasSameRules() + endTime = time; + setEndMode(); + if (isSimple) { + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, + dayOfMonth, time); + } + } + + /** + * Sets the rule which specifies the end of daylight savings time. + * + * @param month + * the {@code Calendar} month in which daylight savings time ends. + * @param day + * the occurrence of the day of the week on which daylight + * savings time ends. + * @param dayOfWeek + * the {@code Calendar} day of the week on which daylight savings time + * ends. + * @param time + * the time of day in milliseconds standard time on which + * daylight savings time ends. + */ + public void setEndRule(int month, int day, int dayOfWeek, int time) { + endMonth = month; + endDay = day; + endDayOfWeek = dayOfWeek; + endTime = time; + setEndMode(); + if (isSimple) { + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, + dayOfWeek, time); + } + } + + /** + * Sets the rule which specifies the end of daylight savings time. + * + * @param month + * the {@code Calendar} month in which daylight savings time ends. + * @param day + * the {@code Calendar} day of the month. + * @param dayOfWeek + * the {@code Calendar} day of the week on which daylight savings time + * ends. + * @param time + * the time of day in milliseconds on which daylight savings time + * ends. + * @param after + * selects the day after or before the day of month. + */ + public void setEndRule(int month, int day, int dayOfWeek, int time, + boolean after) { + endMonth = month; + endDay = after ? day : -day; + endDayOfWeek = -dayOfWeek; + endTime = time; + setEndMode(); + if (isSimple) { + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, + dayOfWeek, time, after); + } + } + + /** + * Sets the offset for standard time from GMT for this {@code SimpleTimeZone}. + * + * @param offset + * the offset from GMT of standard time in milliseconds. + */ + @Override + public void setRawOffset(int offset) { + rawOffset = offset; + icuTZ.setRawOffset(offset); + } + + private void setStartMode() { + if (startDayOfWeek == 0) { + startMode = DOM_MODE; + } else if (startDayOfWeek < 0) { + startDayOfWeek = -startDayOfWeek; + if (startDay < 0) { + startDay = -startDay; + startMode = DOW_LE_DOM_MODE; + } else { + startMode = DOW_GE_DOM_MODE; + } + } else { + startMode = DOW_IN_MONTH_MODE; + } + useDaylight = startDay != 0 && endDay != 0; + if (startDay != 0) { + checkRange(startMonth, startMode == DOM_MODE ? 1 : startDayOfWeek, + startTime); + if (startMode != DOW_IN_MONTH_MODE) { + checkDay(startMonth, startDay); + } else { + if (startDay < -5 || startDay > 5) { + throw new IllegalArgumentException(Messages.getString( + "luni.40", startDay)); //$NON-NLS-1$ + } + } + } + if (startMode != DOM_MODE) { + startDayOfWeek--; + } + } + + /** + * Sets the rule which specifies the start of daylight savings time. + * + * @param month + * the {@code Calendar} month in which daylight savings time starts. + * @param dayOfMonth + * the {@code Calendar} day of the month on which daylight savings time + * starts. + * @param time + * the time of day in milliseconds on which daylight savings time + * starts. + */ + public void setStartRule(int month, int dayOfMonth, int time) { + startMonth = month; + startDay = dayOfMonth; + startDayOfWeek = 0; // Initialize this value for hasSameRules() + startTime = time; + setStartMode(); + if (isSimple) { + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, + dayOfMonth, time); + } + } + + /** + * Sets the rule which specifies the start of daylight savings time. + * + * @param month + * the {@code Calendar} month in which daylight savings time starts. + * @param day + * the occurrence of the day of the week on which daylight + * savings time starts. + * @param dayOfWeek + * the {@code Calendar} day of the week on which daylight savings time + * starts. + * @param time + * the time of day in milliseconds on which daylight savings time + * starts. + */ + public void setStartRule(int month, int day, int dayOfWeek, int time) { + startMonth = month; + startDay = day; + startDayOfWeek = dayOfWeek; + startTime = time; + setStartMode(); + if (isSimple) { + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, + dayOfWeek, time); + } + } + + /** + * Sets the rule which specifies the start of daylight savings time. + * + * @param month + * the {@code Calendar} month in which daylight savings time starts. + * @param day + * the {@code Calendar} day of the month. + * @param dayOfWeek + * the {@code Calendar} day of the week on which daylight savings time + * starts. + * @param time + * the time of day in milliseconds on which daylight savings time + * starts. + * @param after + * selects the day after or before the day of month. + */ + public void setStartRule(int month, int day, int dayOfWeek, int time, + boolean after) { + startMonth = month; + startDay = after ? day : -day; + startDayOfWeek = -dayOfWeek; + startTime = time; + setStartMode(); + if (isSimple) { + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, + dayOfWeek, time, after); + } + } + + /** + * Sets the starting year for daylight savings time in this {@code SimpleTimeZone}. + * Years before this start year will always be in standard time. + * + * @param year + * the starting year. + */ + public void setStartYear(int year) { + startYear = year; + useDaylight = true; + } + + /** + * Returns the string representation of this {@code SimpleTimeZone}. + * + * @return the string representation of this {@code SimpleTimeZone}. + */ + @Override + public String toString() { + return getClass().getName() + + "[id=" //$NON-NLS-1$ + + getID() + + ",offset=" //$NON-NLS-1$ + + rawOffset + + ",dstSavings=" //$NON-NLS-1$ + + dstSavings + + ",useDaylight=" //$NON-NLS-1$ + + useDaylight + + ",startYear=" //$NON-NLS-1$ + + startYear + + ",startMode=" //$NON-NLS-1$ + + startMode + + ",startMonth=" //$NON-NLS-1$ + + startMonth + + ",startDay=" //$NON-NLS-1$ + + startDay + + ",startDayOfWeek=" //$NON-NLS-1$ + + (useDaylight && (startMode != DOM_MODE) ? startDayOfWeek + 1 + : 0) + ",startTime=" + startTime + ",endMode=" //$NON-NLS-1$ //$NON-NLS-2$ + + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay //$NON-NLS-1$ //$NON-NLS-2$ + + ",endDayOfWeek=" //$NON-NLS-1$ + + (useDaylight && (endMode != DOM_MODE) ? endDayOfWeek + 1 : 0) + + ",endTime=" + endTime + "]"; //$NON-NLS-1$//$NON-NLS-2$ + } + + @Override + public boolean useDaylightTime() { + return useDaylight; + } + + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("dstSavings", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("endDay", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("endDayOfWeek", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("endMode", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("endMonth", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("endTime", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("monthLength", byte[].class), //$NON-NLS-1$ + new ObjectStreamField("rawOffset", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("serialVersionOnStream", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("startDay", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("startDayOfWeek", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("startMode", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("startMonth", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("startTime", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("startYear", Integer.TYPE), //$NON-NLS-1$ + new ObjectStreamField("useDaylight", Boolean.TYPE), }; //$NON-NLS-1$ + + private void writeObject(ObjectOutputStream stream) throws IOException { + int sEndDay = endDay, sEndDayOfWeek = endDayOfWeek + 1, sStartDay = startDay, sStartDayOfWeek = startDayOfWeek + 1; + if (useDaylight + && (startMode != DOW_IN_MONTH_MODE || endMode != DOW_IN_MONTH_MODE)) { + Calendar cal = new GregorianCalendar(this); + if (endMode != DOW_IN_MONTH_MODE) { + cal.set(Calendar.MONTH, endMonth); + cal.set(Calendar.DATE, endDay); + sEndDay = cal.get(Calendar.DAY_OF_WEEK_IN_MONTH); + if (endMode == DOM_MODE) { + sEndDayOfWeek = cal.getFirstDayOfWeek(); + } + } + if (startMode != DOW_IN_MONTH_MODE) { + cal.set(Calendar.MONTH, startMonth); + cal.set(Calendar.DATE, startDay); + sStartDay = cal.get(Calendar.DAY_OF_WEEK_IN_MONTH); + if (startMode == DOM_MODE) { + sStartDayOfWeek = cal.getFirstDayOfWeek(); + } + } + } + ObjectOutputStream.PutField fields = stream.putFields(); + fields.put("dstSavings", dstSavings); //$NON-NLS-1$ + fields.put("endDay", sEndDay); //$NON-NLS-1$ + fields.put("endDayOfWeek", sEndDayOfWeek); //$NON-NLS-1$ + fields.put("endMode", endMode); //$NON-NLS-1$ + fields.put("endMonth", endMonth); //$NON-NLS-1$ + fields.put("endTime", endTime); //$NON-NLS-1$ + fields.put("monthLength", GregorianCalendar.DaysInMonth); //$NON-NLS-1$ + fields.put("rawOffset", rawOffset); //$NON-NLS-1$ + fields.put("serialVersionOnStream", 1); //$NON-NLS-1$ + fields.put("startDay", sStartDay); //$NON-NLS-1$ + fields.put("startDayOfWeek", sStartDayOfWeek); //$NON-NLS-1$ + fields.put("startMode", startMode); //$NON-NLS-1$ + fields.put("startMonth", startMonth); //$NON-NLS-1$ + fields.put("startTime", startTime); //$NON-NLS-1$ + fields.put("startYear", startYear); //$NON-NLS-1$ + fields.put("useDaylight", useDaylight); //$NON-NLS-1$ + stream.writeFields(); + stream.writeInt(4); + byte[] values = new byte[4]; + values[0] = (byte) startDay; + values[1] = (byte) (startMode == DOM_MODE ? 0 : startDayOfWeek + 1); + values[2] = (byte) endDay; + values[3] = (byte) (endMode == DOM_MODE ? 0 : endDayOfWeek + 1); + stream.write(values); + } + + private void readObject(ObjectInputStream stream) throws IOException, + ClassNotFoundException { + ObjectInputStream.GetField fields = stream.readFields(); + rawOffset = fields.get("rawOffset", 0); //$NON-NLS-1$ + useDaylight = fields.get("useDaylight", false); //$NON-NLS-1$ + if (useDaylight) { + endMonth = fields.get("endMonth", 0); //$NON-NLS-1$ + endTime = fields.get("endTime", 0); //$NON-NLS-1$ + startMonth = fields.get("startMonth", 0); //$NON-NLS-1$ + startTime = fields.get("startTime", 0); //$NON-NLS-1$ + startYear = fields.get("startYear", 0); //$NON-NLS-1$ + } + if (fields.get("serialVersionOnStream", 0) == 0) { //$NON-NLS-1$ + if (useDaylight) { + startMode = endMode = DOW_IN_MONTH_MODE; + endDay = fields.get("endDay", 0); //$NON-NLS-1$ + endDayOfWeek = fields.get("endDayOfWeek", 0) - 1; //$NON-NLS-1$ + startDay = fields.get("startDay", 0); //$NON-NLS-1$ + startDayOfWeek = fields.get("startDayOfWeek", 0) - 1; //$NON-NLS-1$ + } + } else { + dstSavings = fields.get("dstSavings", 0); //$NON-NLS-1$ + if (useDaylight) { + endMode = fields.get("endMode", 0); //$NON-NLS-1$ + startMode = fields.get("startMode", 0); //$NON-NLS-1$ + int length = stream.readInt(); + byte[] values = new byte[length]; + stream.readFully(values); + if (length >= 4) { + startDay = values[0]; + startDayOfWeek = values[1]; + if (startMode != DOM_MODE) { + startDayOfWeek--; + } + endDay = values[2]; + endDayOfWeek = values[3]; + if (endMode != DOM_MODE) { + endDayOfWeek--; + } + } + } + } + } + +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java new file mode 100644 index 000000000..c5691e1a9 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java @@ -0,0 +1,509 @@ +/* + * Copyright 2014 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. + */ +/* + * 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.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TCloneable; + +public abstract class TimeZone implements TSerializable, TCloneable { + 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 THashMap AvailableZones; + + private static TimeZone Default; + + static TimeZone GMT = new SimpleTimeZone(0, "GMT"); // Greenwich Mean Time + + private String ID; + + private static void initializeAvailable() { + TimeZone[] zones = TimeZones.getTimeZones(); + AvailableZones = new THashMap<>((zones.length + 1) * 4 / 3); + AvailableZones.put(GMT.getID(), GMT); + for (int i = 0; i < zones.length; i++) { + AvailableZones.put(zones[i].getID(), zones[i]); + } + } + + public TimeZone() { + } + + @Override + public Object clone() { + try { + TimeZone zone = (TimeZone) super.clone(); + return zone; + } catch (CloneNotSupportedException e) { + return null; + } + } + + public static synchronized String[] getAvailableIDs() { + return AvailableZones.keySet().toArray(new String[0]); + } + + public static synchronized String[] getAvailableIDs(int offset) { + List result = new ArrayList<>(); + for (TIterator iter = AvailableZones.values().iterator(); iter.hasNext()) { + if () + } + return Arrays.copyOf(result, j); + int count = 0; + int length = availableIDs.length; + String[] all = new String[length]; + for (int i = 0; i < length; i++) { + if (tz.getRawOffset() == offset) { + all[count++] = tz.getID(); + } + } + String[] answer = new String[count]; + System.arraycopy(all, 0, answer, 0, count); + return answer; + } + + /** + * Gets the default time zone. + * + * @return the default time zone. + */ + public static synchronized TimeZone getDefault() { + if (Default == null) { + setDefault(null); + } + return (TimeZone) 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, Locale.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(Locale 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, Locale.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, Locale locale) { + if(icuTimeZone == null || !ID.equals(icuTimeZone.getID())){ + icuTimeZone = com.ibm.icu.util.TimeZone.getTimeZone(ID); + } + return icuTimeZone.getDisplayName( + daylightTime, style, locale); + } + + /** + * 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) { + if (inDaylightTime(new Date(time))) { + return getRawOffset() + getDSTSavings(); + } + return 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 synchronized TimeZone getTimeZone(String name) { + if (AvailableZones == null) { + initializeAvailable(); + } + + TimeZone zone = AvailableZones.get(name); + if(zone == null && isAvailableIDInICU(name)){ + appendAvailableZones(name); + zone = AvailableZones.get(name); + } + if (zone == null) { + 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 (TimeZone) 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 (TimeZone) GMT.clone(); + } + raw += minute * 60000; + } else if (hour >= 30 || index > 6) { + raw = (hour / 100 * 3600000) + (hour % 100 * 60000); + } + if (sign == '-') { + raw = -raw; + } + return new SimpleTimeZone(raw, formattedName); + } + } + } + zone = GMT; + } + return (TimeZone) zone.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(TimeZone 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(Date 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 synchronized void setDefault(TimeZone timezone) { + if (timezone != null) { + setICUDefaultTimeZone(timezone); + Default = timezone; + return; + } + + String zone = AccessController.doPrivileged(new PriviAction( + "user.timezone")); + + // sometimes DRLVM incorrectly adds "\n" to the end of timezone ID + if (zone != null && zone.contains("\n")) { + zone = zone.substring(0, zone.indexOf("\n")); + } + + // if property user.timezone is not set, we call the native method + // getCustomTimeZone + if (zone == null || zone.length() == 0) { + int[] tzinfo = new int[10]; + boolean[] isCustomTimeZone = new boolean[1]; + + String zoneId = getCustomTimeZone(tzinfo, isCustomTimeZone); + + // if returned TimeZone is a user customized TimeZone + if (isCustomTimeZone[0]) { + // build a new SimpleTimeZone + switch (tzinfo[1]) { + case 0: + // does not observe DST + Default = new SimpleTimeZone(tzinfo[0], zoneId); + break; + default: + // observes DST + Default = new SimpleTimeZone(tzinfo[0], zoneId, tzinfo[5], + tzinfo[4], tzinfo[3], tzinfo[2], tzinfo[9], + tzinfo[8], tzinfo[7], tzinfo[6], tzinfo[1]); + } + } else { + // get TimeZone + Default = getTimeZone(zoneId); + } + } else { + // if property user.timezone is set in command line (with -D option) + Default = getTimeZone(zone); + } + setICUDefaultTimeZone(Default); + } + + private static void setICUDefaultTimeZone(TimeZone timezone) { + final com.ibm.icu.util.TimeZone icuTZ = com.ibm.icu.util.TimeZone + .getTimeZone(timezone.getID()); + + AccessController + .doPrivileged(new PrivilegedAction() { + public java.lang.reflect.Field run() { + java.lang.reflect.Field field = null; + try { + field = com.ibm.icu.util.TimeZone.class + .getDeclaredField("defaultZone"); + field.setAccessible(true); + field.set("defaultZone", icuTZ); + } catch (Exception e) { + return null; + } + return field; + } + }); + } + + /** + * 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-classlib/src/main/java/org/teavm/classlib/java/util/TimeZones.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZones.java new file mode 100644 index 000000000..f9e70f561 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZones.java @@ -0,0 +1,707 @@ +/* + * Copyright 2014 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. + */ +/* + * 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; + +final class TimeZones { + + private static final int HALF_HOUR = 1800000; + private static final int ONE_HOUR = HALF_HOUR * 2; + + public static TimeZone[] getTimeZones() { + return new TimeZone[] { + new SimpleTimeZone(-11 * ONE_HOUR, "MIT"), //$NON-NLS-1$ + new SimpleTimeZone(-10 * ONE_HOUR, "HST"), //$NON-NLS-1$ + new SimpleTimeZone(-9 * ONE_HOUR, "AST", Calendar.APRIL, 1, //$NON-NLS-1$ + -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-8 * ONE_HOUR, "PST", Calendar.APRIL, 1, //$NON-NLS-1$ + -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-7 * ONE_HOUR, "MST", Calendar.APRIL, 1, //$NON-NLS-1$ + -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-7 * ONE_HOUR, "PNT"), //$NON-NLS-1$ + new SimpleTimeZone(-6 * ONE_HOUR, "CST", Calendar.APRIL, 1, //$NON-NLS-1$ + -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-5 * ONE_HOUR, "EST", Calendar.APRIL, 1, //$NON-NLS-1$ + -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-5 * ONE_HOUR, "IET"), //$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "PRT"), //$NON-NLS-1$ + new SimpleTimeZone(-3 * ONE_HOUR - 1800000, + "CNT", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 60000, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 60000), + new SimpleTimeZone(-3 * ONE_HOUR, "AGT"), //$NON-NLS-1$ + new SimpleTimeZone(-3 * ONE_HOUR, "BET", Calendar.OCTOBER, 8, //$NON-NLS-1$ + -Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.FEBRUARY, 15, + -Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(0 * ONE_HOUR, "UTC"), //$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "WET", Calendar.MARCH, -1, //$NON-NLS-1$ + Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, "ECT", Calendar.MARCH, -1, //$NON-NLS-1$ + Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, "MET", Calendar.MARCH, 21, 0, //$NON-NLS-1$ + 0 * ONE_HOUR, Calendar.SEPTEMBER, 23, 0, 0 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, "ART", Calendar.APRIL, -1, //$NON-NLS-1$ + Calendar.FRIDAY, 0 * ONE_HOUR, Calendar.SEPTEMBER, -1, + Calendar.THURSDAY, 23 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, "CAT"), //$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "EET", Calendar.MARCH, -1, //$NON-NLS-1$ + Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(3 * ONE_HOUR, "EAT"), //$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR + 1800000, + "Asia/Tehran", //$NON-NLS-1$ + Calendar.MARCH, 21, 0, 0 * ONE_HOUR, + Calendar.SEPTEMBER, 23, 0, 0 * ONE_HOUR), + new SimpleTimeZone(4 * ONE_HOUR, "NET", Calendar.MARCH, -1, //$NON-NLS-1$ + Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(5 * ONE_HOUR, "PLT"), //$NON-NLS-1$ + new SimpleTimeZone(5 * ONE_HOUR + 1800000, "IST"), //$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR, "BST"), //$NON-NLS-1$ + new SimpleTimeZone(7 * ONE_HOUR, "VST"), //$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "CTT"), //$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR, "JST"), //$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR + 1800000, "ACT"), //$NON-NLS-1$ + new SimpleTimeZone(10 * ONE_HOUR, "AET", Calendar.OCTOBER, -1, //$NON-NLS-1$ + Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(11 * ONE_HOUR, "SST"), //$NON-NLS-1$ + new SimpleTimeZone(12 * ONE_HOUR, "NST", Calendar.OCTOBER, 1, //$NON-NLS-1$ + -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, 15, + -Calendar.SUNDAY, 2 * ONE_HOUR), + + new SimpleTimeZone(-6 * ONE_HOUR, "America/Costa_Rica"), //$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, + "America/Halifax", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-2 * ONE_HOUR, "Atlantic/South_Georgia"), //$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, + "Europe/London", //$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Algiers"), //$NON-NLS-1$ + new SimpleTimeZone( + 2 * ONE_HOUR, + "Africa/Cairo", //$NON-NLS-1$ + Calendar.APRIL, -1, Calendar.FRIDAY, 0 * ONE_HOUR, + Calendar.SEPTEMBER, -1, Calendar.THURSDAY, + 23 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Harare"), //$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, + "Asia/Jerusalem", //$NON-NLS-1$ + Calendar.APRIL, 9, 0, 1 * ONE_HOUR, Calendar.SEPTEMBER, + 24, 0, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Bucharest", //$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(3 * ONE_HOUR, + "Europe/Moscow", //$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(4 * ONE_HOUR + 1800000, "Asia/Kabul"), //$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR + 1800000, + "Australia/Adelaide", Calendar.OCTOBER, -1, //$NON-NLS-1$ + Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(10 * ONE_HOUR, "Australia/Brisbane"), //$NON-NLS-1$ + new SimpleTimeZone(10 * ONE_HOUR, + "Australia/Hobart", //$NON-NLS-1$ + Calendar.OCTOBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + + new SimpleTimeZone(-9 * ONE_HOUR - 1800000, "Pacific/Marquesas"), //$NON-NLS-1$ + new SimpleTimeZone(-1 * ONE_HOUR, + "Atlantic/Azores", //$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(4 * ONE_HOUR, "Asia/Dubai"), //$NON-NLS-1$ + new SimpleTimeZone(20700000, "Asia/Katmandu"), //$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR + 1800000, "Asia/Rangoon"), //$NON-NLS-1$ + new SimpleTimeZone(45900000, + "Pacific/Chatham", //$NON-NLS-1$ + Calendar.OCTOBER, 1, -Calendar.SUNDAY, 9900000, + Calendar.MARCH, 15, -Calendar.SUNDAY, 9900000), + + new SimpleTimeZone(-11 * ONE_HOUR, "Pacific/Apia"), //$NON-NLS-1$ + new SimpleTimeZone(-11 * ONE_HOUR, "Pacific/Niue"), //$NON-NLS-1$ + new SimpleTimeZone(-11 * ONE_HOUR, "Pacific/Pago_Pago"), //$NON-NLS-1$ + new SimpleTimeZone(-10 * ONE_HOUR, + "America/Adak", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-10 * ONE_HOUR, "Pacific/Fakaofo"), //$NON-NLS-1$ + new SimpleTimeZone(-10 * ONE_HOUR, "Pacific/Honolulu"), //$NON-NLS-1$ + new SimpleTimeZone(-10 * ONE_HOUR, "Pacific/Rarotonga"), //$NON-NLS-1$ + new SimpleTimeZone(-10 * ONE_HOUR, "Pacific/Tahiti"), //$NON-NLS-1$ + new SimpleTimeZone(-9 * ONE_HOUR, + "America/Anchorage", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-9 * ONE_HOUR, "Pacific/Gambier"), //$NON-NLS-1$ + new SimpleTimeZone(-8 * ONE_HOUR, + "America/Los_Angeles", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-8 * ONE_HOUR, + "America/Tijuana", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-8 * ONE_HOUR, + "America/Vancouver", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-8 * ONE_HOUR, "Pacific/Pitcairn"), //$NON-NLS-1$ + new SimpleTimeZone(-7 * ONE_HOUR, "America/Dawson_Creek"), //$NON-NLS-1$ + new SimpleTimeZone(-7 * ONE_HOUR, + "America/Denver", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-7 * ONE_HOUR, + "America/Edmonton", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-7 * ONE_HOUR, + "America/Mazatlan", //$NON-NLS-1$ + Calendar.MAY, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.SEPTEMBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-7 * ONE_HOUR, "America/Phoenix"), //$NON-NLS-1$ + new SimpleTimeZone(-6 * ONE_HOUR, "America/Belize"), //$NON-NLS-1$ + new SimpleTimeZone(-6 * ONE_HOUR, + "America/Chicago", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-6 * ONE_HOUR, "America/El_Salvador"), //$NON-NLS-1$ + new SimpleTimeZone(-6 * ONE_HOUR, "America/Managua"), //$NON-NLS-1$ + new SimpleTimeZone(-6 * ONE_HOUR, + "America/Mexico_City", //$NON-NLS-1$ + Calendar.MAY, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.SEPTEMBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-6 * ONE_HOUR, "America/Regina"), //$NON-NLS-1$ + new SimpleTimeZone(-6 * ONE_HOUR, "America/Tegucigalpa"), //$NON-NLS-1$ + new SimpleTimeZone(-6 * ONE_HOUR, + "America/Winnipeg", //$NON-NLS-1$ //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-6 * ONE_HOUR, + "Pacific/Easter", //$NON-NLS-1$ + Calendar.OCTOBER, 9, -Calendar.SUNDAY, 4 * ONE_HOUR, + Calendar.MARCH, 9, -Calendar.SUNDAY, 3 * ONE_HOUR), + new SimpleTimeZone(-6 * ONE_HOUR, "Pacific/Galapagos"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, "America/Bogota"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, "America/Cayman"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, + "America/Grand_Turk",//$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 0 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(-5 * ONE_HOUR, "America/Guayaquil"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, + "America/Havana", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 0 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(-5 * ONE_HOUR, "America/Indianapolis"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, "America/Jamaica"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, "America/Lima"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, + "America/Montreal", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-5 * ONE_HOUR, + "America/Nassau", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-5 * ONE_HOUR, + "America/New_York", //$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-5 * ONE_HOUR, "America/Panama"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, "America/Port-au-Prince"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, "America/Porto_Acre"), //$NON-NLS-1$ + new SimpleTimeZone(-5 * ONE_HOUR, "America/Rio_Branco"), //$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Anguilla"), //$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Antigua"), //$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Aruba"), //$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, + "America/Asuncion", //$NON-NLS-1$ + Calendar.OCTOBER, 1, -Calendar.SUNDAY, 0 * ONE_HOUR, + Calendar.MARCH, 1, -Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(-4 * ONE_HOUR, "America/Barbados"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Caracas"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, + "America/Cuiaba",//$NON-NLS-1$ + Calendar.OCTOBER, 8, -Calendar.SUNDAY, 0 * ONE_HOUR, + Calendar.FEBRUARY, 15, -Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(-4 * ONE_HOUR, "America/Curacao"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Dominica"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Grenada"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Guadeloupe"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Guyana"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/La_Paz"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Manaus"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Martinique"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Montserrat"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Port_of_Spain"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/Puerto_Rico"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, + "America/Santiago",//$NON-NLS-1$ + Calendar.OCTOBER, 9, -Calendar.SUNDAY, 4 * ONE_HOUR, + Calendar.MARCH, 9, -Calendar.SUNDAY, 3 * ONE_HOUR), + new SimpleTimeZone(-4 * ONE_HOUR, "America/Santo_Domingo"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/St_Kitts"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/St_Lucia"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/St_Thomas"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, "America/St_Vincent"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, + "America/Thule",//$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-4 * ONE_HOUR, "America/Tortola"),//$NON-NLS-1$ + new SimpleTimeZone(-4 * ONE_HOUR, + "Antarctica/Palmer",//$NON-NLS-1$ + Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * ONE_HOUR, + Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(-4 * ONE_HOUR, + "Atlantic/Bermuda",//$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-4 * ONE_HOUR, + "Atlantic/Stanley",//$NON-NLS-1$ + Calendar.SEPTEMBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.APRIL, 15, -Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-3 * ONE_HOUR - 1800000, + "America/St_Johns",//$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 60000, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 60000), + new SimpleTimeZone(-3 * ONE_HOUR, "America/Buenos_Aires"),//$NON-NLS-1$ + new SimpleTimeZone(-3 * ONE_HOUR, "America/Cayenne"),//$NON-NLS-1$ + new SimpleTimeZone(-3 * ONE_HOUR, "America/Fortaleza"),//$NON-NLS-1$ + new SimpleTimeZone(-3 * ONE_HOUR, + "America/Godthab",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(-3 * ONE_HOUR, + "America/Miquelon",//$NON-NLS-1$ + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(-3 * ONE_HOUR, "America/Montevideo"),//$NON-NLS-1$ + new SimpleTimeZone(-3 * ONE_HOUR, "America/Paramaribo"),//$NON-NLS-1$ + new SimpleTimeZone(-3 * ONE_HOUR, + "America/Sao_Paulo",//$NON-NLS-1$ + Calendar.OCTOBER, 8, -Calendar.SUNDAY, 0 * ONE_HOUR, + Calendar.FEBRUARY, 15, -Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(-2 * ONE_HOUR, "America/Noronha"),//$NON-NLS-1$ + new SimpleTimeZone(-1 * ONE_HOUR, + "America/Scoresbysund",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(-1 * ONE_HOUR, "Atlantic/Cape_Verde"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Abidjan"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Accra"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Banjul"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Bissau"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Casablanca"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Conakry"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Dakar"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Freetown"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Lome"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Monrovia"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Nouakchott"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Ouagadougou"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Sao_Tome"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Africa/Timbuktu"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, + "Atlantic/Canary",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(0 * ONE_HOUR, + "Atlantic/Faeroe",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(0 * ONE_HOUR, "Atlantic/Reykjavik"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, "Atlantic/St_Helena"),//$NON-NLS-1$ + new SimpleTimeZone(0 * ONE_HOUR, + "Europe/Dublin",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(0 * ONE_HOUR, + "Europe/Lisbon",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Bangui"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Douala"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Kinshasa"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Lagos"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Libreville"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Luanda"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Malabo"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Ndjamena"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Niamey"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Porto-Novo"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, "Africa/Tunis"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, + "Africa/Windhoek",//$NON-NLS-1$ + Calendar.SEPTEMBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, "Atlantic/Jan_Mayen"),//$NON-NLS-1$ + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Amsterdam",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Andorra",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Belgrade",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Berlin",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Brussels",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Budapest",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Copenhagen",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Gibraltar",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Luxembourg",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Madrid",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Malta",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Monaco",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, "Europe/Oslo", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Paris",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Prague",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, "Europe/Rome", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Stockholm",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Tirane",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Vaduz",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Vienna",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Warsaw",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(1 * ONE_HOUR, + "Europe/Zurich",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Blantyre"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Bujumbura"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Gaborone"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Johannesburg"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Kigali"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Lubumbashi"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Lusaka"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Maputo"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Maseru"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Mbabane"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Africa/Tripoli"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Asia/Amman", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.THURSDAY, 0 * ONE_HOUR, + Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 0 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, "Asia/Beirut", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Asia/Damascus",//$NON-NLS-1$ + Calendar.APRIL, 1, 0, 0 * ONE_HOUR, Calendar.OCTOBER, + 1, 0, 0 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Asia/Nicosia",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Athens",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Chisinau",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Helsinki",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Istanbul",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Kaliningrad",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, "Europe/Kiev", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Minsk",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, "Europe/Riga", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Simferopol",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, + "Europe/Sofia",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(2 * ONE_HOUR, "Europe/Tallinn"),//$NON-NLS-1$ + new SimpleTimeZone(2 * ONE_HOUR, "Europe/Vilnius"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Africa/Addis_Ababa"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Africa/Asmera"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Africa/Dar_es_Salaam"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Africa/Djibouti"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Africa/Kampala"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Africa/Khartoum"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Africa/Mogadishu"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Africa/Nairobi"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Asia/Aden"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, + "Asia/Baghdad",//$NON-NLS-1$ + Calendar.APRIL, 1, 0, 3 * ONE_HOUR, Calendar.OCTOBER, + 1, 0, 3 * ONE_HOUR), + new SimpleTimeZone(3 * ONE_HOUR, "Asia/Bahrain"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Asia/Kuwait"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Asia/Qatar"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Asia/Riyadh"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Indian/Antananarivo"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Indian/Comoro"),//$NON-NLS-1$ + new SimpleTimeZone(3 * ONE_HOUR, "Indian/Mayotte"),//$NON-NLS-1$ + new SimpleTimeZone(4 * ONE_HOUR, "Asia/Aqtau", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(4 * ONE_HOUR, "Asia/Baku", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 1 * ONE_HOUR), + new SimpleTimeZone(4 * ONE_HOUR, "Asia/Muscat"),//$NON-NLS-1$ + new SimpleTimeZone(4 * ONE_HOUR, + "Asia/Tbilisi",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 0 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(4 * ONE_HOUR, + "Asia/Yerevan",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(4 * ONE_HOUR, + "Europe/Samara",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(4 * ONE_HOUR, "Indian/Mahe"),//$NON-NLS-1$ + new SimpleTimeZone(4 * ONE_HOUR, "Indian/Mauritius"),//$NON-NLS-1$ + new SimpleTimeZone(4 * ONE_HOUR, "Indian/Reunion"),//$NON-NLS-1$ + new SimpleTimeZone(5 * ONE_HOUR, "Asia/Aqtobe", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(5 * ONE_HOUR, "Asia/Ashgabat"),//$NON-NLS-1$ + new SimpleTimeZone(5 * ONE_HOUR, "Asia/Ashkhabad"),//$NON-NLS-1$ + new SimpleTimeZone( + 5 * ONE_HOUR, + "Asia/Bishkek",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, + 2 * ONE_HOUR + 1800000, Calendar.OCTOBER, -1, + Calendar.SUNDAY, 2 * ONE_HOUR + 1800000), + new SimpleTimeZone(5 * ONE_HOUR, "Asia/Dushanbe"),//$NON-NLS-1$ + new SimpleTimeZone(5 * ONE_HOUR, "Asia/Karachi"),//$NON-NLS-1$ + new SimpleTimeZone(5 * ONE_HOUR, "Asia/Tashkent"),//$NON-NLS-1$ + new SimpleTimeZone(5 * ONE_HOUR, + "Asia/Yekaterinburg",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(5 * ONE_HOUR, "Indian/Kerguelen"),//$NON-NLS-1$ + new SimpleTimeZone(5 * ONE_HOUR, "Indian/Maldives"),//$NON-NLS-1$ + new SimpleTimeZone(5 * ONE_HOUR + 1800000, "Asia/Calcutta"),//$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR, "Antarctica/Mawson"),//$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR, "Asia/Almaty", Calendar.MARCH,//$NON-NLS-1$ + -1, Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.OCTOBER, + -1, Calendar.SUNDAY, 0 * ONE_HOUR), + new SimpleTimeZone(5 * ONE_HOUR + HALF_HOUR, "Asia/Colombo"),//$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR, "Asia/Dacca"),//$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR, "Asia/Dhaka"),//$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR, + "Asia/Novosibirsk",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(6 * ONE_HOUR, "Asia/Thimbu"),//$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR, "Asia/Thimphu"),//$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR, "Indian/Chagos"),//$NON-NLS-1$ + new SimpleTimeZone(6 * ONE_HOUR + 1800000, "Indian/Cocos"),//$NON-NLS-1$ + new SimpleTimeZone(7 * ONE_HOUR, "Asia/Bangkok"),//$NON-NLS-1$ + new SimpleTimeZone(7 * ONE_HOUR, "Asia/Jakarta"),//$NON-NLS-1$ + new SimpleTimeZone(7 * ONE_HOUR, + "Asia/Krasnoyarsk",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(7 * ONE_HOUR, "Asia/Phnom_Penh"),//$NON-NLS-1$ + new SimpleTimeZone(7 * ONE_HOUR, "Asia/Saigon"),//$NON-NLS-1$ + new SimpleTimeZone(7 * ONE_HOUR, "Asia/Vientiane"),//$NON-NLS-1$ + new SimpleTimeZone(7 * ONE_HOUR, "Indian/Christmas"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Antarctica/Casey"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Brunei"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Hong_Kong"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, + "Asia/Irkutsk",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Kuala_Lumpur"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Macao"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Manila"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Shanghai"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Singapore"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Taipei"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Ujung_Pandang"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Ulaanbaatar"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Asia/Ulan_Bator"),//$NON-NLS-1$ + new SimpleTimeZone(8 * ONE_HOUR, "Australia/Perth"),//$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR, "Asia/Jayapura"),//$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR, "Asia/Pyongyang"),//$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR, "Asia/Seoul"),//$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR, "Asia/Tokyo"),//$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR, + "Asia/Yakutsk",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR),//$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR, "Pacific/Palau"),//$NON-NLS-1$ + new SimpleTimeZone(9 * ONE_HOUR + 1800000, + "Australia/Broken_Hill", Calendar.OCTOBER, -1,//$NON-NLS-1$ + Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, -1, + Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(9 * ONE_HOUR + 1800000, "Australia/Darwin"),//$NON-NLS-1$ + new SimpleTimeZone(10 * ONE_HOUR, "Antarctica/DumontDUrville"),//$NON-NLS-1$ + new SimpleTimeZone(10 * ONE_HOUR, + "Asia/Vladivostok",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(10 * ONE_HOUR, + "Australia/Sydney",//$NON-NLS-1$ + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(10 * ONE_HOUR, "Pacific/Guam"),//$NON-NLS-1$ + new SimpleTimeZone(10 * ONE_HOUR, "Pacific/Port_Moresby"),//$NON-NLS-1$ + new SimpleTimeZone(10 * ONE_HOUR, "Pacific/Saipan"),//$NON-NLS-1$ + new SimpleTimeZone(10 * ONE_HOUR, "Pacific/Truk"),//$NON-NLS-1$ + new SimpleTimeZone(10 * ONE_HOUR + 1800000, + "Australia/Lord_Howe", Calendar.OCTOBER, -1,//$NON-NLS-1$ + Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, -1, + Calendar.SUNDAY, 2 * ONE_HOUR, 1800000), + new SimpleTimeZone(11 * ONE_HOUR, + "Asia/Magadan",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Efate"),//$NON-NLS-1$ + new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Guadalcanal"),//$NON-NLS-1$ + new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Kosrae"),//$NON-NLS-1$ + new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Noumea"),//$NON-NLS-1$ + new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Ponape"),//$NON-NLS-1$ + new SimpleTimeZone(11 * ONE_HOUR + 1800000, "Pacific/Norfolk"),//$NON-NLS-1$ + new SimpleTimeZone(12 * ONE_HOUR, + "Antarctica/McMurdo",//$NON-NLS-1$ + Calendar.OCTOBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.MARCH, 15, -Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(12 * ONE_HOUR, + "Asia/Anadyr",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(12 * ONE_HOUR, + "Asia/Kamchatka",//$NON-NLS-1$ + Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(12 * ONE_HOUR, + "Pacific/Auckland",//$NON-NLS-1$ + Calendar.OCTOBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, + Calendar.MARCH, 15, -Calendar.SUNDAY, 2 * ONE_HOUR), + new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Fiji"),//$NON-NLS-1$ + new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Funafuti"),//$NON-NLS-1$ + new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Majuro"),//$NON-NLS-1$ + new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Nauru"),//$NON-NLS-1$ + new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Tarawa"),//$NON-NLS-1$ + new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Wake"),//$NON-NLS-1$ + new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Wallis"),//$NON-NLS-1$ + new SimpleTimeZone(13 * ONE_HOUR, "Pacific/Enderbury"),//$NON-NLS-1$ + new SimpleTimeZone(13 * ONE_HOUR, "Pacific/Tongatapu"),//$NON-NLS-1$ + new SimpleTimeZone(14 * ONE_HOUR, "Pacific/Kiritimati"), };//$NON-NLS-1$ + } +} From 0cd1ddedc503e4f86b02e2a165e909bbec0e62fa Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Thu, 15 May 2014 18:25:45 +0400 Subject: [PATCH 2/4] Fixes some compilation errors and applies formatting --- .../teavm/classlib/java/util/Calendar.java | 761 +----------------- .../org/teavm/classlib/java/util/Date.java | 389 +-------- .../classlib/java/util/GregorianCalendar.java | 195 +---- .../classlib/java/util/SimpleTimeZone.java | 604 ++------------ .../teavm/classlib/java/util/TimeZone.java | 285 +------ 5 files changed, 160 insertions(+), 2074 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java index 51a587807..9ff267fed 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java @@ -32,36 +32,19 @@ package org.teavm.classlib.java.util; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TCloneable; +import org.teavm.classlib.java.lang.TComparable; + public abstract class Calendar implements TSerializable, TCloneable, TComparable { - - private static final long serialVersionUID = -1807547505821590642L; - - /** - * Set to {@code true} when the calendar fields have been set from the time, set to - * {@code false} when a field is changed and the fields must be recomputed. - */ protected boolean areFieldsSet; - /** - * An integer array of calendar fields. The length is {@code FIELD_COUNT}. - */ protected int[] fields; - /** - * A boolean array. Each element indicates if the corresponding field has - * been set. The length is {@code FIELD_COUNT}. - */ protected boolean[] isSet; - /** - * Set to {@code true} when the time has been set, set to {@code false} when a field is - * changed and the time must be recomputed. - */ protected boolean isTimeSet; - /** - * The time in milliseconds since January 1, 1970. - */ protected long time; transient int lastTimeFieldSet; @@ -76,344 +59,95 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable private TimeZone zone; - /** - * Value of the {@code MONTH} field indicating the first month of the - * year. - */ public static final int JANUARY = 0; - /** - * Value of the {@code MONTH} field indicating the second month of - * the year. - */ public static final int FEBRUARY = 1; - /** - * Value of the {@code MONTH} field indicating the third month of the - * year. - */ public static final int MARCH = 2; - /** - * Value of the {@code MONTH} field indicating the fourth month of - * the year. - */ public static final int APRIL = 3; - /** - * Value of the {@code MONTH} field indicating the fifth month of the - * year. - */ public static final int MAY = 4; - /** - * Value of the {@code MONTH} field indicating the sixth month of the - * year. - */ public static final int JUNE = 5; - /** - * Value of the {@code MONTH} field indicating the seventh month of - * the year. - */ public static final int JULY = 6; - /** - * Value of the {@code MONTH} field indicating the eighth month of - * the year. - */ public static final int AUGUST = 7; - /** - * Value of the {@code MONTH} field indicating the ninth month of the - * year. - */ public static final int SEPTEMBER = 8; - /** - * Value of the {@code MONTH} field indicating the tenth month of the - * year. - */ public static final int OCTOBER = 9; - /** - * Value of the {@code MONTH} field indicating the eleventh month of - * the year. - */ public static final int NOVEMBER = 10; - /** - * Value of the {@code MONTH} field indicating the twelfth month of - * the year. - */ public static final int DECEMBER = 11; - /** - * Value of the {@code MONTH} field indicating the thirteenth month - * of the year. Although {@code GregorianCalendar} does not use this - * value, lunar calendars do. - */ public static final int UNDECIMBER = 12; - /** - * Value of the {@code DAY_OF_WEEK} field indicating Sunday. - */ public static final int SUNDAY = 1; - /** - * Value of the {@code DAY_OF_WEEK} field indicating Monday. - */ public static final int MONDAY = 2; - /** - * Value of the {@code DAY_OF_WEEK} field indicating Tuesday. - */ public static final int TUESDAY = 3; - /** - * Value of the {@code DAY_OF_WEEK} field indicating Wednesday. - */ public static final int WEDNESDAY = 4; - /** - * Value of the {@code DAY_OF_WEEK} field indicating Thursday. - */ public static final int THURSDAY = 5; - /** - * Value of the {@code DAY_OF_WEEK} field indicating Friday. - */ public static final int FRIDAY = 6; - /** - * Value of the {@code DAY_OF_WEEK} field indicating Saturday. - */ public static final int SATURDAY = 7; - /** - * Field number for {@code get} and {@code set} indicating the - * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific - * value; see subclass documentation. - * - * @see GregorianCalendar#AD - * @see GregorianCalendar#BC - */ public static final int ERA = 0; - /** - * Field number for {@code get} and {@code set} indicating the - * year. This is a calendar-specific value; see subclass documentation. - */ public static final int YEAR = 1; - /** - * Field number for {@code get} and {@code set} indicating the - * month. This is a calendar-specific value. The first month of the year is - * {@code JANUARY}; the last depends on the number of months in a - * year. - * - * @see #JANUARY - * @see #FEBRUARY - * @see #MARCH - * @see #APRIL - * @see #MAY - * @see #JUNE - * @see #JULY - * @see #AUGUST - * @see #SEPTEMBER - * @see #OCTOBER - * @see #NOVEMBER - * @see #DECEMBER - * @see #UNDECIMBER - */ public static final int MONTH = 2; - /** - * Field number for {@code get} and {@code set} indicating the - * week number within the current year. The first week of the year, as - * defined by {@code getFirstDayOfWeek()} and - * {@code getMinimalDaysInFirstWeek()}, has value 1. Subclasses - * define the value of {@code WEEK_OF_YEAR} for days before the first - * week of the year. - * - * @see #getFirstDayOfWeek - * @see #getMinimalDaysInFirstWeek - */ public static final int WEEK_OF_YEAR = 3; - /** - * Field number for {@code get} and {@code set} indicating the - * week number within the current month. The first week of the month, as - * defined by {@code getFirstDayOfWeek()} and - * {@code getMinimalDaysInFirstWeek()}, has value 1. Subclasses - * define the value of {@code WEEK_OF_MONTH} for days before the - * first week of the month. - * - * @see #getFirstDayOfWeek - * @see #getMinimalDaysInFirstWeek - */ public static final int WEEK_OF_MONTH = 4; - /** - * Field number for {@code get} and {@code set} indicating the - * day of the month. This is a synonym for {@code DAY_OF_MONTH}. The - * first day of the month has value 1. - * - * @see #DAY_OF_MONTH - */ public static final int DATE = 5; - /** - * Field number for {@code get} and {@code set} indicating the - * day of the month. This is a synonym for {@code DATE}. The first - * day of the month has value 1. - * - * @see #DATE - */ public static final int DAY_OF_MONTH = 5; - /** - * Field number for {@code get} and {@code set} indicating the - * day number within the current year. The first day of the year has value - * 1. - */ public static final int DAY_OF_YEAR = 6; - /** - * Field number for {@code get} and {@code set} indicating the - * day of the week. This field takes values {@code SUNDAY}, - * {@code MONDAY}, {@code TUESDAY}, {@code WEDNESDAY}, - * {@code THURSDAY}, {@code FRIDAY}, and - * {@code SATURDAY}. - * - * @see #SUNDAY - * @see #MONDAY - * @see #TUESDAY - * @see #WEDNESDAY - * @see #THURSDAY - * @see #FRIDAY - * @see #SATURDAY - */ public static final int DAY_OF_WEEK = 7; - /** - * Field number for {@code get} and {@code set} indicating the - * ordinal number of the day of the week within the current month. Together - * with the {@code DAY_OF_WEEK} field, this uniquely specifies a day - * within a month. Unlike {@code WEEK_OF_MONTH} and - * {@code WEEK_OF_YEAR}, this field's value does not - * depend on {@code getFirstDayOfWeek()} or - * {@code getMinimalDaysInFirstWeek()}. {@code DAY_OF_MONTH 1} - * through {@code 7} always correspond to DAY_OF_WEEK_IN_MONTH - * 1; - * {@code 8} through {@code 15} correspond to - * {@code DAY_OF_WEEK_IN_MONTH 2}, and so on. - * {@code DAY_OF_WEEK_IN_MONTH 0} indicates the week before - * {@code DAY_OF_WEEK_IN_MONTH 1}. Negative values count back from - * the end of the month, so the last Sunday of a month is specified as - * {@code DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1}. Because - * negative values count backward they will usually be aligned differently - * within the month than positive values. For example, if a month has 31 - * days, {@code DAY_OF_WEEK_IN_MONTH -1} will overlap - * {@code DAY_OF_WEEK_IN_MONTH 5} and the end of {@code 4}. - * - * @see #DAY_OF_WEEK - * @see #WEEK_OF_MONTH - */ public static final int DAY_OF_WEEK_IN_MONTH = 8; - /** - * Field number for {@code get} and {@code set} indicating - * whether the {@code HOUR} is before or after noon. E.g., at - * 10:04:15.250 PM the {@code AM_PM} is {@code PM}. - * - * @see #AM - * @see #PM - * @see #HOUR - */ public static final int AM_PM = 9; - /** - * Field number for {@code get} and {@code set} indicating the - * hour of the morning or afternoon. {@code HOUR} is used for the - * 12-hour clock. E.g., at 10:04:15.250 PM the {@code HOUR} is 10. - * - * @see #AM_PM - * @see #HOUR_OF_DAY - */ public static final int HOUR = 10; - /** - * Field number for {@code get} and {@code set} indicating the - * hour of the day. {@code HOUR_OF_DAY} is used for the 24-hour - * clock. E.g., at 10:04:15.250 PM the {@code HOUR_OF_DAY} is 22. - * - * @see #HOUR - */ public static final int HOUR_OF_DAY = 11; - /** - * Field number for {@code get} and {@code set} indicating the - * minute within the hour. E.g., at 10:04:15.250 PM the {@code MINUTE} - * is 4. - */ public static final int MINUTE = 12; - /** - * Field number for {@code get} and {@code set} indicating the - * second within the minute. E.g., at 10:04:15.250 PM the - * {@code SECOND} is 15. - */ public static final int SECOND = 13; - /** - * Field number for {@code get} and {@code set} indicating the - * millisecond within the second. E.g., at 10:04:15.250 PM the - * {@code MILLISECOND} is 250. - */ public static final int MILLISECOND = 14; - /** - * Field number for {@code get} and {@code set} indicating the - * raw offset from GMT in milliseconds. - */ public static final int ZONE_OFFSET = 15; - /** - * Field number for {@code get} and {@code set} indicating the - * daylight savings offset in milliseconds. - */ public static final int DST_OFFSET = 16; - /** - * This is the total number of fields in this calendar. - */ public static final int FIELD_COUNT = 17; - /** - * Value of the {@code AM_PM} field indicating the period of the day - * from midnight to just before noon. - */ public static final int AM = 0; - /** - * Value of the {@code AM_PM} field indicating the period of the day - * from noon to just before midnight. - */ public static final int PM = 1; @SuppressWarnings("nls") - private static String[] fieldNames = { "ERA=", "YEAR=", "MONTH=", - "WEEK_OF_YEAR=", "WEEK_OF_MONTH=", "DAY_OF_MONTH=", "DAY_OF_YEAR=", - "DAY_OF_WEEK=", "DAY_OF_WEEK_IN_MONTH=", "AM_PM=", "HOUR=", - "HOUR_OF_DAY", "MINUTE=", "SECOND=", "MILLISECOND=", - "ZONE_OFFSET=", "DST_OFFSET=" }; + private static String[] fieldNames = { "ERA=", "YEAR=", "MONTH=", "WEEK_OF_YEAR=", "WEEK_OF_MONTH=", + "DAY_OF_MONTH=", "DAY_OF_YEAR=", "DAY_OF_WEEK=", "DAY_OF_WEEK_IN_MONTH=", "AM_PM=", "HOUR=", "HOUR_OF_DAY", + "MINUTE=", "SECOND=", "MILLISECOND=", "ZONE_OFFSET=", "DST_OFFSET=" }; - /** - * Constructs a {@code Calendar} instance using the default {@code TimeZone} and {@code Locale}. - */ protected Calendar() { - this(TimeZone.getDefault(), Locale.getDefault()); + this(TimeZone.getDefault(), TLocale.getDefault()); } Calendar(TimeZone timezone) { @@ -424,49 +158,16 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable setTimeZone(timezone); } - /** - * Constructs a {@code Calendar} instance using the specified {@code TimeZone} and {@code Locale}. - * - * @param timezone - * the timezone. - * @param locale - * the locale. - */ - protected Calendar(TimeZone timezone, Locale locale) { + protected Calendar(TimeZone timezone, TLocale locale) { this(timezone); - com.ibm.icu.util.Calendar icuCalendar = com.ibm.icu.util.Calendar - .getInstance(com.ibm.icu.util.SimpleTimeZone - .getTimeZone(timezone.getID()), locale); + com.ibm.icu.util.Calendar icuCalendar = com.ibm.icu.util.Calendar.getInstance( + com.ibm.icu.util.SimpleTimeZone.getTimeZone(timezone.getID()), locale); setFirstDayOfWeek(icuCalendar.getFirstDayOfWeek()); setMinimalDaysInFirstWeek(icuCalendar.getMinimalDaysInFirstWeek()); } - - /** - * Adds the specified amount to a {@code Calendar} field. - * - * @param field - * the {@code Calendar} field to modify. - * @param value - * the amount to add to the field. - * @throws IllegalArgumentException - * if {@code field} is {@code DST_OFFSET} or {@code - * ZONE_OFFSET}. - */ abstract public void add(int field, int value); - /** - * Returns whether the {@code Date} specified by this {@code Calendar} instance is after the {@code Date} - * specified by the parameter. The comparison is not dependent on the time - * zones of the {@code Calendar}. - * - * @param calendar - * the {@code Calendar} instance to compare. - * @return {@code true} when this Calendar is after calendar, {@code false} otherwise. - * @throws IllegalArgumentException - * if the time is not set and the time cannot be computed - * from the current field values. - */ public boolean after(Object calendar) { if (!(calendar instanceof Calendar)) { return false; @@ -474,18 +175,6 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return getTimeInMillis() > ((Calendar) calendar).getTimeInMillis(); } - /** - * Returns whether the {@code Date} specified by this {@code Calendar} instance is before the - * {@code Date} specified by the parameter. The comparison is not dependent on the - * time zones of the {@code Calendar}. - * - * @param calendar - * the {@code Calendar} instance to compare. - * @return {@code true} when this Calendar is before calendar, {@code false} otherwise. - * @throws IllegalArgumentException - * if the time is not set and the time cannot be computed - * from the current field values. - */ public boolean before(Object calendar) { if (!(calendar instanceof Calendar)) { return false; @@ -493,10 +182,6 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return getTimeInMillis() < ((Calendar) calendar).getTimeInMillis(); } - /** - * Clears all of the fields of this {@code Calendar}. All fields are initialized to - * zero. - */ public final void clear() { for (int i = 0; i < FIELD_COUNT; i++) { fields[i] = 0; @@ -505,25 +190,12 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable areFieldsSet = isTimeSet = false; } - /** - * Clears the specified field to zero and sets the isSet flag to {@code false}. - * - * @param field - * the field to clear. - */ public final void clear(int field) { fields[field] = 0; isSet[field] = false; areFieldsSet = isTimeSet = false; } - /** - * Returns a new {@code Calendar} with the same properties. - * - * @return a shallow copy of this {@code Calendar}. - * - * @see java.lang.Cloneable - */ @Override public Object clone() { try { @@ -537,14 +209,6 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable } } - /** - * Computes the time from the fields if the time has not already been set. - * Computes the fields from the time if the fields are not already set. - * - * @throws IllegalArgumentException - * if the time is not set and the time cannot be computed - * from the current field values. - */ protected void complete() { if (!isTimeSet) { computeTime(); @@ -556,30 +220,10 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable } } - /** - * Computes the {@code Calendar} fields from {@code time}. - */ protected abstract void computeFields(); - /** - * Computes {@code time} from the Calendar fields. - * - * @throws IllegalArgumentException - * if the time cannot be computed from the current field - * values. - */ protected abstract void computeTime(); - /** - * Compares the specified object to this {@code Calendar} and returns whether they are - * equal. The object must be an instance of {@code Calendar} and have the same - * properties. - * - * @param object - * the object to compare with this object. - * @return {@code true} if the specified object is equal to this {@code Calendar}, {@code false} - * otherwise. - */ @Override public boolean equals(Object object) { if (this == object) { @@ -589,41 +233,17 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return false; } Calendar cal = (Calendar) object; - return getTimeInMillis() == cal.getTimeInMillis() - && isLenient() == cal.isLenient() - && getFirstDayOfWeek() == cal.getFirstDayOfWeek() - && getMinimalDaysInFirstWeek() == cal - .getMinimalDaysInFirstWeek() - && getTimeZone().equals(cal.getTimeZone()); + return getTimeInMillis() == cal.getTimeInMillis() && isLenient() == cal.isLenient() && + getFirstDayOfWeek() == cal.getFirstDayOfWeek() && + getMinimalDaysInFirstWeek() == cal.getMinimalDaysInFirstWeek() && + getTimeZone().equals(cal.getTimeZone()); } - /** - * Gets the value of the specified field after computing the field values by - * calling {@code complete()} first. - * - * @param field - * the field to get. - * @return the value of the specified field. - * - * @throws IllegalArgumentException - * if the fields are not set, the time is not set, and the - * time cannot be computed from the current field values. - * @throws ArrayIndexOutOfBoundsException - * if the field is not inside the range of possible fields. - * The range is starting at 0 up to {@code FIELD_COUNT}. - */ public int get(int field) { complete(); return fields[field]; } - /** - * Gets the maximum value of the specified field for the current date. - * - * @param field - * the field. - * @return the maximum value of the specified field. - */ public int getActualMaximum(int field) { int value, next; if (getMaximum(field) == (next = getLeastMaximum(field))) { @@ -642,13 +262,6 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return value; } - /** - * Gets the minimum value of the specified field for the current date. - * - * @param field - * the field. - * @return the minimum value of the specified field. - */ public int getActualMinimum(int field) { int value, next; if (getMinimum(field) == (next = getGreatestMinimum(field))) { @@ -667,149 +280,46 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return value; } - /** - * Gets the list of installed {@code Locale}s which support {@code Calendar}. - * - * @return an array of {@code Locale}. - */ - public static synchronized Locale[] getAvailableLocales() { - return Locale.getAvailableLocales(); + public static synchronized TLocale[] getAvailableLocales() { + return TLocale.getAvailableLocales(); } - /** - * Gets the first day of the week for this {@code Calendar}. - * - * @return the first day of the week. - */ public int getFirstDayOfWeek() { return firstDayOfWeek; } - /** - * Gets the greatest minimum value of the specified field. This is the - * biggest value that {@code getActualMinimum} can return for any possible - * time. - * - * @param field - * the field. - * @return the greatest minimum value of the specified field. - */ abstract public int getGreatestMinimum(int field); - /** - * Constructs a new instance of the {@code Calendar} subclass appropriate for the - * default {@code Locale}. - * - * @return a {@code Calendar} subclass instance set to the current date and time in - * the default {@code Timezone}. - */ public static synchronized Calendar getInstance() { return new GregorianCalendar(); } - /** - * Constructs a new instance of the {@code Calendar} subclass appropriate for the - * specified {@code Locale}. - * - * @param locale - * the locale to use. - * @return a {@code Calendar} subclass instance set to the current date and time. - */ - public static synchronized Calendar getInstance(Locale locale) { + public static synchronized Calendar getInstance(TLocale locale) { return new GregorianCalendar(locale); } - /** - * Constructs a new instance of the {@code Calendar} subclass appropriate for the - * default {@code Locale}, using the specified {@code TimeZone}. - * - * @param timezone - * the {@code TimeZone} to use. - * @return a {@code Calendar} subclass instance set to the current date and time in - * the specified timezone. - */ public static synchronized Calendar getInstance(TimeZone timezone) { return new GregorianCalendar(timezone); } - /** - * Constructs a new instance of the {@code Calendar} subclass appropriate for the - * specified {@code Locale}. - * - * @param timezone - * the {@code TimeZone} to use. - * @param locale - * the {@code Locale} to use. - * @return a {@code Calendar} subclass instance set to the current date and time in - * the specified timezone. - */ - public static synchronized Calendar getInstance(TimeZone timezone, - Locale locale) { + public static synchronized Calendar getInstance(TimeZone timezone, TLocale locale) { return new GregorianCalendar(timezone, locale); } - /** - * Gets the smallest maximum value of the specified field. This is the - * smallest value that {@code getActualMaximum()} can return for any - * possible time. - * - * @param field - * the field number. - * @return the smallest maximum value of the specified field. - */ abstract public int getLeastMaximum(int field); - /** - * Gets the greatest maximum value of the specified field. This returns the - * biggest value that {@code get} can return for the specified field. - * - * @param field - * the field. - * @return the greatest maximum value of the specified field. - */ abstract public int getMaximum(int field); - /** - * Gets the minimal days in the first week of the year. - * - * @return the minimal days in the first week of the year. - */ public int getMinimalDaysInFirstWeek() { return minimalDaysInFirstWeek; } - /** - * Gets the smallest minimum value of the specified field. this returns the - * smallest value thet {@code get} can return for the specified field. - * - * @param field - * the field number. - * @return the smallest minimum value of the specified field. - */ abstract public int getMinimum(int field); - /** - * Gets the time of this {@code Calendar} as a {@code Date} object. - * - * @return a new {@code Date} initialized to the time of this {@code Calendar}. - * - * @throws IllegalArgumentException - * if the time is not set and the time cannot be computed - * from the current field values. - */ public final Date getTime() { return new Date(getTimeInMillis()); } - /** - * Computes the time from the fields if required and returns the time. - * - * @return the time of this {@code Calendar}. - * - * @throws IllegalArgumentException - * if the time is not set and the time cannot be computed - * from the current field values. - */ public long getTimeInMillis() { if (!isTimeSet) { computeTime(); @@ -818,72 +328,28 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return time; } - /** - * Gets the timezone of this {@code Calendar}. - * - * @return the {@code TimeZone} used by this {@code Calendar}. - */ public TimeZone getTimeZone() { return zone; } - /** - * Returns an integer hash code for the receiver. Objects which are equal - * return the same value for this method. - * - * @return the receiver's hash. - * - * @see #equals - */ @Override public int hashCode() { - return (isLenient() ? 1237 : 1231) + getFirstDayOfWeek() - + getMinimalDaysInFirstWeek() + getTimeZone().hashCode(); + return (isLenient() ? 1237 : 1231) + getFirstDayOfWeek() + getMinimalDaysInFirstWeek() + + getTimeZone().hashCode(); } - /** - * Gets the value of the specified field without recomputing. - * - * @param field - * the field. - * @return the value of the specified field. - */ protected final int internalGet(int field) { return fields[field]; } - /** - * Returns if this {@code Calendar} accepts field values which are outside the valid - * range for the field. - * - * @return {@code true} if this {@code Calendar} is lenient, {@code false} otherwise. - */ public boolean isLenient() { return lenient; } - /** - * Returns whether the specified field is set. - * - * @param field - * a {@code Calendar} field number. - * @return {@code true} if the specified field is set, {@code false} otherwise. - */ public final boolean isSet(int field) { return isSet[field]; } - /** - * Adds the specified amount to the specified field and wraps the value of - * the field when it goes beyond the maximum or minimum value for the - * current date. Other fields will be adjusted as required to maintain a - * consistent date. - * - * @param field - * the field to roll. - * @param value - * the amount to add. - */ public void roll(int field, int value) { boolean increment = value >= 0; int count = increment ? value : -value; @@ -892,27 +358,8 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable } } - /** - * Increment or decrement the specified field and wrap the value of the - * field when it goes beyond the maximum or minimum value for the current - * date. Other fields will be adjusted as required to maintain a consistent - * date. - * - * @param field - * the number indicating the field to roll. - * @param increment - * {@code true} to increment the field, {@code false} to decrement. - */ abstract public void roll(int field, boolean increment); - /** - * Sets a field to the specified value. - * - * @param field - * the code indicating the {@code Calendar} field to modify. - * @param value - * the value. - */ public void set(int field, int value) { fields[field] = value; isSet[field] = true; @@ -928,115 +375,39 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable } } - /** - * Sets the year, month and day of the month fields. Other fields are not - * changed. - * - * @param year - * the year. - * @param month - * the month. - * @param day - * the day of the month. - */ public final void set(int year, int month, int day) { set(YEAR, year); set(MONTH, month); set(DATE, day); } - /** - * Sets the year, month, day of the month, hour of day and minute fields. - * Other fields are not changed. - * - * @param year - * the year. - * @param month - * the month. - * @param day - * the day of the month. - * @param hourOfDay - * the hour of day. - * @param minute - * the minute. - */ - public final void set(int year, int month, int day, int hourOfDay, - int minute) { + public final void set(int year, int month, int day, int hourOfDay, int minute) { set(year, month, day); set(HOUR_OF_DAY, hourOfDay); set(MINUTE, minute); } - /** - * Sets the year, month, day of the month, hour of day, minute and second - * fields. Other fields are not changed. - * - * @param year - * the year. - * @param month - * the month. - * @param day - * the day of the month. - * @param hourOfDay - * the hour of day. - * @param minute - * the minute. - * @param second - * the second. - */ - public final void set(int year, int month, int day, int hourOfDay, - int minute, int second) { + public final void set(int year, int month, int day, int hourOfDay, int minute, int second) { set(year, month, day, hourOfDay, minute); set(SECOND, second); } - /** - * Sets the first day of the week for this {@code Calendar}. - * - * @param value - * a {@code Calendar} day of the week. - */ public void setFirstDayOfWeek(int value) { firstDayOfWeek = value; } - /** - * Sets this {@code Calendar} to accept field values which are outside the valid - * range for the field. - * - * @param value - * a boolean value. - */ public void setLenient(boolean value) { lenient = value; } - /** - * Sets the minimal days in the first week of the year. - * - * @param value - * the minimal days in the first week of the year. - */ public void setMinimalDaysInFirstWeek(int value) { minimalDaysInFirstWeek = value; } - /** - * Sets the time of this {@code Calendar}. - * - * @param date - * a {@code Date} object. - */ public final void setTime(Date date) { setTimeInMillis(date.getTime()); } - /** - * Sets the time of this {@code Calendar}. - * - * @param milliseconds - * the time as the number of milliseconds since Jan. 1, 1970. - */ public void setTimeInMillis(long milliseconds) { if (!isTimeSet || !areFieldsSet || time != milliseconds) { time = milliseconds; @@ -1046,33 +417,18 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable } } - /** - * Sets the {@code TimeZone} used by this Calendar. - * - * @param timezone - * a {@code TimeZone}. - */ public void setTimeZone(TimeZone timezone) { zone = timezone; areFieldsSet = false; } - /** - * Returns the string representation of this {@code Calendar}. - * - * @return the string representation of this {@code Calendar}. - */ @Override @SuppressWarnings("nls") public String toString() { - StringBuilder result = new StringBuilder(getClass().getName() + "[time=" - + (isTimeSet ? String.valueOf(time) : "?") - + ",areFieldsSet=" - + areFieldsSet - + // ",areAllFieldsSet=" + areAllFieldsSet + - ",lenient=" + lenient + ",zone=" + zone + ",firstDayOfWeek=" - + firstDayOfWeek + ",minimalDaysInFirstWeek=" - + minimalDaysInFirstWeek); + StringBuilder result = new StringBuilder(getClass().getName() + "[time=" + + (isTimeSet ? String.valueOf(time) : "?") + ",areFieldsSet=" + areFieldsSet + ",lenient=" + lenient + + ",zone=" + zone + ",firstDayOfWeek=" + firstDayOfWeek + ",minimalDaysInFirstWeek=" + + minimalDaysInFirstWeek); for (int i = 0; i < FIELD_COUNT; i++) { result.append(','); result.append(fieldNames[i]); @@ -1087,21 +443,7 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return result.toString(); } - /** - * Compares the times of the two {@code Calendar}, which represent the milliseconds - * from the January 1, 1970 00:00:00.000 GMT (Gregorian). - * - * @param anotherCalendar - * another calendar that this one is compared with. - * @return 0 if the times of the two {@code Calendar}s are equal, -1 if the time of - * this {@code Calendar} is before the other one, 1 if the time of this - * {@code Calendar} is after the other one. - * @throws NullPointerException - * if the argument is null. - * @throws IllegalArgumentException - * if the argument does not include a valid time - * value. - */ + @Override public int compareTo(Calendar anotherCalendar) { if (null == anotherCalendar) { throw new NullPointerException(); @@ -1116,51 +458,4 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable } return -1; } - - @SuppressWarnings("nls") - private static final ObjectStreamField[] serialPersistentFields = { - new ObjectStreamField("areFieldsSet", Boolean.TYPE), - new ObjectStreamField("fields", int[].class), - new ObjectStreamField("firstDayOfWeek", Integer.TYPE), - new ObjectStreamField("isSet", boolean[].class), - new ObjectStreamField("isTimeSet", Boolean.TYPE), - new ObjectStreamField("lenient", Boolean.TYPE), - new ObjectStreamField("minimalDaysInFirstWeek", Integer.TYPE), - new ObjectStreamField("nextStamp", Integer.TYPE), - new ObjectStreamField("serialVersionOnStream", Integer.TYPE), - new ObjectStreamField("time", Long.TYPE), - new ObjectStreamField("zone", TimeZone.class), }; - - @SuppressWarnings("nls") - private void writeObject(ObjectOutputStream stream) throws IOException { - complete(); - ObjectOutputStream.PutField putFields = stream.putFields(); - putFields.put("areFieldsSet", areFieldsSet); - putFields.put("fields", this.fields); - putFields.put("firstDayOfWeek", firstDayOfWeek); - putFields.put("isSet", isSet); - putFields.put("isTimeSet", isTimeSet); - putFields.put("lenient", lenient); - putFields.put("minimalDaysInFirstWeek", minimalDaysInFirstWeek); - putFields.put("nextStamp", 2 /* MINIMUM_USER_STAMP */); - putFields.put("serialVersionOnStream", 1); - putFields.put("time", time); - putFields.put("zone", zone); - stream.writeFields(); - } - - @SuppressWarnings("nls") - private void readObject(ObjectInputStream stream) throws IOException, - ClassNotFoundException { - ObjectInputStream.GetField readFields = stream.readFields(); - areFieldsSet = readFields.get("areFieldsSet", false); - this.fields = (int[]) readFields.get("fields", null); - firstDayOfWeek = readFields.get("firstDayOfWeek", Calendar.SUNDAY); - isSet = (boolean[]) readFields.get("isSet", null); - isTimeSet = readFields.get("isTimeSet", false); - lenient = readFields.get("lenient", true); - minimalDaysInFirstWeek = readFields.get("minimalDaysInFirstWeek", 1); - time = readFields.get("time", 0L); - zone = (TimeZone) readFields.get("zone", null); - } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java index dd8b4a915..444558a8a 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java @@ -47,34 +47,16 @@ public class Date implements TSerializable, TCloneable, TComparable { private transient long milliseconds; @SuppressWarnings("nls") - private static String[] dayOfWeekNames = { "Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat" }; + private static String[] dayOfWeekNames = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; @SuppressWarnings("nls") - private static String[] monthNames = { "Jan", "Feb", "Mar", "Apr", "May", - "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + private static String[] monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", + "Dec" }; - /** - * Initializes this {@code Date} instance to the current date and time. - */ public Date() { this(System.currentTimeMillis()); } - /** - * Constructs a new {@code Date} initialized to midnight in the default {@code TimeZone} on - * the specified date. - * - * @param year - * the year, 0 is 1900. - * @param month - * the month, 0 - 11. - * @param day - * the day of the month, 1 - 31. - * - * @deprecated use - * {@link GregorianCalendar#GregorianCalendar(int, int, int)} - */ @Deprecated public Date(int year, int month, int day) { GregorianCalendar cal = new GregorianCalendar(false); @@ -82,24 +64,6 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Constructs a new {@code Date} initialized to the specified date and time in the - * default {@code TimeZone}. - * - * @param year - * the year, 0 is 1900. - * @param month - * the month, 0 - 11. - * @param day - * the day of the month, 1 - 31. - * @param hour - * the hour of day, 0 - 23. - * @param minute - * the minute of the hour, 0 - 59. - * - * @deprecated use - * {@link GregorianCalendar#GregorianCalendar(int, int, int, int, int)} - */ @Deprecated public Date(int year, int month, int day, int hour, int minute) { GregorianCalendar cal = new GregorianCalendar(false); @@ -107,26 +71,6 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Constructs a new {@code Date} initialized to the specified date and time in the - * default {@code TimeZone}. - * - * @param year - * the year, 0 is 1900. - * @param month - * the month, 0 - 11. - * @param day - * the day of the month, 1 - 31. - * @param hour - * the hour of day, 0 - 23. - * @param minute - * the minute of the hour, 0 - 59. - * @param second - * the second of the minute, 0 - 59. - * - * @deprecated use - * {@link GregorianCalendar#GregorianCalendar(int, int, int, int, int, int)} - */ @Deprecated public Date(int year, int month, int day, int hour, int minute, int second) { GregorianCalendar cal = new GregorianCalendar(false); @@ -134,62 +78,23 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Initializes this {@code Date} instance using the specified millisecond value. The - * value is the number of milliseconds since Jan. 1, 1970 GMT. - * - * @param milliseconds - * the number of milliseconds since Jan. 1, 1970 GMT. - */ public Date(long milliseconds) { this.milliseconds = milliseconds; } - /** - * Constructs a new {@code Date} initialized to the date and time parsed from the - * specified String. - * - * @param string - * the String to parse. - * - * @deprecated use {@link DateFormat} - */ @Deprecated public Date(String string) { milliseconds = parse(string); } - /** - * Returns if this {@code Date} is after the specified Date. - * - * @param date - * a Date instance to compare. - * @return {@code true} if this {@code Date} is after the specified {@code Date}, - * {@code false} otherwise. - */ public boolean after(Date date) { return milliseconds > date.milliseconds; } - /** - * Returns if this {@code Date} is before the specified Date. - * - * @param date - * a {@code Date} instance to compare. - * @return {@code true} if this {@code Date} is before the specified {@code Date}, - * {@code false} otherwise. - */ public boolean before(Date date) { return milliseconds < date.milliseconds; } - /** - * Returns a new {@code Date} with the same millisecond value as this {@code Date}. - * - * @return a shallow copy of this {@code Date}. - * - * @see java.lang.Cloneable - */ @Override public Object clone() { try { @@ -199,15 +104,6 @@ public class Date implements TSerializable, TCloneable, TComparable { } } - /** - * Compare the receiver to the specified {@code Date} to determine the relative - * ordering. - * - * @param date - * a {@code Date} to compare against. - * @return an {@code int < 0} if this {@code Date} is less than the specified {@code Date}, {@code 0} if - * they are equal, and an {@code int > 0} if this {@code Date} is greater. - */ public int compareTo(Date date) { if (milliseconds < date.milliseconds) { return -1; @@ -218,140 +114,56 @@ public class Date implements TSerializable, TCloneable, TComparable { return 1; } - /** - * Compares the specified object to this {@code Date} and returns if they are equal. - * To be equal, the object must be an instance of {@code Date} and have the same millisecond - * value. - * - * @param object - * the object to compare with this object. - * @return {@code true} if the specified object is equal to this {@code Date}, {@code false} - * otherwise. - * - * @see #hashCode - */ @Override public boolean equals(Object object) { - return (object == this) || (object instanceof Date) - && (milliseconds == ((Date) object).milliseconds); + return (object == this) || (object instanceof Date) && (milliseconds == ((Date) object).milliseconds); } - /** - * Returns the gregorian calendar day of the month for this {@code Date} object. - * - * @return the day of the month. - * - * @deprecated use {@code Calendar.get(Calendar.DATE)} - */ @Deprecated public int getDate() { return new GregorianCalendar(milliseconds).get(Calendar.DATE); } - /** - * Returns the gregorian calendar day of the week for this {@code Date} object. - * - * @return the day of the week. - * - * @deprecated use {@code Calendar.get(Calendar.DAY_OF_WEEK)} - */ @Deprecated public int getDay() { return new GregorianCalendar(milliseconds).get(Calendar.DAY_OF_WEEK) - 1; } - /** - * Returns the gregorian calendar hour of the day for this {@code Date} object. - * - * @return the hour of the day. - * - * @deprecated use {@code Calendar.get(Calendar.HOUR_OF_DAY)} - */ @Deprecated public int getHours() { return new GregorianCalendar(milliseconds).get(Calendar.HOUR_OF_DAY); } - /** - * Returns the gregorian calendar minute of the hour for this {@code Date} object. - * - * @return the minutes. - * - * @deprecated use {@code Calendar.get(Calendar.MINUTE)} - */ @Deprecated public int getMinutes() { return new GregorianCalendar(milliseconds).get(Calendar.MINUTE); } - /** - * Returns the gregorian calendar month for this {@code Date} object. - * - * @return the month. - * - * @deprecated use {@code Calendar.get(Calendar.MONTH)} - */ @Deprecated public int getMonth() { return new GregorianCalendar(milliseconds).get(Calendar.MONTH); } - /** - * Returns the gregorian calendar second of the minute for this {@code Date} object. - * - * @return the seconds. - * - * @deprecated use {@code Calendar.get(Calendar.SECOND)} - */ @Deprecated public int getSeconds() { return new GregorianCalendar(milliseconds).get(Calendar.SECOND); } - /** - * Returns this {@code Date} as a millisecond value. The value is the number of - * milliseconds since Jan. 1, 1970, midnight GMT. - * - * @return the number of milliseconds since Jan. 1, 1970, midnight GMT. - */ public long getTime() { return milliseconds; } - /** - * Returns the timezone offset in minutes of the default {@code TimeZone}. - * - * @return the timezone offset in minutes of the default {@code TimeZone}. - * - * @deprecated use - * {@code (Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / 60000} - */ @Deprecated public int getTimezoneOffset() { GregorianCalendar cal = new GregorianCalendar(milliseconds); return -(cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / 60000; } - /** - * Returns the gregorian calendar year since 1900 for this {@code Date} object. - * - * @return the year - 1900. - * - * @deprecated use {@code Calendar.get(Calendar.YEAR) - 1900} - */ @Deprecated public int getYear() { return new GregorianCalendar(milliseconds).get(Calendar.YEAR) - 1900; } - /** - * Returns an integer hash code for the receiver. Objects which are equal - * return the same value for this method. - * - * @return this {@code Date}'s hash. - * - * @see #equals - */ @Override public int hashCode() { return (int) (milliseconds >>> 32) ^ (int) milliseconds; @@ -366,23 +178,12 @@ public class Date implements TSerializable, TCloneable, TComparable { return -1; } - /** - * Returns the millisecond value of the date and time parsed from the - * specified {@code String}. Many date/time formats are recognized, including IETF - * standard syntax, i.e. Tue, 22 Jun 1999 12:16:00 GMT-0500 - * - * @param string - * the String to parse. - * @return the millisecond value parsed from the String. - * - * @deprecated use {@link DateFormat} - */ @Deprecated public static long parse(String string) { if (string == null) { // luni.06=The string argument is null - throw new IllegalArgumentException(Messages.getString("luni.06")); //$NON-NLS-1$ + throw new IllegalArgumentException(); } char sign = 0; @@ -428,11 +229,8 @@ public class Date implements TSerializable, TCloneable, TComparable { if (zoneOffset == 0) { zone = true; if (next == ':') { - minutesOffset = sign == '-' ? -Integer - .parseInt(string.substring(offset, - offset + 2)) : Integer - .parseInt(string.substring(offset, - offset + 2)); + minutesOffset = sign == '-' ? -Integer.parseInt(string.substring(offset, offset + 2)) + : Integer.parseInt(string.substring(offset, offset + 2)); offset += 2; } zoneOffset = sign == '-' ? -digit : digit; @@ -441,9 +239,7 @@ public class Date implements TSerializable, TCloneable, TComparable { throw new IllegalArgumentException(); } } else if (digit >= 70) { - if (year == -1 - && (Character.isSpace(next) || next == ',' - || next == '/' || next == '\r')) { + if (year == -1 && (Character.isSpace(next) || next == ',' || next == '/' || next == '\r')) { year = digit; } else { throw new IllegalArgumentException(); @@ -464,8 +260,7 @@ public class Date implements TSerializable, TCloneable, TComparable { } else { throw new IllegalArgumentException(); } - } else if (Character.isSpace(next) || next == ',' - || next == '-' || next == '\r') { + } else if (Character.isSpace(next) || next == ',' || next == '-' || next == '\r') { if (hour != -1 && minute == -1) { minute = digit; } else if (minute != -1 && second == -1) { @@ -502,15 +297,12 @@ public class Date implements TSerializable, TCloneable, TComparable { } hour += 12; } else { - DateFormatSymbols symbols = new DateFormatSymbols(Locale.US); - String[] weekdays = symbols.getWeekdays(), months = symbols - .getMonths(); + DateFormatSymbols symbols = new DateFormatSymbols(TLocale.US); + String[] weekdays = symbols.getWeekdays(), months = symbols.getMonths(); int value; if (parse(text, weekdays) != -1) {/* empty */ - } else if (month == -1 - && (month = parse(text, months)) != -1) {/* empty */ - } else if (text.equals("GMT") || text.equals("UT") //$NON-NLS-1$ //$NON-NLS-2$ - || text.equals("UTC")) { //$NON-NLS-1$ + } else if (month == -1 && (month = parse(text, months)) != -1) {/* empty */ + } else if (text.equals("GMT") || text.equals("UT") || text.equals("UTC")) { zone = true; zoneOffset = 0; } else if ((value = zone(text)) != 0) { @@ -524,8 +316,7 @@ public class Date implements TSerializable, TCloneable, TComparable { if (next == '+' || (year != -1 && next == '-')) { sign = next; - } else if (!Character.isSpace(next) && next != ',' - && nextState != NUMBERS) { + } else if (!Character.isSpace(next) && next != ',' && nextState != NUMBERS) { sign = 0; } @@ -560,20 +351,11 @@ public class Date implements TSerializable, TCloneable, TComparable { } return UTC(year - 1900, month, date, hour, minute, second); } - return new Date(year - 1900, month, date, hour, minute, second) - .getTime(); + return new Date(year - 1900, month, date, hour, minute, second).getTime(); } throw new IllegalArgumentException(); } - /** - * Sets the gregorian calendar day of the month for this {@code Date} object. - * - * @param day - * the day of the month. - * - * @deprecated use {@code Calendar.set(Calendar.DATE, day)} - */ @Deprecated public void setDate(int day) { GregorianCalendar cal = new GregorianCalendar(milliseconds); @@ -581,14 +363,6 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Sets the gregorian calendar hour of the day for this {@code Date} object. - * - * @param hour - * the hour of the day. - * - * @deprecated use {@code Calendar.set(Calendar.HOUR_OF_DAY, hour)} - */ @Deprecated public void setHours(int hour) { GregorianCalendar cal = new GregorianCalendar(milliseconds); @@ -596,14 +370,6 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Sets the gregorian calendar minute of the hour for this {@code Date} object. - * - * @param minute - * the minutes. - * - * @deprecated use {@code Calendar.set(Calendar.MINUTE, minute)} - */ @Deprecated public void setMinutes(int minute) { GregorianCalendar cal = new GregorianCalendar(milliseconds); @@ -611,14 +377,6 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Sets the gregorian calendar month for this {@code Date} object. - * - * @param month - * the month. - * - * @deprecated use {@code Calendar.set(Calendar.MONTH, month)} - */ @Deprecated public void setMonth(int month) { GregorianCalendar cal = new GregorianCalendar(milliseconds); @@ -626,14 +384,6 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Sets the gregorian calendar second of the minute for this {@code Date} object. - * - * @param second - * the seconds. - * - * @deprecated use {@code Calendar.set(Calendar.SECOND, second)} - */ @Deprecated public void setSeconds(int second) { GregorianCalendar cal = new GregorianCalendar(milliseconds); @@ -641,25 +391,10 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Sets this {@code Date} to the specified millisecond value. The value is the - * number of milliseconds since Jan. 1, 1970 GMT. - * - * @param milliseconds - * the number of milliseconds since Jan. 1, 1970 GMT. - */ public void setTime(long milliseconds) { this.milliseconds = milliseconds; } - /** - * Sets the gregorian calendar year since 1900 for this {@code Date} object. - * - * @param year - * the year since 1900. - * - * @deprecated use {@code Calendar.set(Calendar.YEAR, year + 1900)} - */ @Deprecated public void setYear(int year) { GregorianCalendar cal = new GregorianCalendar(milliseconds); @@ -667,52 +402,28 @@ public class Date implements TSerializable, TCloneable, TComparable { milliseconds = cal.getTimeInMillis(); } - /** - * Returns the string representation of this {@code Date} in GMT in the format: 22 - * Jun 1999 13:02:00 GMT - * - * @return the string representation of this {@code Date} in GMT. - * - * @deprecated use {@link DateFormat} - */ @Deprecated public String toGMTString() { - SimpleDateFormat format1 = new SimpleDateFormat("d MMM ", Locale.US); //$NON-NLS-1$ - SimpleDateFormat format2 = new SimpleDateFormat( - " HH:mm:ss 'GMT'", Locale.US); //$NON-NLS-1$ - TimeZone gmtZone = TimeZone.getTimeZone("GMT"); //$NON-NLS-1$ + SimpleDateFormat format1 = new SimpleDateFormat("d MMM ", TLocale.US); + SimpleDateFormat format2 = new SimpleDateFormat(" HH:mm:ss 'GMT'", TLocale.US); + TimeZone gmtZone = TimeZone.getTimeZone("GMT"); format1.setTimeZone(gmtZone); format2.setTimeZone(gmtZone); GregorianCalendar gc = new GregorianCalendar(gmtZone); gc.setTimeInMillis(milliseconds); - return format1.format(this) + gc.get(Calendar.YEAR) - + format2.format(this); + return format1.format(this) + gc.get(Calendar.YEAR) + format2.format(this); } - /** - * Returns the string representation of this {@code Date} for the default {@code Locale}. - * - * @return the string representation of this {@code Date} for the default {@code Locale}. - * - * @deprecated use {@link DateFormat} - */ @Deprecated public String toLocaleString() { return DateFormat.getDateTimeInstance().format(this); } - /** - * Returns the string representation of this {@code Date} in the format: Tue Jun 22 - * 13:07:00 GMT 1999 - * - * @return the string representation of this {@code Date}. - */ @Override public String toString() { Calendar cal = new GregorianCalendar(milliseconds); TimeZone zone = cal.getTimeZone(); - String zoneName = zone.getDisplayName(zone.inDaylightTime(this), - TimeZone.SHORT, Locale.getDefault()); + String zoneName = zone.getDisplayName(zone.inDaylightTime(this), TimeZone.SHORT, TLocale.getDefault()); StringBuilder sb = new StringBuilder(34); sb.append(dayOfWeekNames[cal.get(Calendar.DAY_OF_WEEK) - 1]); @@ -735,80 +446,46 @@ public class Date implements TSerializable, TCloneable, TComparable { } private String toTwoDigits(int digit) { - if(digit >= 10) { - return "" + digit;//$NON-NLS-1$ + if (digit >= 10) { + return "" + digit; } else { - return "0" + digit;//$NON-NLS-1$ + return "0" + digit; } } - /** - * Returns the millisecond value of the specified date and time in GMT. - * - * @param year - * the year, 0 is 1900. - * @param month - * the month, 0 - 11. - * @param day - * the day of the month, 1 - 31. - * @param hour - * the hour of day, 0 - 23. - * @param minute - * the minute of the hour, 0 - 59. - * @param second - * the second of the minute, 0 - 59. - * @return the date and time in GMT in milliseconds. - * - * @deprecated use: - * Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); - * cal.set(year + 1900, month, day, hour, minute, second); - * cal.getTime().getTime(); - */ @Deprecated - public static long UTC(int year, int month, int day, int hour, int minute, - int second) { + public static long UTC(int year, int month, int day, int hour, int minute, int second) { GregorianCalendar cal = new GregorianCalendar(false); - cal.setTimeZone(TimeZone.getTimeZone("GMT")); //$NON-NLS-1$ + cal.setTimeZone(TimeZone.getTimeZone("GMT")); cal.set(1900 + year, month, day, hour, minute, second); return cal.getTimeInMillis(); } private static int zone(String text) { - if (text.equals("EST")) { //$NON-NLS-1$ + if (text.equals("EST")) { return -5; } - if (text.equals("EDT")) { //$NON-NLS-1$ + if (text.equals("EDT")) { return -4; } - if (text.equals("CST")) { //$NON-NLS-1$ + if (text.equals("CST")) { return -6; } - if (text.equals("CDT")) { //$NON-NLS-1$ + if (text.equals("CDT")) { return -5; } - if (text.equals("MST")) { //$NON-NLS-1$ + if (text.equals("MST")) { return -7; } - if (text.equals("MDT")) { //$NON-NLS-1$ + if (text.equals("MDT")) { return -6; } - if (text.equals("PST")) { //$NON-NLS-1$ + if (text.equals("PST")) { return -8; } - if (text.equals("PDT")) { //$NON-NLS-1$ + if (text.equals("PDT")) { return -7; } return 0; } - - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.defaultWriteObject(); - stream.writeLong(getTime()); - } - - private void readObject(ObjectInputStream stream) throws IOException, - ClassNotFoundException { - stream.defaultReadObject(); - setTime(stream.readLong()); - } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java index 90ab6a763..426a2406c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java @@ -17,174 +17,7 @@ package org.teavm.classlib.java.util; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -/** - * {@code GregorianCalendar} is a concrete subclass of {@link Calendar} - * and provides the standard calendar used by most of the world. - * - *

- * The standard (Gregorian) calendar has 2 eras, BC and AD. - * - *

- * This implementation handles a single discontinuity, which corresponds by - * default to the date the Gregorian calendar was instituted (October 15, 1582 - * in some countries, later in others). The cutover date may be changed by the - * caller by calling {@code setGregorianChange()}. - * - *

- * Historically, in those countries which adopted the Gregorian calendar first, - * October 4, 1582 was thus followed by October 15, 1582. This calendar models - * this correctly. Before the Gregorian cutover, {@code GregorianCalendar} - * implements the Julian calendar. The only difference between the Gregorian and - * the Julian calendar is the leap year rule. The Julian calendar specifies leap - * years every four years, whereas the Gregorian calendar omits century years - * which are not divisible by 400. - * - *

- * {@code GregorianCalendar} implements proleptic Gregorian - * and Julian calendars. That is, dates are computed by extrapolating the - * current rules indefinitely far backward and forward in time. As a result, - * {@code GregorianCalendar} may be used for all years to generate - * meaningful and consistent results. However, dates obtained using - * {@code GregorianCalendar} are historically accurate only from March 1, - * 4 AD onward, when modern Julian calendar rules were adopted. Before this - * date, leap year rules were applied irregularly, and before 45 BC the Julian - * calendar did not even exist. - * - *

- * Prior to the institution of the Gregorian calendar, New Year's Day was March - * 25. To avoid confusion, this calendar always uses January 1. A manual - * adjustment may be made if desired for dates that are prior to the Gregorian - * changeover and which fall between January 1 and March 24. - * - *

- * Values calculated for the {@code WEEK_OF_YEAR} field range from 1 to - * 53. Week 1 for a year is the earliest seven day period starting on - * {@code getFirstDayOfWeek()} that contains at least - * {@code getMinimalDaysInFirstWeek()} days from that year. It thus - * depends on the values of {@code getMinimalDaysInFirstWeek()}, - * {@code getFirstDayOfWeek()}, and the day of the week of January 1. - * Weeks between week 1 of one year and week 1 of the following year are - * numbered sequentially from 2 to 52 or 53 (as needed). - * - *

- * For example, January 1, 1998 was a Thursday. If - * {@code getFirstDayOfWeek()} is {@code MONDAY} and - * {@code getMinimalDaysInFirstWeek()} is 4 (these are the values - * reflecting ISO 8601 and many national standards), then week 1 of 1998 starts - * on December 29, 1997, and ends on January 4, 1998. If, however, - * {@code getFirstDayOfWeek()} is {@code SUNDAY}, then week 1 of - * 1998 starts on January 4, 1998, and ends on January 10, 1998; the first three - * days of 1998 then are part of week 53 of 1997. - * - *

- * Values calculated for the {@code WEEK_OF_MONTH} field range from 0 or - * 1 to 4 or 5. Week 1 of a month (the days with WEEK_OF_MONTH = - * 1) - * is the earliest set of at least {@code getMinimalDaysInFirstWeek()} - * contiguous days in that month, ending on the day before - * {@code getFirstDayOfWeek()}. Unlike week 1 of a year, week 1 of a - * month may be shorter than 7 days, need not start on - * {@code getFirstDayOfWeek()}, and will not include days of the - * previous month. Days of a month before week 1 have a - * {@code WEEK_OF_MONTH} of 0. - * - *

- * For example, if {@code getFirstDayOfWeek()} is {@code SUNDAY} - * and {@code getMinimalDaysInFirstWeek()} is 4, then the first week of - * January 1998 is Sunday, January 4 through Saturday, January 10. These days - * have a {@code WEEK_OF_MONTH} of 1. Thursday, January 1 through - * Saturday, January 3 have a {@code WEEK_OF_MONTH} of 0. If - * {@code getMinimalDaysInFirstWeek()} is changed to 3, then January 1 - * through January 3 have a {@code WEEK_OF_MONTH} of 1. - * - *

- * Example:

- * - *
- * // get the supported ids for GMT-08:00 (Pacific Standard Time)
- * String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
- * // if no ids were returned, something is wrong. get out.
- * if (ids.length == 0)
- *     System.exit(0);
- *
- *  // begin output
- * System.out.println("Current Time");
- *
- * // create a Pacific Standard Time time zone
- * SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
- *
- * // set up rules for daylight savings time
- * pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
- * pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
- *
- * // create a GregorianCalendar with the Pacific Daylight time zone
- * // and the current date and time
- * Calendar calendar = new GregorianCalendar(pdt);
- * Date trialTime = new Date();
- * calendar.setTime(trialTime);
- *
- * // print out a bunch of interesting things
- * System.out.println("ERA: " + calendar.get(Calendar.ERA));
- * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
- * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
- * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
- * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
- * System.out.println("DATE: " + calendar.get(Calendar.DATE));
- * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
- * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
- * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
- * System.out.println("DAY_OF_WEEK_IN_MONTH: "
- *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
- * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
- * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
- * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
- * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
- * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
- * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
- * System.out.println("ZONE_OFFSET: "
- *                    + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000)));
- * System.out.println("DST_OFFSET: "
- *                    + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000)));
-
- * System.out.println("Current Time, with hour reset to 3");
- * calendar.clear(Calendar.HOUR_OF_DAY); // so doesn't override
- * calendar.set(Calendar.HOUR, 3);
- * System.out.println("ERA: " + calendar.get(Calendar.ERA));
- * System.out.println("YEAR: " + calendar.get(Calendar.YEAR));
- * System.out.println("MONTH: " + calendar.get(Calendar.MONTH));
- * System.out.println("WEEK_OF_YEAR: " + calendar.get(Calendar.WEEK_OF_YEAR));
- * System.out.println("WEEK_OF_MONTH: " + calendar.get(Calendar.WEEK_OF_MONTH));
- * System.out.println("DATE: " + calendar.get(Calendar.DATE));
- * System.out.println("DAY_OF_MONTH: " + calendar.get(Calendar.DAY_OF_MONTH));
- * System.out.println("DAY_OF_YEAR: " + calendar.get(Calendar.DAY_OF_YEAR));
- * System.out.println("DAY_OF_WEEK: " + calendar.get(Calendar.DAY_OF_WEEK));
- * System.out.println("DAY_OF_WEEK_IN_MONTH: "
- *                    + calendar.get(Calendar.DAY_OF_WEEK_IN_MONTH));
- * System.out.println("AM_PM: " + calendar.get(Calendar.AM_PM));
- * System.out.println("HOUR: " + calendar.get(Calendar.HOUR));
- * System.out.println("HOUR_OF_DAY: " + calendar.get(Calendar.HOUR_OF_DAY));
- * System.out.println("MINUTE: " + calendar.get(Calendar.MINUTE));
- * System.out.println("SECOND: " + calendar.get(Calendar.SECOND));
- * System.out.println("MILLISECOND: " + calendar.get(Calendar.MILLISECOND));
- * System.out.println("ZONE_OFFSET: "
- *        + (calendar.get(Calendar.ZONE_OFFSET)/(60*60*1000))); // in hours
- * System.out.println("DST_OFFSET: "
- *        + (calendar.get(Calendar.DST_OFFSET)/(60*60*1000))); // in hours
- * 
- * - *
- * - * @see Calendar - * @see TimeZone - */ public class GregorianCalendar extends Calendar { - - private static final long serialVersionUID = -8125100834729963327L; - /** * Value for the BC era. */ @@ -236,7 +69,7 @@ public class GregorianCalendar extends Calendar { * time with the default {@code Locale} and {@code TimeZone}. */ public GregorianCalendar() { - this(TimeZone.getDefault(), Locale.getDefault()); + this(TimeZone.getDefault(), TLocale.getDefault()); } /** @@ -251,7 +84,7 @@ public class GregorianCalendar extends Calendar { * the day of the month. */ public GregorianCalendar(int year, int month, int day) { - super(TimeZone.getDefault(), Locale.getDefault()); + super(TimeZone.getDefault(), TLocale.getDefault()); set(year, month, day); } @@ -271,7 +104,7 @@ public class GregorianCalendar extends Calendar { * the minute. */ public GregorianCalendar(int year, int month, int day, int hour, int minute) { - super(TimeZone.getDefault(), Locale.getDefault()); + super(TimeZone.getDefault(), TLocale.getDefault()); set(year, month, day, hour, minute); } @@ -294,7 +127,7 @@ public class GregorianCalendar extends Calendar { */ public GregorianCalendar(int year, int month, int day, int hour, int minute, int second) { - super(TimeZone.getDefault(), Locale.getDefault()); + super(TimeZone.getDefault(), TLocale.getDefault()); set(year, month, day, hour, minute, second); } @@ -310,7 +143,7 @@ public class GregorianCalendar extends Calendar { * @param locale * the {@code Locale}. */ - public GregorianCalendar(Locale locale) { + public GregorianCalendar(TLocale locale) { this(TimeZone.getDefault(), locale); } @@ -322,7 +155,7 @@ public class GregorianCalendar extends Calendar { * the {@code TimeZone}. */ public GregorianCalendar(TimeZone timezone) { - this(timezone, Locale.getDefault()); + this(timezone, TLocale.getDefault()); } /** @@ -334,12 +167,12 @@ public class GregorianCalendar extends Calendar { * @param locale * the {@code Locale}. */ - public GregorianCalendar(TimeZone timezone, Locale locale) { + public GregorianCalendar(TimeZone timezone, TLocale locale) { super(timezone, locale); setTimeInMillis(System.currentTimeMillis()); } - GregorianCalendar(boolean ignored) { + GregorianCalendar(@SuppressWarnings("unused") boolean ignored) { super(TimeZone.getDefault()); setFirstDayOfWeek(SUNDAY); setMinimalDaysInFirstWeek(1); @@ -1413,18 +1246,6 @@ public class GregorianCalendar extends Calendar { isCached = false; } - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.defaultWriteObject(); - } - - private void readObject(ObjectInputStream stream) throws IOException, - ClassNotFoundException { - - stream.defaultReadObject(); - setGregorianChange(new Date(gregorianCutover)); - isCached = false; - } - @Override public void setFirstDayOfWeek(int value) { super.setFirstDayOfWeek(value); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java index 98a7f288e..edb563faa 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java @@ -17,33 +17,8 @@ package org.teavm.classlib.java.util; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamField; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import org.apache.harmony.luni.internal.nls.Messages; - -/** - * {@code SimpleTimeZone} is a concrete subclass of {@code TimeZone} - * that represents a time zone for use with a Gregorian calendar. This class - * does not handle historical changes. - *

- * Use a negative value for {@code dayOfWeekInMonth} to indicate that - * {@code SimpleTimeZone} should count from the end of the month - * backwards. For example, Daylight Savings Time ends at the last - * (dayOfWeekInMonth = -1) Sunday in October, at 2 AM in standard time. - * - * @see Calendar - * @see GregorianCalendar - * @see TimeZone - */ public class SimpleTimeZone extends TimeZone { - private static final long serialVersionUID = -403250971215465050L; - private int rawOffset; private int startYear, startMonth, startDay, startDayOfWeek, startTime; @@ -52,26 +27,12 @@ public class SimpleTimeZone extends TimeZone { private int startMode, endMode; - private static final int DOM_MODE = 1, DOW_IN_MONTH_MODE = 2, - DOW_GE_DOM_MODE = 3, DOW_LE_DOM_MODE = 4; + private static final int DOM_MODE = 1, DOW_IN_MONTH_MODE = 2, DOW_GE_DOM_MODE = 3, DOW_LE_DOM_MODE = 4; - /** - * The constant for representing a start or end time in GMT time mode. - */ public static final int UTC_TIME = 2; - /** - * The constant for representing a start or end time in standard local time mode, - * based on timezone's raw offset from GMT; does not include Daylight - * savings. - */ public static final int STANDARD_TIME = 1; - /** - * The constant for representing a start or end time in local wall clock time - * mode, based on timezone's adjusted offset from GMT; includes - * Daylight savings. - */ public static final int WALL_TIME = 0; private boolean useDaylight; @@ -80,22 +41,8 @@ public class SimpleTimeZone extends TimeZone { private int dstSavings = 3600000; - private final transient com.ibm.icu.util.TimeZone icuTZ; - private final transient boolean isSimple; - /** - * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT - * and time zone ID. Timezone IDs can be obtained from - * {@code TimeZone.getAvailableIDs}. Normally you should use {@code TimeZone.getDefault} to - * construct a {@code TimeZone}. - * - * @param offset - * the given base time zone offset to GMT. - * @param name - * the time zone ID which is obtained from - * {@code TimeZone.getAvailableIDs}. - */ public SimpleTimeZone(int offset, final String name) { setID(name); rawOffset = offset; @@ -109,131 +56,18 @@ public class SimpleTimeZone extends TimeZone { useDaylight = icuTZ.useDaylightTime(); } - /** - * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT, - * time zone ID, and times to start and end the daylight savings time. Timezone IDs can - * be obtained from {@code TimeZone.getAvailableIDs}. Normally you should use - * {@code TimeZone.getDefault} to create a {@code TimeZone}. For a time zone that does not - * use daylight saving time, do not use this constructor; instead you should - * use {@code SimpleTimeZone(rawOffset, ID)}. - *

- * By default, this constructor specifies day-of-week-in-month rules. That - * is, if the {@code startDay} is 1, and the {@code startDayOfWeek} is {@code SUNDAY}, then this - * indicates the first Sunday in the {@code startMonth}. A {@code startDay} of -1 likewise - * indicates the last Sunday. However, by using negative or zero values for - * certain parameters, other types of rules can be specified. - *

- * Day of month: To specify an exact day of the month, such as March 1, set - * {@code startDayOfWeek} to zero. - *

- * Day of week after day of month: To specify the first day of the week - * occurring on or after an exact day of the month, make the day of the week - * negative. For example, if {@code startDay} is 5 and {@code startDayOfWeek} is {@code -MONDAY}, - * this indicates the first Monday on or after the 5th day of the - * {@code startMonth}. - *

- * Day of week before day of month: To specify the last day of the week - * occurring on or before an exact day of the month, make the day of the - * week and the day of the month negative. For example, if {@code startDay} is {@code -21} - * and {@code startDayOfWeek} is {@code -WEDNESDAY}, this indicates the last Wednesday on or - * before the 21st of the {@code startMonth}. - *

- * The above examples refer to the {@code startMonth}, {@code startDay}, and {@code startDayOfWeek}; - * the same applies for the {@code endMonth}, {@code endDay}, and {@code endDayOfWeek}. - *

- * The daylight savings time difference is set to the default value: one hour. - * - * @param offset - * the given base time zone offset to GMT. - * @param name - * the time zone ID which is obtained from - * {@code TimeZone.getAvailableIDs}. - * @param startMonth - * the daylight savings starting month. The month indexing is 0-based. eg, 0 - * for January. - * @param startDay - * the daylight savings starting day-of-week-in-month. Please see - * the member description for an example. - * @param startDayOfWeek - * the daylight savings starting day-of-week. Please see the - * member description for an example. - * @param startTime - * the daylight savings starting time in local wall time, which - * is standard time in this case. Please see the member - * description for an example. - * @param endMonth - * the daylight savings ending month. The month indexing is 0-based. eg, 0 for - * January. - * @param endDay - * the daylight savings ending day-of-week-in-month. Please see - * the member description for an example. - * @param endDayOfWeek - * the daylight savings ending day-of-week. Please see the member - * description for an example. - * @param endTime - * the daylight savings ending time in local wall time, which is - * daylight time in this case. Please see the member description - * for an example. - * @throws IllegalArgumentException - * if the month, day, dayOfWeek, or time parameters are out of - * range for the start or end rule. - */ - public SimpleTimeZone(int offset, String name, int startMonth, - int startDay, int startDayOfWeek, int startTime, int endMonth, - int endDay, int endDayOfWeek, int endTime) { - this(offset, name, startMonth, startDay, startDayOfWeek, startTime, - endMonth, endDay, endDayOfWeek, endTime, 3600000); + public SimpleTimeZone(int offset, String name, int startMonth, int startDay, int startDayOfWeek, int startTime, + int endMonth, int endDay, int endDayOfWeek, int endTime) { + this(offset, name, startMonth, startDay, startDayOfWeek, startTime, endMonth, endDay, endDayOfWeek, endTime, + 3600000); } - /** - * Constructs a {@code SimpleTimeZone} with the given base time zone offset from GMT, - * time zone ID, times to start and end the daylight savings time, and - * the daylight savings time difference in milliseconds. - * - * @param offset - * the given base time zone offset to GMT. - * @param name - * the time zone ID which is obtained from - * {@code TimeZone.getAvailableIDs}. - * @param startMonth - * the daylight savings starting month. Month is 0-based. eg, 0 - * for January. - * @param startDay - * the daylight savings starting day-of-week-in-month. Please see - * the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. - * @param startDayOfWeek - * the daylight savings starting day-of-week. Please see the - * description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. - * @param startTime - * The daylight savings starting time in local wall time, which - * is standard time in this case. Please see the description of - * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. - * @param endMonth - * the daylight savings ending month. Month is 0-based. eg, 0 for - * January. - * @param endDay - * the daylight savings ending day-of-week-in-month. Please see - * the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. - * @param endDayOfWeek - * the daylight savings ending day-of-week. Please see the description of - * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. - * @param endTime - * the daylight savings ending time in local wall time, which is - * daylight time in this case. Please see the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} - * for an example. - * @param daylightSavings - * the daylight savings time difference in milliseconds. - * @throws IllegalArgumentException - * if the month, day, dayOfWeek, or time parameters are out of - * range for the start or end rule. - */ - public SimpleTimeZone(int offset, String name, int startMonth, - int startDay, int startDayOfWeek, int startTime, int endMonth, - int endDay, int endDayOfWeek, int endTime, int daylightSavings) { + public SimpleTimeZone(int offset, String name, int startMonth, int startDay, int startDayOfWeek, int startTime, + int endMonth, int endDay, int endDayOfWeek, int endTime, int daylightSavings) { icuTZ = getICUTimeZone(name); if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) { isSimple = true; - com.ibm.icu.util.SimpleTimeZone tz = (com.ibm.icu.util.SimpleTimeZone)icuTZ; + com.ibm.icu.util.SimpleTimeZone tz = (com.ibm.icu.util.SimpleTimeZone) icuTZ; tz.setRawOffset(offset); tz.setStartRule(startMonth, startDay, startDayOfWeek, startTime); tz.setEndRule(endMonth, endDay, endDayOfWeek, endTime); @@ -244,8 +78,7 @@ public class SimpleTimeZone extends TimeZone { setID(name); rawOffset = offset; if (daylightSavings <= 0) { - throw new IllegalArgumentException(Messages.getString( - "luni.3B", daylightSavings)); //$NON-NLS-1$ + throw new IllegalArgumentException(String.valueOf(daylightSavings)); } dstSavings = daylightSavings; @@ -255,70 +88,16 @@ public class SimpleTimeZone extends TimeZone { useDaylight = daylightSavings > 0 || icuTZ.useDaylightTime(); } - /** - * Construct a {@code SimpleTimeZone} with the given base time zone offset from GMT, - * time zone ID, times to start and end the daylight savings time including a - * mode specifier, the daylight savings time difference in milliseconds. - * The mode specifies either {@link #WALL_TIME}, {@link #STANDARD_TIME}, or - * {@link #UTC_TIME}. - * - * @param offset - * the given base time zone offset to GMT. - * @param name - * the time zone ID which is obtained from - * {@code TimeZone.getAvailableIDs}. - * @param startMonth - * the daylight savings starting month. The month indexing is 0-based. eg, 0 - * for January. - * @param startDay - * the daylight savings starting day-of-week-in-month. Please see - * the description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. - * @param startDayOfWeek - * the daylight savings starting day-of-week. Please see the - * description of {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. - * @param startTime - * the time of day in milliseconds on which daylight savings - * time starts, based on the {@code startTimeMode}. - * @param startTimeMode - * the mode (UTC, standard, or wall time) of the start time - * value. - * @param endDay - * the day of the week on which daylight savings time ends. - * @param endMonth - * the daylight savings ending month. The month indexing is 0-based. eg, 0 for - * January. - * @param endDayOfWeek - * the daylight savings ending day-of-week. Please see the description of - * {@link #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)} for an example. - * @param endTime - * the time of day in milliseconds on which daylight savings - * time ends, based on the {@code endTimeMode}. - * @param endTimeMode - * the mode (UTC, standard, or wall time) of the end time value. - * @param daylightSavings - * the daylight savings time difference in milliseconds. - * @throws IllegalArgumentException - * if the month, day, dayOfWeek, or time parameters are out of - * range for the start or end rule. - */ - public SimpleTimeZone(int offset, String name, int startMonth, - int startDay, int startDayOfWeek, int startTime, int startTimeMode, - int endMonth, int endDay, int endDayOfWeek, int endTime, - int endTimeMode, int daylightSavings) { + public SimpleTimeZone(int offset, String name, int startMonth, int startDay, int startDayOfWeek, int startTime, + int startTimeMode, int endMonth, int endDay, int endDayOfWeek, int endTime, int endTimeMode, + int daylightSavings) { - this(offset, name, startMonth, startDay, startDayOfWeek, startTime, - endMonth, endDay, endDayOfWeek, endTime, daylightSavings); + this(offset, name, startMonth, startDay, startDayOfWeek, startTime, endMonth, endDay, endDayOfWeek, endTime, + daylightSavings); startMode = startTimeMode; endMode = endTimeMode; } - /** - * Returns a new {@code SimpleTimeZone} with the same ID, {@code rawOffset} and daylight - * savings time rules as this SimpleTimeZone. - * - * @return a shallow copy of this {@code SimpleTimeZone}. - * @see java.lang.Cloneable - */ @Override public Object clone() { SimpleTimeZone zone = (SimpleTimeZone) super.clone(); @@ -328,34 +107,19 @@ public class SimpleTimeZone extends TimeZone { return zone; } - /** - * Compares the specified object to this {@code SimpleTimeZone} and returns whether they - * are equal. The object must be an instance of {@code SimpleTimeZone} and have the - * same internal data. - * - * @param object - * the object to compare with this object. - * @return {@code true} if the specified object is equal to this - * {@code SimpleTimeZone}, {@code false} otherwise. - * @see #hashCode - */ @Override public boolean equals(Object object) { if (!(object instanceof SimpleTimeZone)) { return false; } SimpleTimeZone tz = (SimpleTimeZone) object; - return getID().equals(tz.getID()) - && rawOffset == tz.rawOffset - && useDaylight == tz.useDaylight - && (!useDaylight || (startYear == tz.startYear - && startMonth == tz.startMonth - && startDay == tz.startDay && startMode == tz.startMode - && startDayOfWeek == tz.startDayOfWeek - && startTime == tz.startTime && endMonth == tz.endMonth - && endDay == tz.endDay - && endDayOfWeek == tz.endDayOfWeek - && endTime == tz.endTime && endMode == tz.endMode && dstSavings == tz.dstSavings)); + return getID().equals(tz.getID()) && + rawOffset == tz.rawOffset && + useDaylight == tz.useDaylight && + (!useDaylight || (startYear == tz.startYear && startMonth == tz.startMonth && startDay == tz.startDay && + startMode == tz.startMode && startDayOfWeek == tz.startDayOfWeek && startTime == tz.startTime && + endMonth == tz.endMonth && endDay == tz.endDay && endDayOfWeek == tz.endDayOfWeek && + endTime == tz.endTime && endMode == tz.endMode && dstSavings == tz.dstSavings)); } @Override @@ -367,10 +131,9 @@ public class SimpleTimeZone extends TimeZone { } @Override - public int getOffset(int era, int year, int month, int day, int dayOfWeek, - int time) { + public int getOffset(int era, int year, int month, int day, int dayOfWeek, int time) { if (era != GregorianCalendar.BC && era != GregorianCalendar.AD) { - throw new IllegalArgumentException(Messages.getString("luni.3C", era)); //$NON-NLS-1$ + throw new IllegalArgumentException(String.valueOf(era)); } checkRange(month, dayOfWeek, time); if (month != Calendar.FEBRUARY || day != 29 || !isLeapYear(year)) { @@ -389,20 +152,12 @@ public class SimpleTimeZone extends TimeZone { return rawOffset; } - /** - * Returns an integer hash code for the receiver. Objects which are equal - * return the same value for this method. - * - * @return the receiver's hash. - * @see #equals - */ @Override public synchronized int hashCode() { int hashCode = getID().hashCode() + rawOffset; if (useDaylight) { - hashCode += startYear + startMonth + startDay + startDayOfWeek - + startTime + startMode + endMonth + endDay + endDayOfWeek - + endTime + endMode + dstSavings; + hashCode += startYear + startMonth + startDay + startDayOfWeek + startTime + startMode + endMonth + endDay + + endDayOfWeek + endTime + endMode + dstSavings; } return hashCode; } @@ -419,13 +174,11 @@ public class SimpleTimeZone extends TimeZone { if (!useDaylight) { return rawOffset == tz.rawOffset; } - return rawOffset == tz.rawOffset && dstSavings == tz.dstSavings - && startYear == tz.startYear && startMonth == tz.startMonth - && startDay == tz.startDay && startMode == tz.startMode - && startDayOfWeek == tz.startDayOfWeek - && startTime == tz.startTime && endMonth == tz.endMonth - && endDay == tz.endDay && endDayOfWeek == tz.endDayOfWeek - && endTime == tz.endTime && endMode == tz.endMode; + return rawOffset == tz.rawOffset && dstSavings == tz.dstSavings && startYear == tz.startYear && + startMonth == tz.startMonth && startDay == tz.startDay && startMode == tz.startMode && + startDayOfWeek == tz.startDayOfWeek && startTime == tz.startTime && endMonth == tz.endMonth && + endDay == tz.endDay && endDayOfWeek == tz.endDayOfWeek && endTime == tz.endTime && + endMode == tz.endMode; } @Override @@ -440,12 +193,6 @@ public class SimpleTimeZone extends TimeZone { return year % 4 == 0; } - /** - * Sets the daylight savings offset in milliseconds for this {@code SimpleTimeZone}. - * - * @param milliseconds - * the daylight savings offset in milliseconds. - */ public void setDSTSavings(int milliseconds) { if (milliseconds > 0) { dstSavings = milliseconds; @@ -456,20 +203,19 @@ public class SimpleTimeZone extends TimeZone { private void checkRange(int month, int dayOfWeek, int time) { if (month < Calendar.JANUARY || month > Calendar.DECEMBER) { - throw new IllegalArgumentException(Messages.getString("luni.3D", month)); //$NON-NLS-1$ + throw new IllegalArgumentException(String.valueOf(month)); } if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) { - throw new IllegalArgumentException(Messages - .getString("luni.48", dayOfWeek)); //$NON-NLS-1$ + throw new IllegalArgumentException(String.valueOf(dayOfWeek)); } if (time < 0 || time >= 24 * 3600000) { - throw new IllegalArgumentException(Messages.getString("luni.3E", time)); //$NON-NLS-1$ + throw new IllegalArgumentException(String.valueOf(time)); } } private void checkDay(int month, int day) { if (day <= 0 || day > GregorianCalendar.DaysInMonth[month]) { - throw new IllegalArgumentException(Messages.getString("luni.3F", day)); //$NON-NLS-1$ + throw new IllegalArgumentException(String.valueOf(day)); } } @@ -489,14 +235,12 @@ public class SimpleTimeZone extends TimeZone { } useDaylight = startDay != 0 && endDay != 0; if (endDay != 0) { - checkRange(endMonth, endMode == DOM_MODE ? 1 : endDayOfWeek, - endTime); + checkRange(endMonth, endMode == DOM_MODE ? 1 : endDayOfWeek, endTime); if (endMode != DOW_IN_MONTH_MODE) { checkDay(endMonth, endDay); } else { if (endDay < -5 || endDay > 5) { - throw new IllegalArgumentException(Messages.getString( - "luni.40", endDay)); //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("luni.40", endDay)); //$NON-NLS-1$ } } } @@ -505,18 +249,6 @@ public class SimpleTimeZone extends TimeZone { } } - /** - * Sets the rule which specifies the end of daylight savings time. - * - * @param month - * the {@code Calendar} month in which daylight savings time ends. - * @param dayOfMonth - * the {@code Calendar} day of the month on which daylight savings time - * ends. - * @param time - * the time of day in milliseconds standard time on which - * daylight savings time ends. - */ public void setEndRule(int month, int dayOfMonth, int time) { endMonth = month; endDay = dayOfMonth; @@ -524,26 +256,10 @@ public class SimpleTimeZone extends TimeZone { endTime = time; setEndMode(); if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, - dayOfMonth, time); + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, dayOfMonth, time); } } - /** - * Sets the rule which specifies the end of daylight savings time. - * - * @param month - * the {@code Calendar} month in which daylight savings time ends. - * @param day - * the occurrence of the day of the week on which daylight - * savings time ends. - * @param dayOfWeek - * the {@code Calendar} day of the week on which daylight savings time - * ends. - * @param time - * the time of day in milliseconds standard time on which - * daylight savings time ends. - */ public void setEndRule(int month, int day, int dayOfWeek, int time) { endMonth = month; endDay = day; @@ -551,46 +267,21 @@ public class SimpleTimeZone extends TimeZone { endTime = time; setEndMode(); if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, - dayOfWeek, time); + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, dayOfWeek, time); } } - /** - * Sets the rule which specifies the end of daylight savings time. - * - * @param month - * the {@code Calendar} month in which daylight savings time ends. - * @param day - * the {@code Calendar} day of the month. - * @param dayOfWeek - * the {@code Calendar} day of the week on which daylight savings time - * ends. - * @param time - * the time of day in milliseconds on which daylight savings time - * ends. - * @param after - * selects the day after or before the day of month. - */ - public void setEndRule(int month, int day, int dayOfWeek, int time, - boolean after) { + public void setEndRule(int month, int day, int dayOfWeek, int time, boolean after) { endMonth = month; endDay = after ? day : -day; endDayOfWeek = -dayOfWeek; endTime = time; setEndMode(); if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, - dayOfWeek, time, after); + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, dayOfWeek, time, after); } } - /** - * Sets the offset for standard time from GMT for this {@code SimpleTimeZone}. - * - * @param offset - * the offset from GMT of standard time in milliseconds. - */ @Override public void setRawOffset(int offset) { rawOffset = offset; @@ -613,14 +304,12 @@ public class SimpleTimeZone extends TimeZone { } useDaylight = startDay != 0 && endDay != 0; if (startDay != 0) { - checkRange(startMonth, startMode == DOM_MODE ? 1 : startDayOfWeek, - startTime); + checkRange(startMonth, startMode == DOM_MODE ? 1 : startDayOfWeek, startTime); if (startMode != DOW_IN_MONTH_MODE) { checkDay(startMonth, startDay); } else { if (startDay < -5 || startDay > 5) { - throw new IllegalArgumentException(Messages.getString( - "luni.40", startDay)); //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("luni.40", startDay)); //$NON-NLS-1$ } } } @@ -629,18 +318,6 @@ public class SimpleTimeZone extends TimeZone { } } - /** - * Sets the rule which specifies the start of daylight savings time. - * - * @param month - * the {@code Calendar} month in which daylight savings time starts. - * @param dayOfMonth - * the {@code Calendar} day of the month on which daylight savings time - * starts. - * @param time - * the time of day in milliseconds on which daylight savings time - * starts. - */ public void setStartRule(int month, int dayOfMonth, int time) { startMonth = month; startDay = dayOfMonth; @@ -648,26 +325,10 @@ public class SimpleTimeZone extends TimeZone { startTime = time; setStartMode(); if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, - dayOfMonth, time); + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, dayOfMonth, time); } } - /** - * Sets the rule which specifies the start of daylight savings time. - * - * @param month - * the {@code Calendar} month in which daylight savings time starts. - * @param day - * the occurrence of the day of the week on which daylight - * savings time starts. - * @param dayOfWeek - * the {@code Calendar} day of the week on which daylight savings time - * starts. - * @param time - * the time of day in milliseconds on which daylight savings time - * starts. - */ public void setStartRule(int month, int day, int dayOfWeek, int time) { startMonth = month; startDay = day; @@ -675,199 +336,38 @@ public class SimpleTimeZone extends TimeZone { startTime = time; setStartMode(); if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, - dayOfWeek, time); + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, dayOfWeek, time); } } - /** - * Sets the rule which specifies the start of daylight savings time. - * - * @param month - * the {@code Calendar} month in which daylight savings time starts. - * @param day - * the {@code Calendar} day of the month. - * @param dayOfWeek - * the {@code Calendar} day of the week on which daylight savings time - * starts. - * @param time - * the time of day in milliseconds on which daylight savings time - * starts. - * @param after - * selects the day after or before the day of month. - */ - public void setStartRule(int month, int day, int dayOfWeek, int time, - boolean after) { + public void setStartRule(int month, int day, int dayOfWeek, int time, boolean after) { startMonth = month; startDay = after ? day : -day; startDayOfWeek = -dayOfWeek; startTime = time; setStartMode(); if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, - dayOfWeek, time, after); + ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, dayOfWeek, time, after); } } - /** - * Sets the starting year for daylight savings time in this {@code SimpleTimeZone}. - * Years before this start year will always be in standard time. - * - * @param year - * the starting year. - */ public void setStartYear(int year) { startYear = year; useDaylight = true; } - /** - * Returns the string representation of this {@code SimpleTimeZone}. - * - * @return the string representation of this {@code SimpleTimeZone}. - */ @Override public String toString() { - return getClass().getName() - + "[id=" //$NON-NLS-1$ - + getID() - + ",offset=" //$NON-NLS-1$ - + rawOffset - + ",dstSavings=" //$NON-NLS-1$ - + dstSavings - + ",useDaylight=" //$NON-NLS-1$ - + useDaylight - + ",startYear=" //$NON-NLS-1$ - + startYear - + ",startMode=" //$NON-NLS-1$ - + startMode - + ",startMonth=" //$NON-NLS-1$ - + startMonth - + ",startDay=" //$NON-NLS-1$ - + startDay - + ",startDayOfWeek=" //$NON-NLS-1$ - + (useDaylight && (startMode != DOM_MODE) ? startDayOfWeek + 1 - : 0) + ",startTime=" + startTime + ",endMode=" //$NON-NLS-1$ //$NON-NLS-2$ - + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay //$NON-NLS-1$ //$NON-NLS-2$ - + ",endDayOfWeek=" //$NON-NLS-1$ - + (useDaylight && (endMode != DOM_MODE) ? endDayOfWeek + 1 : 0) - + ",endTime=" + endTime + "]"; //$NON-NLS-1$//$NON-NLS-2$ + return getClass().getName() + "[id=" + getID() + ",offset=" + rawOffset + ",dstSavings=" + dstSavings + + ",useDaylight=" + useDaylight + ",startYear=" + startYear + ",startMode=" + startMode + ",startMonth=" + + startMonth + ",startDay=" + startDay + ",startDayOfWeek=" + + (useDaylight && (startMode != DOM_MODE) ? startDayOfWeek + 1 : 0) + ",startTime=" + startTime + + ",endMode=" + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay + ",endDayOfWeek=" + + (useDaylight && (endMode != DOM_MODE) ? endDayOfWeek + 1 : 0) + ",endTime=" + endTime + "]"; } @Override public boolean useDaylightTime() { return useDaylight; } - - private static final ObjectStreamField[] serialPersistentFields = { - new ObjectStreamField("dstSavings", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("endDay", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("endDayOfWeek", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("endMode", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("endMonth", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("endTime", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("monthLength", byte[].class), //$NON-NLS-1$ - new ObjectStreamField("rawOffset", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("serialVersionOnStream", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("startDay", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("startDayOfWeek", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("startMode", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("startMonth", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("startTime", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("startYear", Integer.TYPE), //$NON-NLS-1$ - new ObjectStreamField("useDaylight", Boolean.TYPE), }; //$NON-NLS-1$ - - private void writeObject(ObjectOutputStream stream) throws IOException { - int sEndDay = endDay, sEndDayOfWeek = endDayOfWeek + 1, sStartDay = startDay, sStartDayOfWeek = startDayOfWeek + 1; - if (useDaylight - && (startMode != DOW_IN_MONTH_MODE || endMode != DOW_IN_MONTH_MODE)) { - Calendar cal = new GregorianCalendar(this); - if (endMode != DOW_IN_MONTH_MODE) { - cal.set(Calendar.MONTH, endMonth); - cal.set(Calendar.DATE, endDay); - sEndDay = cal.get(Calendar.DAY_OF_WEEK_IN_MONTH); - if (endMode == DOM_MODE) { - sEndDayOfWeek = cal.getFirstDayOfWeek(); - } - } - if (startMode != DOW_IN_MONTH_MODE) { - cal.set(Calendar.MONTH, startMonth); - cal.set(Calendar.DATE, startDay); - sStartDay = cal.get(Calendar.DAY_OF_WEEK_IN_MONTH); - if (startMode == DOM_MODE) { - sStartDayOfWeek = cal.getFirstDayOfWeek(); - } - } - } - ObjectOutputStream.PutField fields = stream.putFields(); - fields.put("dstSavings", dstSavings); //$NON-NLS-1$ - fields.put("endDay", sEndDay); //$NON-NLS-1$ - fields.put("endDayOfWeek", sEndDayOfWeek); //$NON-NLS-1$ - fields.put("endMode", endMode); //$NON-NLS-1$ - fields.put("endMonth", endMonth); //$NON-NLS-1$ - fields.put("endTime", endTime); //$NON-NLS-1$ - fields.put("monthLength", GregorianCalendar.DaysInMonth); //$NON-NLS-1$ - fields.put("rawOffset", rawOffset); //$NON-NLS-1$ - fields.put("serialVersionOnStream", 1); //$NON-NLS-1$ - fields.put("startDay", sStartDay); //$NON-NLS-1$ - fields.put("startDayOfWeek", sStartDayOfWeek); //$NON-NLS-1$ - fields.put("startMode", startMode); //$NON-NLS-1$ - fields.put("startMonth", startMonth); //$NON-NLS-1$ - fields.put("startTime", startTime); //$NON-NLS-1$ - fields.put("startYear", startYear); //$NON-NLS-1$ - fields.put("useDaylight", useDaylight); //$NON-NLS-1$ - stream.writeFields(); - stream.writeInt(4); - byte[] values = new byte[4]; - values[0] = (byte) startDay; - values[1] = (byte) (startMode == DOM_MODE ? 0 : startDayOfWeek + 1); - values[2] = (byte) endDay; - values[3] = (byte) (endMode == DOM_MODE ? 0 : endDayOfWeek + 1); - stream.write(values); - } - - private void readObject(ObjectInputStream stream) throws IOException, - ClassNotFoundException { - ObjectInputStream.GetField fields = stream.readFields(); - rawOffset = fields.get("rawOffset", 0); //$NON-NLS-1$ - useDaylight = fields.get("useDaylight", false); //$NON-NLS-1$ - if (useDaylight) { - endMonth = fields.get("endMonth", 0); //$NON-NLS-1$ - endTime = fields.get("endTime", 0); //$NON-NLS-1$ - startMonth = fields.get("startMonth", 0); //$NON-NLS-1$ - startTime = fields.get("startTime", 0); //$NON-NLS-1$ - startYear = fields.get("startYear", 0); //$NON-NLS-1$ - } - if (fields.get("serialVersionOnStream", 0) == 0) { //$NON-NLS-1$ - if (useDaylight) { - startMode = endMode = DOW_IN_MONTH_MODE; - endDay = fields.get("endDay", 0); //$NON-NLS-1$ - endDayOfWeek = fields.get("endDayOfWeek", 0) - 1; //$NON-NLS-1$ - startDay = fields.get("startDay", 0); //$NON-NLS-1$ - startDayOfWeek = fields.get("startDayOfWeek", 0) - 1; //$NON-NLS-1$ - } - } else { - dstSavings = fields.get("dstSavings", 0); //$NON-NLS-1$ - if (useDaylight) { - endMode = fields.get("endMode", 0); //$NON-NLS-1$ - startMode = fields.get("startMode", 0); //$NON-NLS-1$ - int length = stream.readInt(); - byte[] values = new byte[length]; - stream.readFully(values); - if (length >= 4) { - startDay = values[0]; - startDayOfWeek = values[1]; - if (startMode != DOM_MODE) { - startDayOfWeek--; - } - endDay = values[2]; - endDayOfWeek = values[3]; - if (endMode != DOM_MODE) { - endDayOfWeek--; - } - } - } - } - } - } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java index c5691e1a9..323727add 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java @@ -32,26 +32,14 @@ package org.teavm.classlib.java.util; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.lang.TCloneable; public abstract class TimeZone implements TSerializable, TCloneable { 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 THashMap AvailableZones; @@ -89,29 +77,16 @@ public abstract class TimeZone implements TSerializable, TCloneable { } public static synchronized String[] getAvailableIDs(int offset) { - List result = new ArrayList<>(); - for (TIterator iter = AvailableZones.values().iterator(); iter.hasNext()) { - if () - } - return Arrays.copyOf(result, j); - int count = 0; - int length = availableIDs.length; - String[] all = new String[length]; - for (int i = 0; i < length; i++) { + TList result = new TArrayList<>(); + for (TIterator iter = AvailableZones.values().iterator(); iter.hasNext();) { + TimeZone tz = iter.next(); if (tz.getRawOffset() == offset) { - all[count++] = tz.getID(); + result.add(tz.getID()); } } - String[] answer = new String[count]; - System.arraycopy(all, 0, answer, 0, count); - return answer; + return result.toArray(new String[0]); } - /** - * Gets the default time zone. - * - * @return the default time zone. - */ public static synchronized TimeZone getDefault() { if (Default == null) { setDefault(null); @@ -119,90 +94,29 @@ public abstract class TimeZone implements TSerializable, TCloneable { return (TimeZone) 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, Locale.getDefault()); + 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(Locale locale) { + 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, Locale.getDefault()); + 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, Locale locale) { - if(icuTimeZone == null || !ID.equals(icuTimeZone.getID())){ + public String getDisplayName(boolean daylightTime, int style, TLocale locale) { + if (icuTimeZone == null || !ID.equals(icuTimeZone.getID())) { icuTimeZone = com.ibm.icu.util.TimeZone.getTimeZone(ID); } - return icuTimeZone.getDisplayName( - daylightTime, style, locale); + return icuTimeZone.getDisplayName(daylightTime, style, locale); } - /** - * 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; @@ -210,15 +124,6 @@ public abstract class TimeZone implements TSerializable, TCloneable { 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) { if (inDaylightTime(new Date(time))) { return getRawOffset() + getDSTSavings(); @@ -226,54 +131,16 @@ public abstract class TimeZone implements TSerializable, TCloneable { return 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); + 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 synchronized TimeZone getTimeZone(String name) { if (AvailableZones == null) { initializeAvailable(); } TimeZone zone = AvailableZones.get(name); - if(zone == null && isAvailableIDInICU(name)){ - appendAvailableZones(name); - zone = AvailableZones.get(name); - } if (zone == null) { if (name.startsWith("GMT") && name.length() > 3) { char sign = name.charAt(3); @@ -287,10 +154,8 @@ public abstract class TimeZone implements TSerializable, TCloneable { 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 (index < formattedName.length() && formattedName.charAt(index) == ':') { + int minute = parseNumber(formattedName, index + 1, position); if (position[0] == -1 || minute < 0 || minute > 59) { return (TimeZone) GMT.clone(); } @@ -339,15 +204,6 @@ public abstract class TimeZone implements TSerializable, TCloneable { 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(TimeZone zone) { if (zone == null) { return false; @@ -355,21 +211,11 @@ public abstract class TimeZone implements TSerializable, TCloneable { 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(Date 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) { + while (index < length && (digit = Character.digit(string.charAt(index), 10)) != -1) { index++; result = result * 10 + digit; } @@ -377,15 +223,6 @@ public abstract class TimeZone implements TSerializable, TCloneable { 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 synchronized void setDefault(TimeZone timezone) { if (timezone != null) { setICUDefaultTimeZone(timezone); @@ -393,8 +230,7 @@ public abstract class TimeZone implements TSerializable, TCloneable { return; } - String zone = AccessController.doPrivileged(new PriviAction( - "user.timezone")); + String zone = AccessController.doPrivileged(new PriviAction("user.timezone")); // sometimes DRLVM incorrectly adds "\n" to the end of timezone ID if (zone != null && zone.contains("\n")) { @@ -413,15 +249,14 @@ public abstract class TimeZone implements TSerializable, TCloneable { if (isCustomTimeZone[0]) { // build a new SimpleTimeZone switch (tzinfo[1]) { - case 0: - // does not observe DST - Default = new SimpleTimeZone(tzinfo[0], zoneId); - break; - default: - // observes DST - Default = new SimpleTimeZone(tzinfo[0], zoneId, tzinfo[5], - tzinfo[4], tzinfo[3], tzinfo[2], tzinfo[9], - tzinfo[8], tzinfo[7], tzinfo[6], tzinfo[1]); + case 0: + // does not observe DST + Default = new SimpleTimeZone(tzinfo[0], zoneId); + break; + default: + // observes DST + Default = new SimpleTimeZone(tzinfo[0], zoneId, tzinfo[5], tzinfo[4], tzinfo[3], tzinfo[2], + tzinfo[9], tzinfo[8], tzinfo[7], tzinfo[6], tzinfo[1]); } } else { // get TimeZone @@ -435,32 +270,23 @@ public abstract class TimeZone implements TSerializable, TCloneable { } private static void setICUDefaultTimeZone(TimeZone timezone) { - final com.ibm.icu.util.TimeZone icuTZ = com.ibm.icu.util.TimeZone - .getTimeZone(timezone.getID()); + final com.ibm.icu.util.TimeZone icuTZ = com.ibm.icu.util.TimeZone.getTimeZone(timezone.getID()); - AccessController - .doPrivileged(new PrivilegedAction() { - public java.lang.reflect.Field run() { - java.lang.reflect.Field field = null; - try { - field = com.ibm.icu.util.TimeZone.class - .getDeclaredField("defaultZone"); - field.setAccessible(true); - field.set("defaultZone", icuTZ); - } catch (Exception e) { - return null; - } - return field; - } - }); + AccessController.doPrivileged(new PrivilegedAction() { + public java.lang.reflect.Field run() { + java.lang.reflect.Field field = null; + try { + field = com.ibm.icu.util.TimeZone.class.getDeclaredField("defaultZone"); + field.setAccessible(true); + field.set("defaultZone", icuTZ); + } catch (Exception e) { + return null; + } + return field; + } + }); } - /** - * 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(); @@ -468,42 +294,9 @@ public abstract class TimeZone implements TSerializable, TCloneable { 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); + private static native String getCustomTimeZone(int[] tzinfo, boolean[] isCustomTimeZone); } From 2e97872496bcfe81eb09508e9c2c7628dd2d947a Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Fri, 16 May 2014 17:46:26 +0400 Subject: [PATCH 3/4] Adds formatting classes from the java.text package --- .../teavm/classlib/java/text/Annotation.java | 35 + .../text/AttributedCharacterIterator.java | 144 ++++ .../classlib/java/text/AttributedString.java | 630 ++++++++++++++++++ .../classlib/java/text/CharacterIterator.java | 42 ++ .../teavm/classlib/java/text/DateFormat.java | 280 ++++++++ .../classlib/java/text/DateFormatSymbols.java | 240 +++++++ .../classlib/java/text/DecimalFormat.java | 432 ++++++++++++ .../java/text/DecimalFormatSymbols.java | 280 ++++++++ .../classlib/java/text/FieldPosition.java | 87 +++ .../org/teavm/classlib/java/text/Format.java | 137 ++++ .../classlib/java/text/NumberFormat.java | 263 ++++++++ .../classlib/java/text/ParseException.java | 51 ++ .../classlib/java/text/ParsePosition.java | 62 ++ .../classlib/java/text/SimpleDateFormat.java | 597 +++++++++++++++++ .../org/teavm/classlib/java/util/Date.java | 7 +- .../teavm/classlib/java/util/TimeZone.java | 14 - 16 files changed, 3284 insertions(+), 17 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/Annotation.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/AttributedCharacterIterator.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/AttributedString.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/CharacterIterator.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormat.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormatSymbols.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/DecimalFormat.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/DecimalFormatSymbols.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/FieldPosition.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/Format.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/NumberFormat.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/ParseException.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/ParsePosition.java create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/text/SimpleDateFormat.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/Annotation.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/Annotation.java new file mode 100644 index 000000000..98013ad47 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/Annotation.java @@ -0,0 +1,35 @@ +/* + * 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.text; + +public class Annotation { + private Object value; + + public Annotation(Object attribute) { + value = attribute; + } + + public Object getValue() { + return value; + } + + @Override + public String toString() { + return getClass().getName() + "[value=" + value + ']'; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/AttributedCharacterIterator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/AttributedCharacterIterator.java new file mode 100644 index 000000000..6c6096e9c --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/AttributedCharacterIterator.java @@ -0,0 +1,144 @@ +/* + * 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.text; + +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.util.TMap; +import org.teavm.classlib.java.util.TSet; + +public interface AttributedCharacterIterator extends CharacterIterator { + + public static class Attribute implements TSerializable { + public static final Attribute INPUT_METHOD_SEGMENT = new Attribute( + "input_method_segment"); + + public static final Attribute LANGUAGE = new Attribute("language"); + + public static final Attribute READING = new Attribute("reading"); + + private String name; + + protected Attribute(String name) { + this.name = name; + } + + @Override + public final boolean equals(Object object) { + return this == object; + } + + protected String getName() { + return name; + } + + @Override + public final int hashCode() { + return super.hashCode(); + } + + @Override + public String toString() { + return getClass().getName() + '(' + getName() + ')'; + } + } + + /** + * Returns a set of attributes present in the {@code + * AttributedCharacterIterator}. An empty set is returned if no attributes + * were defined. + * + * @return a set of attribute keys; may be empty. + */ + public TSet getAllAttributeKeys(); + + /** + * Returns the value stored in the attribute for the current character. If + * the attribute was not defined then {@code null} is returned. + * + * @param attribute the attribute for which the value should be returned. + * @return the value of the requested attribute for the current character or + * {@code null} if it was not defined. + */ + public Object getAttribute(Attribute attribute); + + /** + * Returns a map of all attributes of the current character. If no + * attributes were defined for the current character then an empty map is + * returned. + * + * @return a map of all attributes for the current character or an empty + * map. + */ + public TMap getAttributes(); + + /** + * Returns the index of the last character in the run having the same + * attributes as the current character. + * + * @return the index of the last character of the current run. + */ + public int getRunLimit(); + + /** + * Returns the index of the last character in the run that has the same + * attribute value for the given attribute as the current character. + * + * @param attribute + * the attribute which the run is based on. + * @return the index of the last character of the current run. + */ + public int getRunLimit(Attribute attribute); + + /** + * Returns the index of the last character in the run that has the same + * attribute values for the attributes in the set as the current character. + * + * @param attributes + * the set of attributes which the run is based on. + * @return the index of the last character of the current run. + */ + public int getRunLimit(TSet attributes); + + /** + * Returns the index of the first character in the run that has the same + * attributes as the current character. + * + * @return the index of the last character of the current run. + */ + public int getRunStart(); + + /** + * Returns the index of the first character in the run that has the same + * attribute value for the given attribute as the current character. + * + * @param attribute + * the attribute which the run is based on. + * @return the index of the last character of the current run. + */ + public int getRunStart(Attribute attribute); + + /** + * Returns the index of the first character in the run that has the same + * attribute values for the attributes in the set as the current character. + * + * @param attributes + * the set of attributes which the run is based on. + * @return the index of the last character of the current run. + */ + public int getRunStart(TSet attributes); +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/AttributedString.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/AttributedString.java new file mode 100644 index 000000000..0ad14c1e6 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/AttributedString.java @@ -0,0 +1,630 @@ +/* + * 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.text; + +import org.teavm.classlib.java.text.AttributedCharacterIterator.Attribute; +import org.teavm.classlib.java.util.*; + +public class AttributedString { + + String text; + + TMap> attributeMap; + + static class Range { + int start; + + int end; + + Object value; + + Range(int s, int e, Object v) { + start = s; + end = e; + value = v; + } + } + + static class AttributedIterator implements AttributedCharacterIterator { + + private int begin, end, offset; + + private AttributedString attrString; + + private THashSet attributesAllowed; + + AttributedIterator(AttributedString attrString) { + this.attrString = attrString; + begin = 0; + end = attrString.text.length(); + offset = 0; + } + + AttributedIterator(AttributedString attrString, AttributedCharacterIterator.Attribute[] attributes, int begin, + int end) { + if (begin < 0 || end > attrString.text.length() || begin > end) { + throw new IllegalArgumentException(); + } + this.begin = begin; + this.end = end; + offset = begin; + this.attrString = attrString; + if (attributes != null) { + THashSet set = new THashSet<>((attributes.length * 4 / 3) + 1); + for (int i = attributes.length; --i >= 0;) { + set.add(attributes[i]); + } + attributesAllowed = set; + } + } + + @Override + @SuppressWarnings("unchecked") + public Object clone() { + try { + AttributedIterator clone = (AttributedIterator) super.clone(); + if (attributesAllowed != null) { + clone.attributesAllowed = (THashSet) attributesAllowed.clone(); + } + return clone; + } catch (CloneNotSupportedException e) { + return null; + } + } + + @Override + public char current() { + if (offset == end) { + return DONE; + } + return attrString.text.charAt(offset); + } + + @Override + public char first() { + if (begin == end) { + return DONE; + } + offset = begin; + return attrString.text.charAt(offset); + } + + @Override + public int getBeginIndex() { + return begin; + } + + @Override + public int getEndIndex() { + return end; + } + + @Override + public int getIndex() { + return offset; + } + + private boolean inRange(Range range) { + if (!(range.value instanceof Annotation)) { + return true; + } + return range.start >= begin && range.start < end && range.end > begin && range.end <= end; + } + + private boolean inRange(TList ranges) { + TIterator it = ranges.iterator(); + while (it.hasNext()) { + Range range = it.next(); + if (range.start >= begin && range.start < end) { + return !(range.value instanceof Annotation) || (range.end > begin && range.end <= end); + } else if (range.end > begin && range.end <= end) { + return !(range.value instanceof Annotation) || (range.start >= begin && range.start < end); + } + } + return false; + } + + @Override + public TSet getAllAttributeKeys() { + if (begin == 0 && end == attrString.text.length() && attributesAllowed == null) { + return attrString.attributeMap.keySet(); + } + + TSet result = new THashSet<>((attrString.attributeMap.size() * 4 / 3) + 1); + TIterator>> it = attrString.attributeMap.entrySet().iterator(); + while (it.hasNext()) { + TMap.Entry> entry = it.next(); + if (attributesAllowed == null || attributesAllowed.contains(entry.getKey())) { + TList ranges = entry.getValue(); + if (inRange(ranges)) { + result.add(entry.getKey()); + } + } + } + return result; + } + + private Object currentValue(TList ranges) { + TIterator it = ranges.iterator(); + while (it.hasNext()) { + Range range = it.next(); + if (offset >= range.start && offset < range.end) { + return inRange(range) ? range.value : null; + } + } + return null; + } + + @Override + public Object getAttribute(AttributedCharacterIterator.Attribute attribute) { + if (attributesAllowed != null && !attributesAllowed.contains(attribute)) { + return null; + } + TArrayList ranges = (TArrayList) attrString.attributeMap.get(attribute); + if (ranges == null) { + return null; + } + return currentValue(ranges); + } + + @Override + public TMap getAttributes() { + TMap result = new THashMap<>((attrString.attributeMap.size() * 4 / 3) + 1); + TIterator>> it = attrString.attributeMap.entrySet().iterator(); + while (it.hasNext()) { + TMap.Entry> entry = it.next(); + if (attributesAllowed == null || attributesAllowed.contains(entry.getKey())) { + Object value = currentValue(entry.getValue()); + if (value != null) { + result.put(entry.getKey(), value); + } + } + } + return result; + } + + @Override + public int getRunLimit() { + return getRunLimit(getAllAttributeKeys()); + } + + private int runLimit(TList ranges) { + int result = end; + TListIterator it = ranges.listIterator(ranges.size()); + while (it.hasPrevious()) { + Range range = it.previous(); + if (range.end <= begin) { + break; + } + if (offset >= range.start && offset < range.end) { + return inRange(range) ? range.end : result; + } else if (offset >= range.end) { + break; + } + result = range.start; + } + return result; + } + + @Override + public int getRunLimit(AttributedCharacterIterator.Attribute attribute) { + if (attributesAllowed != null && !attributesAllowed.contains(attribute)) { + return end; + } + TArrayList ranges = (TArrayList) attrString.attributeMap.get(attribute); + if (ranges == null) { + return end; + } + return runLimit(ranges); + } + + @Override + public int getRunLimit(TSet attributes) { + int limit = end; + TIterator it = attributes.iterator(); + while (it.hasNext()) { + AttributedCharacterIterator.Attribute attribute = it.next(); + int newLimit = getRunLimit(attribute); + if (newLimit < limit) { + limit = newLimit; + } + } + return limit; + } + + @Override + public int getRunStart() { + return getRunStart(getAllAttributeKeys()); + } + + private int runStart(TList ranges) { + int result = begin; + TIterator it = ranges.iterator(); + while (it.hasNext()) { + Range range = it.next(); + if (range.start >= end) { + break; + } + if (offset >= range.start && offset < range.end) { + return inRange(range) ? range.start : result; + } else if (offset < range.start) { + break; + } + result = range.end; + } + return result; + } + + @Override + public int getRunStart(AttributedCharacterIterator.Attribute attribute) { + if (attributesAllowed != null && !attributesAllowed.contains(attribute)) { + return begin; + } + TArrayList ranges = (TArrayList) attrString.attributeMap.get(attribute); + if (ranges == null) { + return begin; + } + return runStart(ranges); + } + + @Override + public int getRunStart(TSet attributes) { + int start = begin; + TIterator it = attributes.iterator(); + while (it.hasNext()) { + AttributedCharacterIterator.Attribute attribute = it.next(); + int newStart = getRunStart(attribute); + if (newStart > start) { + start = newStart; + } + } + return start; + } + + @Override + public char last() { + if (begin == end) { + return DONE; + } + offset = end - 1; + return attrString.text.charAt(offset); + } + + @Override + public char next() { + if (offset >= (end - 1)) { + offset = end; + return DONE; + } + return attrString.text.charAt(++offset); + } + + @Override + public char previous() { + if (offset == begin) { + return DONE; + } + return attrString.text.charAt(--offset); + } + + @Override + public char setIndex(int location) { + if (location < begin || location > end) { + throw new IllegalArgumentException(); + } + offset = location; + if (offset == end) { + return DONE; + } + return attrString.text.charAt(offset); + } + } + + public AttributedString(AttributedCharacterIterator iterator) { + if (iterator.getBeginIndex() > iterator.getEndIndex()) { + throw new IllegalArgumentException("Invalid substring range"); + } + StringBuilder buffer = new StringBuilder(); + for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex(); i++) { + buffer.append(iterator.current()); + iterator.next(); + } + text = buffer.toString(); + TSet attributes = iterator.getAllAttributeKeys(); + if (attributes == null) { + return; + } + attributeMap = new THashMap<>((attributes.size() * 4 / 3) + 1); + + TIterator it = attributes.iterator(); + while (it.hasNext()) { + AttributedCharacterIterator.Attribute attribute = it.next(); + iterator.setIndex(0); + while (iterator.current() != CharacterIterator.DONE) { + int start = iterator.getRunStart(attribute); + int limit = iterator.getRunLimit(attribute); + Object value = iterator.getAttribute(attribute); + if (value != null) { + addAttribute(attribute, value, start, limit); + } + iterator.setIndex(limit); + } + } + } + + private AttributedString(AttributedCharacterIterator iterator, int start, int end, TSet attributes) { + if (start < iterator.getBeginIndex() || end > iterator.getEndIndex() || start > end) { + throw new IllegalArgumentException(); + } + + if (attributes == null) { + return; + } + + StringBuilder buffer = new StringBuilder(); + iterator.setIndex(start); + while (iterator.getIndex() < end) { + buffer.append(iterator.current()); + iterator.next(); + } + text = buffer.toString(); + attributeMap = new THashMap<>((attributes.size() * 4 / 3) + 1); + + TIterator it = attributes.iterator(); + while (it.hasNext()) { + AttributedCharacterIterator.Attribute attribute = it.next(); + iterator.setIndex(start); + while (iterator.getIndex() < end) { + Object value = iterator.getAttribute(attribute); + int runStart = iterator.getRunStart(attribute); + int limit = iterator.getRunLimit(attribute); + if ((value instanceof Annotation && runStart >= start && limit <= end) || + (value != null && !(value instanceof Annotation))) { + addAttribute(attribute, value, (runStart < start ? start : runStart) - start, (limit > end ? end + : limit) - start); + } + iterator.setIndex(limit); + } + } + } + + public AttributedString(AttributedCharacterIterator iterator, int start, int end) { + this(iterator, start, end, iterator.getAllAttributeKeys()); + } + + public AttributedString(AttributedCharacterIterator iterator, int start, int end, + AttributedCharacterIterator.Attribute[] attributes) { + this(iterator, start, end, new THashSet<>(TArrays.asList(attributes))); + } + + public AttributedString(String value) { + if (value == null) { + throw new NullPointerException(); + } + text = value; + attributeMap = new THashMap<>(11); + } + + public AttributedString(String value, TMap attributes) { + if (value == null) { + throw new NullPointerException(); + } + if (value.length() == 0 && !attributes.isEmpty()) { + throw new IllegalArgumentException("Cannot add attributes to empty string"); + } + text = value; + attributeMap = new THashMap<>((attributes.size() * 4 / 3) + 1); + TIterator it = attributes.entrySet().iterator(); + while (it.hasNext()) { + TMap.Entry entry = (TMap.Entry) it.next(); + TArrayList ranges = new TArrayList<>(1); + ranges.add(new Range(0, text.length(), entry.getValue())); + attributeMap.put((AttributedCharacterIterator.Attribute) entry.getKey(), ranges); + } + } + + /** + * Applies a given attribute to this string. + * + * @param attribute + * the attribute that will be applied to this string. + * @param value + * the value of the attribute that will be applied to this + * string. + * @throws IllegalArgumentException + * if the length of this attributed string is 0. + * @throws NullPointerException + * if {@code attribute} is {@code null}. + */ + public void addAttribute(AttributedCharacterIterator.Attribute attribute, Object value) { + if (null == attribute) { + throw new NullPointerException(); + } + if (text.length() == 0) { + throw new IllegalArgumentException(); + } + + TList ranges = attributeMap.get(attribute); + if (ranges == null) { + ranges = new TArrayList(1); + attributeMap.put(attribute, ranges); + } else { + ranges.clear(); + } + ranges.add(new Range(0, text.length(), value)); + } + + /** + * Applies a given attribute to the given range of this string. + * + * @param attribute + * the attribute that will be applied to this string. + * @param value + * the value of the attribute that will be applied to this + * string. + * @param start + * the start of the range where the attribute will be applied. + * @param end + * the end of the range where the attribute will be applied. + * @throws IllegalArgumentException + * if {@code start < 0}, {@code end} is greater than the length + * of this string, or if {@code start >= end}. + * @throws NullPointerException + * if {@code attribute} is {@code null}. + */ + public void addAttribute(AttributedCharacterIterator.Attribute attribute, Object value, int start, int end) { + if (null == attribute) { + throw new NullPointerException(); + } + if (start < 0 || end > text.length() || start >= end) { + throw new IllegalArgumentException(); + } + + if (value == null) { + return; + } + + TList ranges = attributeMap.get(attribute); + if (ranges == null) { + ranges = new TArrayList<>(1); + ranges.add(new Range(start, end, value)); + attributeMap.put(attribute, ranges); + return; + } + TListIterator it = ranges.listIterator(); + while (it.hasNext()) { + Range range = it.next(); + if (end <= range.start) { + it.previous(); + break; + } else if (start < range.end || (start == range.end && value.equals(range.value))) { + Range r1 = null, r3; + it.remove(); + r1 = new Range(range.start, start, range.value); + r3 = new Range(end, range.end, range.value); + + while (end > range.end && it.hasNext()) { + range = it.next(); + if (end <= range.end) { + if (end > range.start || (end == range.start && value.equals(range.value))) { + it.remove(); + r3 = new Range(end, range.end, range.value); + break; + } + } else { + it.remove(); + } + } + + if (value.equals(r1.value)) { + if (value.equals(r3.value)) { + it.add(new Range(r1.start < start ? r1.start : start, r3.end > end ? r3.end : end, r1.value)); + } else { + it.add(new Range(r1.start < start ? r1.start : start, end, r1.value)); + if (r3.start < r3.end) { + it.add(r3); + } + } + } else { + if (value.equals(r3.value)) { + if (r1.start < r1.end) { + it.add(r1); + } + it.add(new Range(start, r3.end > end ? r3.end : end, r3.value)); + } else { + if (r1.start < r1.end) { + it.add(r1); + } + it.add(new Range(start, end, value)); + if (r3.start < r3.end) { + it.add(r3); + } + } + } + return; + } + } + it.add(new Range(start, end, value)); + } + + /** + * Applies a given set of attributes to the given range of the string. + * + * @param attributes + * the set of attributes that will be applied to this string. + * @param start + * the start of the range where the attribute will be applied. + * @param end + * the end of the range where the attribute will be applied. + * @throws IllegalArgumentException + * if {@code start < 0}, {@code end} is greater than the length + * of this string, or if {@code start >= end}. + */ + public void addAttributes(TMap attributes, int start, int end) { + TIterator it = attributes.entrySet().iterator(); + while (it.hasNext()) { + TMap.Entry entry = (TMap.Entry) it.next(); + addAttribute((AttributedCharacterIterator.Attribute) entry.getKey(), entry.getValue(), start, end); + } + } + + /** + * Returns an {@code AttributedCharacterIterator} that gives access to the + * complete content of this attributed string. + * + * @return the newly created {@code AttributedCharacterIterator}. + */ + public AttributedCharacterIterator getIterator() { + return new AttributedIterator(this); + } + + /** + * Returns an {@code AttributedCharacterIterator} that gives access to the + * complete content of this attributed string. Only attributes contained in + * {@code attributes} are available from this iterator if they are defined + * for this text. + * + * @param attributes + * the array containing attributes that will be in the new + * iterator if they are defined for this text. + * @return the newly created {@code AttributedCharacterIterator}. + */ + public AttributedCharacterIterator getIterator(AttributedCharacterIterator.Attribute[] attributes) { + return new AttributedIterator(this, attributes, 0, text.length()); + } + + /** + * Returns an {@code AttributedCharacterIterator} that gives access to the + * contents of this attributed string starting at index {@code start} up to + * index {@code end}. Only attributes contained in {@code attributes} are + * available from this iterator if they are defined for this text. + * + * @param attributes + * the array containing attributes that will be in the new + * iterator if they are defined for this text. + * @param start + * the start index of the iterator on the underlying text. + * @param end + * the end index of the iterator on the underlying text. + * @return the newly created {@code AttributedCharacterIterator}. + */ + public AttributedCharacterIterator getIterator(AttributedCharacterIterator.Attribute[] attributes, int start, + int end) { + return new AttributedIterator(this, attributes, start, end); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/CharacterIterator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/CharacterIterator.java new file mode 100644 index 000000000..c3f0e6434 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/CharacterIterator.java @@ -0,0 +1,42 @@ +/* + * 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.text; + +public interface CharacterIterator extends Cloneable { + public static final char DONE = '\uffff'; + + public Object clone(); + + public char current(); + + public char first(); + + public int getBeginIndex(); + + public int getEndIndex(); + + public int getIndex(); + + public char last(); + + public char next(); + + public char previous(); + + public char setIndex(int location); +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormat.java new file mode 100644 index 000000000..a6c2851ae --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormat.java @@ -0,0 +1,280 @@ +/* + * 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.text; + +import org.teavm.classlib.java.util.*; + +public abstract class DateFormat extends Format { + protected Calendar calendar; + protected NumberFormat numberFormat; + public final static int DEFAULT = 2; + public final static int FULL = 0; + public final static int LONG = 1; + public final static int MEDIUM = 2; + public final static int SHORT = 3; + public final static int ERA_FIELD = 0; + public final static int YEAR_FIELD = 1; + public final static int MONTH_FIELD = 2; + public final static int DATE_FIELD = 3; + public final static int HOUR_OF_DAY1_FIELD = 4; + public final static int HOUR_OF_DAY0_FIELD = 5; + public final static int MINUTE_FIELD = 6; + public final static int SECOND_FIELD = 7; + public final static int MILLISECOND_FIELD = 8; + public final static int DAY_OF_WEEK_FIELD = 9; + public final static int DAY_OF_YEAR_FIELD = 10; + public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11; + public final static int WEEK_OF_YEAR_FIELD = 12; + public final static int WEEK_OF_MONTH_FIELD = 13; + public final static int AM_PM_FIELD = 14; + public final static int HOUR1_FIELD = 15; + public final static int HOUR0_FIELD = 16; + public final static int TIMEZONE_FIELD = 17; + + protected DateFormat() { + } + + @Override + public Object clone() { + DateFormat clone = (DateFormat) super.clone(); + clone.calendar = (Calendar) calendar.clone(); + clone.numberFormat = (NumberFormat) numberFormat.clone(); + return clone; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof DateFormat)) { + return false; + } + DateFormat dateFormat = (DateFormat) object; + return numberFormat.equals(dateFormat.numberFormat) && + calendar.getTimeZone().equals(dateFormat.calendar.getTimeZone()) && + calendar.getFirstDayOfWeek() == dateFormat.calendar.getFirstDayOfWeek() && + calendar.getMinimalDaysInFirstWeek() == dateFormat.calendar.getMinimalDaysInFirstWeek() && + calendar.isLenient() == dateFormat.calendar.isLenient(); + } + + @Override + public final StringBuffer format(Object object, StringBuffer buffer, FieldPosition field) { + if (object instanceof Date) { + return format((Date) object, buffer, field); + } + if (object instanceof Number) { + return format(new Date(((Number) object).longValue()), buffer, field); + } + throw new IllegalArgumentException(); + } + + public final String format(Date date) { + return format(date, new StringBuffer(), new FieldPosition(0)).toString(); + } + + public abstract StringBuffer format(Date date, StringBuffer buffer, FieldPosition field); + + public static TLocale[] getAvailableLocales() { + return TLocale.getAvailableLocales(); + } + + public Calendar getCalendar() { + return calendar; + } + + public final static DateFormat getDateInstance() { + return getDateInstance(DEFAULT); + } + + public final static DateFormat getDateInstance(int style) { + checkDateStyle(style); + return getDateInstance(style, TLocale.getDefault()); + } + + public final static DateFormat getDateInstance(int style, TLocale locale) { + checkDateStyle(style); + com.ibm.icu.text.DateFormat icuFormat = com.ibm.icu.text.DateFormat.getDateInstance(style, locale); + return new SimpleDateFormat(locale, (com.ibm.icu.text.SimpleDateFormat) icuFormat); + } + + public final static DateFormat getDateTimeInstance() { + return getDateTimeInstance(DEFAULT, DEFAULT); + } + + public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle) { + checkTimeStyle(timeStyle); + checkDateStyle(dateStyle); + return getDateTimeInstance(dateStyle, timeStyle, TLocale.getDefault()); + } + + public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle, TLocale locale) { + checkTimeStyle(timeStyle); + checkDateStyle(dateStyle); + com.ibm.icu.text.DateFormat icuFormat = com.ibm.icu.text.DateFormat.getDateTimeInstance(dateStyle, timeStyle, + locale); + return new SimpleDateFormat(locale, (com.ibm.icu.text.SimpleDateFormat) icuFormat); + } + + public final static DateFormat getInstance() { + return getDateTimeInstance(SHORT, SHORT); + } + + public NumberFormat getNumberFormat() { + return numberFormat; + } + + static String getStyleName(int style) { + String styleName; + switch (style) { + case SHORT: + styleName = "SHORT"; + break; + case MEDIUM: + styleName = "MEDIUM"; + break; + case LONG: + styleName = "LONG"; + break; + case FULL: + styleName = "FULL"; + break; + default: + styleName = ""; + } + return styleName; + } + + public final static DateFormat getTimeInstance() { + return getTimeInstance(DEFAULT); + } + + public final static DateFormat getTimeInstance(int style) { + checkTimeStyle(style); + return getTimeInstance(style, TLocale.getDefault()); + } + + public final static DateFormat getTimeInstance(int style, TLocale locale) { + checkTimeStyle(style); + com.ibm.icu.text.DateFormat icuFormat = com.ibm.icu.text.DateFormat.getTimeInstance(style, locale); + return new SimpleDateFormat(locale, (com.ibm.icu.text.SimpleDateFormat) icuFormat); + } + + public TimeZone getTimeZone() { + return calendar.getTimeZone(); + } + + @Override + public int hashCode() { + return calendar.getFirstDayOfWeek() + calendar.getMinimalDaysInFirstWeek() + calendar.getTimeZone().hashCode() + + (calendar.isLenient() ? 1231 : 1237) + numberFormat.hashCode(); + } + + public boolean isLenient() { + return calendar.isLenient(); + } + + public Date parse(String string) throws ParseException { + ParsePosition position = new ParsePosition(0); + Date date = parse(string, position); + if (position.getIndex() == 0) { + throw new ParseException("Unparseable date" + string, position.getErrorIndex()); + } + return date; + } + + public abstract Date parse(String string, ParsePosition position); + + @Override + public Object parseObject(String string, ParsePosition position) { + return parse(string, position); + } + + public void setCalendar(Calendar cal) { + calendar = cal; + } + + public void setLenient(boolean value) { + calendar.setLenient(value); + } + + public void setNumberFormat(NumberFormat format) { + numberFormat = format; + } + + public void setTimeZone(TimeZone timezone) { + calendar.setTimeZone(timezone); + } + + public static class Field extends Format.Field { + private static THashMap table = new THashMap<>(); + public final static Field ERA = new Field("era", Calendar.ERA); + public final static Field YEAR = new Field("year", Calendar.YEAR); + public final static Field MONTH = new Field("month", Calendar.MONTH); + public final static Field HOUR_OF_DAY0 = new Field("hour of day", Calendar.HOUR_OF_DAY); + public final static Field HOUR_OF_DAY1 = new Field("hour of day 1", -1); + public final static Field MINUTE = new Field("minute", Calendar.MINUTE); + public final static Field SECOND = new Field("second", Calendar.SECOND); + public final static Field MILLISECOND = new Field("millisecond", Calendar.MILLISECOND); + public final static Field DAY_OF_WEEK = new Field("day of week", Calendar.DAY_OF_WEEK); + public final static Field DAY_OF_MONTH = new Field("day of month", Calendar.DAY_OF_MONTH); + public final static Field DAY_OF_YEAR = new Field("day of year", Calendar.DAY_OF_YEAR); + public final static Field DAY_OF_WEEK_IN_MONTH = new Field("day of week in month", + Calendar.DAY_OF_WEEK_IN_MONTH); + public final static Field WEEK_OF_YEAR = new Field("week of year", Calendar.WEEK_OF_YEAR); + public final static Field WEEK_OF_MONTH = new Field("week of month", Calendar.WEEK_OF_MONTH); + public final static Field AM_PM = new Field("am pm", Calendar.AM_PM); + public final static Field HOUR0 = new Field("hour", Calendar.HOUR); + public final static Field HOUR1 = new Field("hour 1", -1); + public final static Field TIME_ZONE = new Field("time zone", -1); + private int calendarField = -1; + + protected Field(String fieldName, int calendarField) { + super(fieldName); + this.calendarField = calendarField; + if (calendarField != -1 && table.get(new Integer(calendarField)) == null) { + table.put(new Integer(calendarField), this); + } + } + + public int getCalendarField() { + return calendarField; + } + + public static Field ofCalendarField(int calendarField) { + if (calendarField < 0 || calendarField >= Calendar.FIELD_COUNT) { + throw new IllegalArgumentException(); + } + + return table.get(new Integer(calendarField)); + } + } + + private static void checkDateStyle(int style) { + if (!(style == SHORT || style == MEDIUM || style == LONG || style == FULL || style == DEFAULT)) { + throw new IllegalArgumentException("Illegal date style: " + style); + } + } + + private static void checkTimeStyle(int style) { + if (!(style == SHORT || style == MEDIUM || style == LONG || style == FULL || style == DEFAULT)) { + // text.0F=Illegal time style: {0} + throw new IllegalArgumentException("Illegal time style: " + style); + } + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormatSymbols.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormatSymbols.java new file mode 100644 index 000000000..b28f92306 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DateFormatSymbols.java @@ -0,0 +1,240 @@ +/* + * 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.text; + +import java.util.Arrays; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.util.TLocale; + +public class DateFormatSymbols implements TSerializable, Cloneable { + + private static final long serialVersionUID = -5987973545549424702L; + + private String localPatternChars; + + String[] ampms, eras, months, shortMonths, shortWeekdays, weekdays; + + String[][] zoneStrings; + + transient private com.ibm.icu.text.DateFormatSymbols icuSymbols; + + public DateFormatSymbols() { + this(TLocale.getDefault()); + } + + public DateFormatSymbols(TLocale locale) { + this(locale, new com.ibm.icu.text.DateFormatSymbols(locale)); + } + + DateFormatSymbols(TLocale locale, com.ibm.icu.text.DateFormatSymbols icuSymbols) { + this.icuSymbols = icuSymbols; + localPatternChars = icuSymbols.getLocalPatternChars(); + ampms = icuSymbols.getAmPmStrings(); + eras = icuSymbols.getEras(); + months = icuSymbols.getMonths(); + shortMonths = icuSymbols.getShortMonths(); + shortWeekdays = icuSymbols.getShortWeekdays(); + weekdays = icuSymbols.getWeekdays(); + } + + @Override + public Object clone() { + if (zoneStrings == null) { + zoneStrings = icuSymbols.getZoneStrings(); + } + try { + DateFormatSymbols symbols = (DateFormatSymbols) super.clone(); + symbols.ampms = ampms.clone(); + symbols.eras = eras.clone(); + symbols.months = months.clone(); + symbols.shortMonths = shortMonths.clone(); + symbols.shortWeekdays = shortWeekdays.clone(); + symbols.weekdays = weekdays.clone(); + symbols.zoneStrings = new String[zoneStrings.length][]; + for (int i = 0; i < zoneStrings.length; i++) { + symbols.zoneStrings[i] = zoneStrings[i].clone(); + } + return symbols; + } catch (CloneNotSupportedException e) { + return null; + } + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof DateFormatSymbols)) { + return false; + } + if (zoneStrings == null) { + zoneStrings = icuSymbols.getZoneStrings(); + } + + DateFormatSymbols obj = (DateFormatSymbols) object; + + if (obj.zoneStrings == null) { + obj.zoneStrings = obj.icuSymbols.getZoneStrings(); + } + if (!localPatternChars.equals(obj.localPatternChars)) { + return false; + } + if (!Arrays.equals(ampms, obj.ampms)) { + return false; + } + if (!Arrays.equals(eras, obj.eras)) { + return false; + } + if (!Arrays.equals(months, obj.months)) { + return false; + } + if (!Arrays.equals(shortMonths, obj.shortMonths)) { + return false; + } + if (!Arrays.equals(shortWeekdays, obj.shortWeekdays)) { + return false; + } + if (!Arrays.equals(weekdays, obj.weekdays)) { + return false; + } + if (zoneStrings.length != obj.zoneStrings.length) { + return false; + } + for (String[] element : zoneStrings) { + if (element.length != element.length) { + return false; + } + for (int j = 0; j < element.length; j++) { + if (element[j] != element[j] && !(element[j].equals(element[j]))) { + return false; + } + } + } + return true; + } + + public String[] getAmPmStrings() { + return ampms.clone(); + } + + public String[] getEras() { + return eras.clone(); + } + + public String getLocalPatternChars() { + return localPatternChars; + } + + public String[] getMonths() { + return months.clone(); + } + + public String[] getShortMonths() { + return shortMonths.clone(); + } + + public String[] getShortWeekdays() { + return shortWeekdays.clone(); + } + + public String[] getWeekdays() { + return weekdays.clone(); + } + + public String[][] getZoneStrings() { + if (zoneStrings == null) { + zoneStrings = icuSymbols.getZoneStrings(); + } + String[][] clone = new String[zoneStrings.length][]; + for (int i = zoneStrings.length; --i >= 0;) { + clone[i] = zoneStrings[i].clone(); + } + return clone; + } + + @Override + public int hashCode() { + if (zoneStrings == null) { + zoneStrings = icuSymbols.getZoneStrings(); + } + int hashCode; + hashCode = localPatternChars.hashCode(); + for (String element : ampms) { + hashCode += element.hashCode(); + } + for (String element : eras) { + hashCode += element.hashCode(); + } + for (String element : months) { + hashCode += element.hashCode(); + } + for (String element : shortMonths) { + hashCode += element.hashCode(); + } + for (String element : shortWeekdays) { + hashCode += element.hashCode(); + } + for (String element : weekdays) { + hashCode += element.hashCode(); + } + for (String[] element : zoneStrings) { + for (int j = 0; j < element.length; j++) { + if (element[j] != null) { + hashCode += element[j].hashCode(); + } + } + } + return hashCode; + } + + public void setAmPmStrings(String[] data) { + ampms = data.clone(); + } + + public void setEras(String[] data) { + eras = data.clone(); + } + + public void setLocalPatternChars(String data) { + if (data == null) { + throw new NullPointerException(); + } + localPatternChars = data; + } + + public void setMonths(String[] data) { + months = data.clone(); + } + + public void setShortMonths(String[] data) { + shortMonths = data.clone(); + } + + public void setShortWeekdays(String[] data) { + shortWeekdays = data.clone(); + } + + public void setWeekdays(String[] data) { + weekdays = data.clone(); + } + + public void setZoneStrings(String[][] data) { + zoneStrings = data.clone(); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DecimalFormat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DecimalFormat.java new file mode 100644 index 000000000..dbba979dd --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DecimalFormat.java @@ -0,0 +1,432 @@ +/* + * 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.text; + +import org.teavm.classlib.java.util.TLocale; + + +public class DecimalFormat extends NumberFormat { + + private static final long serialVersionUID = 864413376551465018L; + + private transient boolean parseBigDecimal = false; + + private transient DecimalFormatSymbols symbols; + + private transient com.ibm.icu.text.DecimalFormat dform; + + private transient com.ibm.icu.text.DecimalFormatSymbols icuSymbols; + + private static final int CURRENT_SERIAL_VERTION = 3; + + private transient int serialVersionOnStream = 3; + + /** + * Constructs a new {@code DecimalFormat} for formatting and parsing numbers + * for the default locale. + */ + public DecimalFormat() { + TLocale locale = TLocale.getDefault(); + icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale); + symbols = new DecimalFormatSymbols(locale); + dform = new com.ibm.icu.text.DecimalFormat(); + + super.setMaximumFractionDigits(dform.getMaximumFractionDigits()); + super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits()); + super.setMinimumFractionDigits(dform.getMinimumFractionDigits()); + super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits()); + } + + /** + * Constructs a new {@code DecimalFormat} using the specified non-localized + * pattern and the {@code DecimalFormatSymbols} for the default Locale. + * + * @param pattern + * the non-localized pattern. + * @throws IllegalArgumentException + * if the pattern cannot be parsed. + */ + public DecimalFormat(String pattern) { + TLocale locale = TLocale.getDefault(); + icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale); + symbols = new DecimalFormatSymbols(locale); + dform = new com.ibm.icu.text.DecimalFormat(pattern, icuSymbols); + + super.setMaximumFractionDigits(dform.getMaximumFractionDigits()); + super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits()); + super.setMinimumFractionDigits(dform.getMinimumFractionDigits()); + super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits()); + } + + /** + * Constructs a new {@code DecimalFormat} using the specified non-localized + * pattern and {@code DecimalFormatSymbols}. + * + * @param pattern + * the non-localized pattern. + * @param value + * the DecimalFormatSymbols. + * @throws IllegalArgumentException + * if the pattern cannot be parsed. + */ + public DecimalFormat(String pattern, DecimalFormatSymbols value) { + symbols = (DecimalFormatSymbols) value.clone(); + TLocale locale = symbols.getLocale(); + icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale); + copySymbols(icuSymbols, symbols); + + dform = new com.ibm.icu.text.DecimalFormat(pattern, icuSymbols); + + super.setMaximumFractionDigits(dform.getMaximumFractionDigits()); + super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits()); + super.setMinimumFractionDigits(dform.getMinimumFractionDigits()); + super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits()); + } + + DecimalFormat(String pattern, DecimalFormatSymbols value, com.ibm.icu.text.DecimalFormat icuFormat) { + symbols = value; + icuSymbols = value.getIcuSymbols(); + dform = icuFormat; + + super.setMaximumFractionDigits(dform.getMaximumFractionDigits()); + super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits()); + super.setMinimumFractionDigits(dform.getMinimumFractionDigits()); + super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits()); + } + + /** + * Changes the pattern of this decimal format to the specified pattern which + * uses localized pattern characters. + * + * @param pattern + * the localized pattern. + * @throws IllegalArgumentException + * if the pattern cannot be parsed. + */ + public void applyLocalizedPattern(String pattern) { + dform.applyLocalizedPattern(pattern); + super.setMaximumFractionDigits(dform.getMaximumFractionDigits()); + super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits()); + super.setMinimumFractionDigits(dform.getMinimumFractionDigits()); + super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits()); + } + + /** + * Changes the pattern of this decimal format to the specified pattern which + * uses non-localized pattern characters. + * + * @param pattern + * the non-localized pattern. + * @throws IllegalArgumentException + * if the pattern cannot be parsed. + */ + public void applyPattern(String pattern) { + + dform.applyPattern(pattern); + super.setMaximumFractionDigits(dform.getMaximumFractionDigits()); + super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits()); + super.setMinimumFractionDigits(dform.getMinimumFractionDigits()); + super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits()); + } + + /** + * Returns a new instance of {@code DecimalFormat} with the same pattern and + * properties as this decimal format. + * + * @return a shallow copy of this decimal format. + * @see java.lang.Cloneable + */ + @Override + public Object clone() { + DecimalFormat clone = (DecimalFormat) super.clone(); + clone.dform = (com.ibm.icu.text.DecimalFormat) dform.clone(); + clone.symbols = (DecimalFormatSymbols) symbols.clone(); + return clone; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof DecimalFormat)) { + return false; + } + DecimalFormat format = (DecimalFormat) object; + return (this.dform == null ? format.dform == null : this.dform + .equals(format.dform)); + } + + @Override + public AttributedCharacterIterator formatToCharacterIterator(Object object) { + if (object == null) { + throw new NullPointerException(); + } + return dform.formatToCharacterIterator(object); + } + + @Override + public StringBuffer format(double value, StringBuffer buffer, + FieldPosition position) { + return dform.format(value, buffer, position); + } + + @Override + public StringBuffer format(long value, StringBuffer buffer, + FieldPosition position) { + return dform.format(value, buffer, position); + } + + @Override + public final StringBuffer format(Object number, StringBuffer toAppendTo, + FieldPosition pos) { + if (!(number instanceof Number)) { + throw new IllegalArgumentException(); + } + if (toAppendTo == null || pos == null) { + throw new NullPointerException(); + } + if (number instanceof BigInteger || number instanceof BigDecimal) { + return dform.format(number, toAppendTo, pos); + } + return super.format(number, toAppendTo, pos); + } + + public DecimalFormatSymbols getDecimalFormatSymbols() { + return (DecimalFormatSymbols) symbols.clone(); + } + + @Override + public Currency getCurrency() { + final com.ibm.icu.util.Currency cur = dform.getCurrency(); + final String code = (cur == null) ? "XXX" : cur.getCurrencyCode(); //$NON-NLS-1$ + + return Currency.getInstance(code); + } + + public int getGroupingSize() { + return dform.getGroupingSize(); + } + + public int getMultiplier() { + return dform.getMultiplier(); + } + + public String getNegativePrefix() { + return dform.getNegativePrefix(); + } + + public String getNegativeSuffix() { + return dform.getNegativeSuffix(); + } + + public String getPositivePrefix() { + return dform.getPositivePrefix(); + } + + public String getPositiveSuffix() { + return dform.getPositiveSuffix(); + } + + @Override + public int hashCode() { + return dform.hashCode(); + } + + public boolean isDecimalSeparatorAlwaysShown() { + return dform.isDecimalSeparatorAlwaysShown(); + } + + public boolean isParseBigDecimal() { + return this.parseBigDecimal; + } + + @Override + public void setParseIntegerOnly(boolean value) { + // In this implementation, com.ibm.icu.text.DecimalFormat is wrapped to + // fulfill most of the format and parse feature. And this method is + // delegated to the wrapped instance of com.ibm.icu.text.DecimalFormat. + + dform.setParseIntegerOnly(value); + } + + @Override + public boolean isParseIntegerOnly() { + return dform.isParseIntegerOnly(); + } + + private static final Double NEGATIVE_ZERO_DOUBLE = new Double(-0.0); + + @Override + public Number parse(String string, ParsePosition position) { + Number number = dform.parse(string, position); + if (null == number) { + return null; + } + if (this.isParseBigDecimal()) { + if (number instanceof Long) { + return new BigDecimal(number.longValue()); + } + if ((number instanceof Double) && !((Double) number).isInfinite() + && !((Double) number).isNaN()) { + + return new BigDecimal(number.doubleValue()); + } + if (number instanceof BigInteger) { + return new BigDecimal(number.doubleValue()); + } + if (number instanceof com.ibm.icu.math.BigDecimal) { + return new BigDecimal(number.toString()); + } + return number; + } + if ((number instanceof com.ibm.icu.math.BigDecimal) + || (number instanceof BigInteger)) { + return new Double(number.doubleValue()); + } + + if (this.isParseIntegerOnly() && number.equals(NEGATIVE_ZERO_DOUBLE)) { + return new Long(0); + } + return number; + + } + + public void setDecimalFormatSymbols(DecimalFormatSymbols value) { + if (value != null) { + symbols = (DecimalFormatSymbols) value.clone(); + icuSymbols = dform.getDecimalFormatSymbols(); + copySymbols(icuSymbols, symbols); + dform.setDecimalFormatSymbols(icuSymbols); + } + } + + @Override + public void setCurrency(Currency currency) { + dform.setCurrency(com.ibm.icu.util.Currency.getInstance(currency + .getCurrencyCode())); + symbols.setCurrency(currency); + } + + public void setDecimalSeparatorAlwaysShown(boolean value) { + dform.setDecimalSeparatorAlwaysShown(value); + } + + public void setGroupingSize(int value) { + dform.setGroupingSize(value); + } + + @Override + public void setGroupingUsed(boolean value) { + dform.setGroupingUsed(value); + } + + @Override + public boolean isGroupingUsed() { + return dform.isGroupingUsed(); + } + + @Override + public void setMaximumFractionDigits(int value) { + super.setMaximumFractionDigits(value); + dform.setMaximumFractionDigits(value); + } + + @Override + public void setMaximumIntegerDigits(int value) { + super.setMaximumIntegerDigits(value); + dform.setMaximumIntegerDigits(value); + } + + @Override + public void setMinimumFractionDigits(int value) { + super.setMinimumFractionDigits(value); + dform.setMinimumFractionDigits(value); + } + + @Override + public void setMinimumIntegerDigits(int value) { + super.setMinimumIntegerDigits(value); + dform.setMinimumIntegerDigits(value); + } + + public void setMultiplier(int value) { + dform.setMultiplier(value); + } + + public void setNegativePrefix(String value) { + dform.setNegativePrefix(value); + } + + public void setNegativeSuffix(String value) { + dform.setNegativeSuffix(value); + } + + public void setPositivePrefix(String value) { + dform.setPositivePrefix(value); + } + + public void setPositiveSuffix(String value) { + dform.setPositiveSuffix(value); + } + + public void setParseBigDecimal(boolean newValue) { + this.parseBigDecimal = newValue; + } + + public String toLocalizedPattern() { + return dform.toLocalizedPattern(); + } + + public String toPattern() { + return dform.toPattern(); + } + + /* + * Copies decimal format symbols from text object to ICU one. + * + * @param icu the object which receives the new values. @param dfs the + * object which contains the new values. + */ + private void copySymbols(final com.ibm.icu.text.DecimalFormatSymbols icu, + final DecimalFormatSymbols dfs) { + Currency currency = dfs.getCurrency(); + if (currency == null) { + icu.setCurrency(com.ibm.icu.util.Currency.getInstance("XXX")); //$NON-NLS-1$ + } else { + icu.setCurrency(com.ibm.icu.util.Currency.getInstance(dfs + .getCurrency().getCurrencyCode())); + } + + icu.setCurrencySymbol(dfs.getCurrencySymbol()); + icu.setDecimalSeparator(dfs.getDecimalSeparator()); + icu.setDigit(dfs.getDigit()); + icu.setGroupingSeparator(dfs.getGroupingSeparator()); + icu.setInfinity(dfs.getInfinity()); + icu + .setInternationalCurrencySymbol(dfs + .getInternationalCurrencySymbol()); + icu.setMinusSign(dfs.getMinusSign()); + icu.setMonetaryDecimalSeparator(dfs.getMonetaryDecimalSeparator()); + icu.setNaN(dfs.getNaN()); + icu.setPatternSeparator(dfs.getPatternSeparator()); + icu.setPercent(dfs.getPercent()); + icu.setPerMill(dfs.getPerMill()); + icu.setZeroDigit(dfs.getZeroDigit()); + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DecimalFormatSymbols.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DecimalFormatSymbols.java new file mode 100644 index 000000000..92eec39e9 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/DecimalFormatSymbols.java @@ -0,0 +1,280 @@ +/* + * 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.text; + +import java.util.Arrays; +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TCloneable; +import org.teavm.classlib.java.util.TLocale; + +public final class DecimalFormatSymbols implements TCloneable, TSerializable { + + private final int ZeroDigit = 0, Digit = 1, DecimalSeparator = 2, + GroupingSeparator = 3, PatternSeparator = 4, Percent = 5, + PerMill = 6, Exponent = 7, MonetaryDecimalSeparator = 8, + MinusSign = 9; + + transient char[] patternChars; + + private transient Currency currency; + + private transient TLocale locale; + + private String infinity, NaN, currencySymbol, intlCurrencySymbol; + + /** + * Constructs a new {@code DecimalFormatSymbols} containing the symbols for + * the default locale. Best practice is to create a {@code DecimalFormat} + * and then to get the {@code DecimalFormatSymbols} from that object by + * calling {@link DecimalFormat#getDecimalFormatSymbols()}. + */ + public DecimalFormatSymbols() { + this(TLocale.getDefault()); + } + + /** + * Constructs a new DecimalFormatSymbols containing the symbols for the + * specified Locale. Best practice is to create a {@code DecimalFormat} + * and then to get the {@code DecimalFormatSymbols} from that object by + * calling {@link DecimalFormat#getDecimalFormatSymbols()}. + * + * @param locale + * the locale. + */ + public DecimalFormatSymbols(TLocale locale) { + this(locale, new com.ibm.icu.text.DecimalFormatSymbols(locale)); + } + + transient private com.ibm.icu.text.DecimalFormatSymbols icuSymbols; + + DecimalFormatSymbols(TLocale locale, com.ibm.icu.text.DecimalFormatSymbols icuSymbols) { + this.icuSymbols = icuSymbols; + infinity = icuSymbols.getInfinity(); + NaN = icuSymbols.getNaN(); + this.locale = locale; + currencySymbol = icuSymbols.getCurrencySymbol(); + intlCurrencySymbol = icuSymbols.getInternationalCurrencySymbol(); + if (locale.getCountry().length() == 0) { + currency = Currency.getInstance("XXX"); //$NON-NLS-1$ + } else { + currency = Currency.getInstance(locale); + } + patternChars = new char[10]; + patternChars[ZeroDigit] = icuSymbols.getZeroDigit(); + patternChars[Digit] = icuSymbols.getDigit(); + patternChars[DecimalSeparator] = icuSymbols.getDecimalSeparator(); + patternChars[GroupingSeparator] = icuSymbols.getGroupingSeparator(); + patternChars[PatternSeparator] = icuSymbols.getPatternSeparator(); + patternChars[Percent] = icuSymbols.getPercent(); + patternChars[PerMill] = icuSymbols.getPerMill(); + patternChars[Exponent] = icuSymbols.getExponentSeparator().charAt(0); + patternChars[MonetaryDecimalSeparator] = icuSymbols + .getMonetaryDecimalSeparator(); + patternChars[MinusSign] = icuSymbols.getMinusSign(); + } + + @Override + public Object clone() { + try { + DecimalFormatSymbols symbols = (DecimalFormatSymbols) super.clone(); + symbols.patternChars = patternChars.clone(); + return symbols; + } catch (CloneNotSupportedException e) { + return null; + } + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (!(object instanceof DecimalFormatSymbols)) { + return false; + } + DecimalFormatSymbols obj = (DecimalFormatSymbols) object; + return Arrays.equals(patternChars, obj.patternChars) + && infinity.equals(obj.infinity) && NaN.equals(obj.NaN) + && currencySymbol.equals(obj.currencySymbol) + && intlCurrencySymbol.equals(obj.intlCurrencySymbol); + } + + public Currency getCurrency() { + return currency; + } + + public String getInternationalCurrencySymbol() { + return intlCurrencySymbol; + } + + public String getCurrencySymbol() { + return currencySymbol; + } + + public char getDecimalSeparator() { + return patternChars[DecimalSeparator]; + } + + public char getDigit() { + return patternChars[Digit]; + } + + public char getGroupingSeparator() { + return patternChars[GroupingSeparator]; + } + + public String getInfinity() { + return infinity; + } + + String getLocalPatternChars() { + // Don't include the MonetaryDecimalSeparator or the MinusSign + return new String(patternChars, 0, patternChars.length - 2); + } + + public char getMinusSign() { + return patternChars[MinusSign]; + } + + public char getMonetaryDecimalSeparator() { + return patternChars[MonetaryDecimalSeparator]; + } + + public String getNaN() { + return NaN; + } + + public char getPatternSeparator() { + return patternChars[PatternSeparator]; + } + + public char getPercent() { + return patternChars[Percent]; + } + + public char getPerMill() { + return patternChars[PerMill]; + } + + public char getZeroDigit() { + return patternChars[ZeroDigit]; + } + + char getExponential() { + return patternChars[Exponent]; + } + + @Override + public int hashCode() { + return new String(patternChars).hashCode() + infinity.hashCode() + + NaN.hashCode() + currencySymbol.hashCode() + + intlCurrencySymbol.hashCode(); + } + + public void setCurrency(Currency currency) { + if (currency == null) { + throw new NullPointerException(); + } + if (currency == this.currency) { + return; + } + this.currency = currency; + intlCurrencySymbol = currency.getCurrencyCode(); + currencySymbol = currency.getSymbol(locale); + } + + public void setInternationalCurrencySymbol(String value) { + if (value == null) { + currency = null; + intlCurrencySymbol = null; + return; + } + + if (value.equals(intlCurrencySymbol)) { + return; + } + + try { + currency = Currency.getInstance(value); + currencySymbol = currency.getSymbol(locale); + } catch (IllegalArgumentException e) { + currency = null; + } + intlCurrencySymbol = value; + } + + public void setCurrencySymbol(String value) { + currencySymbol = value; + } + + public void setDecimalSeparator(char value) { + patternChars[DecimalSeparator] = value; + } + + public void setDigit(char value) { + patternChars[Digit] = value; + } + + public void setGroupingSeparator(char value) { + patternChars[GroupingSeparator] = value; + } + + public void setInfinity(String value) { + infinity = value; + } + + public void setMinusSign(char value) { + patternChars[MinusSign] = value; + } + + public void setMonetaryDecimalSeparator(char value) { + patternChars[MonetaryDecimalSeparator] = value; + } + + public void setNaN(String value) { + NaN = value; + } + + public void setPatternSeparator(char value) { + patternChars[PatternSeparator] = value; + } + + public void setPercent(char value) { + patternChars[Percent] = value; + } + + public void setPerMill(char value) { + patternChars[PerMill] = value; + } + + public void setZeroDigit(char value) { + patternChars[ZeroDigit] = value; + } + + void setExponential(char value) { + patternChars[Exponent] = value; + } + + TLocale getLocale(){ + return locale; + } + + com.ibm.icu.text.DecimalFormatSymbols getIcuSymbols() { + return icuSymbols; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/FieldPosition.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/FieldPosition.java new file mode 100644 index 000000000..de14cc1ba --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/FieldPosition.java @@ -0,0 +1,87 @@ +/* + * 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.text; + +public class FieldPosition { + private int myField, beginIndex, endIndex; + private Format.Field myAttribute; + + public FieldPosition(int field) { + myField = field; + } + + public FieldPosition(Format.Field attribute) { + myAttribute = attribute; + myField = -1; + } + + public FieldPosition(Format.Field attribute, int field) { + myAttribute = attribute; + myField = field; + } + + void clear() { + beginIndex = endIndex = 0; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof FieldPosition)) { + return false; + } + FieldPosition pos = (FieldPosition) object; + return myField == pos.myField && myAttribute == pos.myAttribute && beginIndex == pos.beginIndex && + endIndex == pos.endIndex; + } + + public int getBeginIndex() { + return beginIndex; + } + + public int getEndIndex() { + return endIndex; + } + + public int getField() { + return myField; + } + + public Format.Field getFieldAttribute() { + return myAttribute; + } + + @Override + public int hashCode() { + int attributeHash = (myAttribute == null) ? 0 : myAttribute.hashCode(); + return attributeHash + myField * 10 + beginIndex * 100 + endIndex; + } + + public void setBeginIndex(int index) { + beginIndex = index; + } + + public void setEndIndex(int index) { + endIndex = index; + } + + @Override + public String toString() { + return getClass().getName() + "[attribute=" + myAttribute + ", field=" + myField + ", beginIndex=" + + beginIndex + ", endIndex=" + endIndex + "]"; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/Format.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/Format.java new file mode 100644 index 000000000..9d9f3f093 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/Format.java @@ -0,0 +1,137 @@ +/* + * 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.text; + +import org.teavm.classlib.java.io.TSerializable; +import org.teavm.classlib.java.lang.TCloneable; + +public abstract class Format implements TSerializable, TCloneable { + public Format() { + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + return null; + } + } + + String convertPattern(String template, String fromChars, String toChars, boolean check) { + if (!check && fromChars.equals(toChars)) { + return template; + } + boolean quote = false; + StringBuilder output = new StringBuilder(); + int length = template.length(); + for (int i = 0; i < length; i++) { + int index; + char next = template.charAt(i); + if (next == '\'') { + quote = !quote; + } + if (!quote && (index = fromChars.indexOf(next)) != -1) { + output.append(toChars.charAt(index)); + } else if (check && !quote && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) { + throw new IllegalArgumentException("Invalid pattern char" + next + " in " + template); + } else { + output.append(next); + } + } + if (quote) { + throw new IllegalArgumentException("Unterminated quote"); + } + return output.toString(); + } + + public final String format(Object object) { + return format(object, new StringBuffer(), new FieldPosition(0)).toString(); + } + + public abstract StringBuffer format(Object object, StringBuffer buffer, FieldPosition field); + + public AttributedCharacterIterator formatToCharacterIterator(Object object) { + return new AttributedString(format(object)).getIterator(); + } + + public Object parseObject(String string) throws ParseException { + ParsePosition position = new ParsePosition(0); + Object result = parseObject(string, position); + if (position.getIndex() == 0) { + throw new ParseException("Format.parseObject(String) parse failure", position.getErrorIndex()); + } + return result; + } + + public abstract Object parseObject(String string, ParsePosition position); + + static boolean upTo(String string, ParsePosition position, StringBuffer buffer, char stop) { + int index = position.getIndex(), length = string.length(); + boolean lastQuote = false, quote = false; + while (index < length) { + char ch = string.charAt(index++); + if (ch == '\'') { + if (lastQuote) { + buffer.append('\''); + } + quote = !quote; + lastQuote = true; + } else if (ch == stop && !quote) { + position.setIndex(index); + return true; + } else { + lastQuote = false; + buffer.append(ch); + } + } + position.setIndex(index); + return false; + } + + static boolean upToWithQuotes(String string, ParsePosition position, StringBuffer buffer, char stop, char start) { + int index = position.getIndex(), length = string.length(), count = 1; + boolean quote = false; + while (index < length) { + char ch = string.charAt(index++); + if (ch == '\'') { + quote = !quote; + } + if (!quote) { + if (ch == stop) { + count--; + } + if (count == 0) { + position.setIndex(index); + return true; + } + if (ch == start) { + count++; + } + } + buffer.append(ch); + } + throw new IllegalArgumentException("Unmatched braces in the pattern"); + } + + public static class Field extends AttributedCharacterIterator.Attribute { + protected Field(String fieldName) { + super(fieldName); + } + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/NumberFormat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/NumberFormat.java new file mode 100644 index 000000000..f061e1202 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/NumberFormat.java @@ -0,0 +1,263 @@ +/* + * 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.text; + +import org.teavm.classlib.java.util.TLocale; + +public abstract class NumberFormat extends Format { + + private static final long serialVersionUID = -2308460125733713944L; + public static final int INTEGER_FIELD = 0; + public static final int FRACTION_FIELD = 1; + + private boolean groupingUsed = true, parseIntegerOnly = false; + + private int maximumIntegerDigits = 40, minimumIntegerDigits = 1, + maximumFractionDigits = 3, minimumFractionDigits = 0; + + public NumberFormat() { + } + + @Override + public Object clone() { + return super.clone(); + } + + @Override + public boolean equals(Object object) { + if (object == this) { + return true; + } + if (!(object instanceof NumberFormat)) { + return false; + } + NumberFormat obj = (NumberFormat) object; + return groupingUsed == obj.groupingUsed + && parseIntegerOnly == obj.parseIntegerOnly + && maximumFractionDigits == obj.maximumFractionDigits + && maximumIntegerDigits == obj.maximumIntegerDigits + && minimumFractionDigits == obj.minimumFractionDigits + && minimumIntegerDigits == obj.minimumIntegerDigits; + } + + public final String format(double value) { + return format(value, new StringBuffer(), new FieldPosition(0)) + .toString(); + } + + public abstract StringBuffer format(double value, StringBuffer buffer, + FieldPosition field); + + public final String format(long value) { + return format(value, new StringBuffer(), new FieldPosition(0)) + .toString(); + } + public abstract StringBuffer format(long value, StringBuffer buffer, + FieldPosition field); + + @Override + public StringBuffer format(Object object, StringBuffer buffer, + FieldPosition field) { + if (object instanceof Number) { + double dv = ((Number) object).doubleValue(); + long lv = ((Number) object).longValue(); + if (dv == lv) { + return format(lv, buffer, field); + } + return format(dv, buffer, field); + } + throw new IllegalArgumentException(); + } + + public static TLocale[] getAvailableLocales() { + return TLocale.getAvailableLocales(); + } + + public Currency getCurrency() { + throw new UnsupportedOperationException(); + } + + public final static NumberFormat getCurrencyInstance() { + return getCurrencyInstance(TLocale.getDefault()); + } + + public static NumberFormat getCurrencyInstance(TLocale locale) { + com.ibm.icu.text.DecimalFormat icuFormat = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat + .getCurrencyInstance(locale); + String pattern = icuFormat.toPattern(); + return new DecimalFormat(pattern, new DecimalFormatSymbols(locale)); + } + + public final static NumberFormat getIntegerInstance() { + return getIntegerInstance(TLocale.getDefault()); + } + + public static NumberFormat getIntegerInstance(TLocale locale) { + com.ibm.icu.text.DecimalFormat icuFormat = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat + .getIntegerInstance(locale); + String pattern = icuFormat.toPattern(); + DecimalFormat format = new DecimalFormat(pattern, new DecimalFormatSymbols(locale)); + format.setParseIntegerOnly(true); + return format; + + } + + public final static NumberFormat getInstance() { + return getNumberInstance(); + } + + public static NumberFormat getInstance(TLocale locale) { + return getNumberInstance(locale); + } + + public int getMaximumFractionDigits() { + return maximumFractionDigits; + } + + public int getMaximumIntegerDigits() { + return maximumIntegerDigits; + } + + public int getMinimumFractionDigits() { + return minimumFractionDigits; + } + + public int getMinimumIntegerDigits() { + return minimumIntegerDigits; + } + + public final static NumberFormat getNumberInstance() { + return getNumberInstance(TLocale.getDefault()); + } + + public static NumberFormat getNumberInstance(TLocale locale) { + com.ibm.icu.text.DecimalFormat icuFormat = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat + .getNumberInstance(locale); + String pattern = icuFormat.toPattern(); + return new DecimalFormat(pattern, new DecimalFormatSymbols(locale, icuFormat.getDecimalFormatSymbols()), icuFormat); + } + + public final static NumberFormat getPercentInstance() { + return getPercentInstance(TLocale.getDefault()); + } + + public static NumberFormat getPercentInstance(TLocale locale) { + com.ibm.icu.text.DecimalFormat icuFormat = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat + .getPercentInstance(locale); + String pattern = icuFormat.toPattern(); + return new DecimalFormat(pattern, new DecimalFormatSymbols(locale)); + } + + @Override + public int hashCode() { + return (groupingUsed ? 1231 : 1237) + (parseIntegerOnly ? 1231 : 1237) + + maximumFractionDigits + maximumIntegerDigits + + minimumFractionDigits + minimumIntegerDigits; + } + + public boolean isGroupingUsed() { + return groupingUsed; + } + + public boolean isParseIntegerOnly() { + return parseIntegerOnly; + } + + public Number parse(String string) throws ParseException { + ParsePosition pos = new ParsePosition(0); + Number number = parse(string, pos); + if (pos.getIndex() == 0) { + throw new ParseException("Unparseable number: " + string, pos.getErrorIndex()); + } + return number; + } + + public abstract Number parse(String string, ParsePosition position); + + @Override + public final Object parseObject(String string, ParsePosition position) { + if (position == null) { + throw new NullPointerException("position is null"); + } + + try { + return parse(string, position); + } catch (Exception e) { + return null; + } + } + + public void setCurrency(Currency currency) { + throw new UnsupportedOperationException(); + } + + public void setGroupingUsed(boolean value) { + groupingUsed = value; + } + + public void setMaximumFractionDigits(int value) { + maximumFractionDigits = value < 0 ? 0 : value; + if (maximumFractionDigits < minimumFractionDigits) { + minimumFractionDigits = maximumFractionDigits; + } + } + + public void setMaximumIntegerDigits(int value) { + maximumIntegerDigits = value < 0 ? 0 : value; + if (maximumIntegerDigits < minimumIntegerDigits) { + minimumIntegerDigits = maximumIntegerDigits; + } + } + + public void setMinimumFractionDigits(int value) { + minimumFractionDigits = value < 0 ? 0 : value; + if (maximumFractionDigits < minimumFractionDigits) { + maximumFractionDigits = minimumFractionDigits; + } + } + + public void setMinimumIntegerDigits(int value) { + minimumIntegerDigits = value < 0 ? 0 : value; + if (maximumIntegerDigits < minimumIntegerDigits) { + maximumIntegerDigits = minimumIntegerDigits; + } + } + + public void setParseIntegerOnly(boolean value) { + parseIntegerOnly = value; + } + + + public static class Field extends Format.Field { + public static final Field SIGN = new Field("sign"); + public static final Field INTEGER = new Field("integer"); + public static final Field FRACTION = new Field("fraction"); + public static final Field EXPONENT = new Field("exponent"); + public static final Field EXPONENT_SIGN = new Field("exponent sign"); + public static final Field EXPONENT_SYMBOL = new Field("exponent symbol"); + public static final Field DECIMAL_SEPARATOR = new Field("decimal separator"); + public static final Field GROUPING_SEPARATOR = new Field("grouping separator"); + public static final Field PERCENT = new Field("percent"); + public static final Field PERMILLE = new Field("per mille"); + public static final Field CURRENCY = new Field("currency"); + + protected Field(String fieldName) { + super(fieldName); + } + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/ParseException.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/ParseException.java new file mode 100644 index 000000000..fa1c7af84 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/ParseException.java @@ -0,0 +1,51 @@ +/* + * 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.text; + +/** + * Thrown when the string being parsed is not in the correct form. + */ +public class ParseException extends Exception { + + private static final long serialVersionUID = 2703218443322787634L; + + private int errorOffset; + + /** + * Constructs a new instance of this class with its stack trace, detail + * message and the location of the error filled in. + * + * @param detailMessage + * the detail message for this exception. + * @param location + * the index at which the parse exception occurred. + */ + public ParseException(String detailMessage, int location) { + super(detailMessage); + errorOffset = location; + } + + /** + * Returns the index at which this parse exception occurred. + * + * @return the location of this exception in the parsed string. + */ + public int getErrorOffset() { + return errorOffset; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/ParsePosition.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/ParsePosition.java new file mode 100644 index 000000000..2c5adb00c --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/ParsePosition.java @@ -0,0 +1,62 @@ +/* + * 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.text; + +public class ParsePosition { + + private int currentPosition, errorIndex = -1; + + public ParsePosition(int index) { + currentPosition = index; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof ParsePosition)) { + return false; + } + ParsePosition pos = (ParsePosition) object; + return currentPosition == pos.currentPosition && errorIndex == pos.errorIndex; + } + + public int getErrorIndex() { + return errorIndex; + } + + public int getIndex() { + return currentPosition; + } + + @Override + public int hashCode() { + return currentPosition + errorIndex; + } + + public void setErrorIndex(int index) { + errorIndex = index; + } + + public void setIndex(int index) { + currentPosition = index; + } + + @Override + public String toString() { + return getClass().getName() + "[index=" + currentPosition + ", errorIndex=" + errorIndex + "]"; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/text/SimpleDateFormat.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/SimpleDateFormat.java new file mode 100644 index 000000000..7039c24e9 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/text/SimpleDateFormat.java @@ -0,0 +1,597 @@ +/* + * 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.text; + +import org.teavm.classlib.java.util.*; + +public class SimpleDateFormat extends DateFormat { + + private static final long serialVersionUID = 4774881970558875024L; + + private static final String patternChars = "GyMdkHmsSEDFwWahKzYeugAZvcLQqV"; //$NON-NLS-1$ + + private String pattern; + + private DateFormatSymbols formatData; + + transient private int creationYear; + + private Date defaultCenturyStart; + + private transient String tzId; + + private transient com.ibm.icu.text.SimpleDateFormat icuFormat; + + public SimpleDateFormat() { + this(TLocale.getDefault()); + icuFormat = new com.ibm.icu.text.SimpleDateFormat(); + icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId)); + pattern = (String) getInternalField("pattern", icuFormat); + formatData = new DateFormatSymbols(TLocale.getDefault()); + } + + public SimpleDateFormat(String pattern) { + this(pattern, TLocale.getDefault()); + } + + private void validateFormat(char format) { + int index = patternChars.indexOf(format); + if (index == -1) { + throw new IllegalArgumentException("Unknown pattern character - " + format); + } + } + + private void validatePattern(String template) { + boolean quote = false; + int next, last = -1, count = 0; + + final int patternLength = template.length(); + for (int i = 0; i < patternLength; i++) { + next = (template.charAt(i)); + if (next == '\'') { + if (count > 0) { + validateFormat((char) last); + count = 0; + } + if (last == next) { + last = -1; + } else { + last = next; + } + quote = !quote; + continue; + } + if (!quote && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) { + if (last == next) { + count++; + } else { + if (count > 0) { + validateFormat((char) last); + } + last = next; + count = 1; + } + } else { + if (count > 0) { + validateFormat((char) last); + count = 0; + } + last = -1; + } + } + if (count > 0) { + validateFormat((char) last); + } + + if (quote) { + throw new IllegalArgumentException("Unterminated quote"); + } + + } + + public SimpleDateFormat(String template, DateFormatSymbols value) { + this(TLocale.getDefault()); + validatePattern(template); + icuFormat = new com.ibm.icu.text.SimpleDateFormat(template, Locale.getDefault()); + icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId)); + pattern = template; + formatData = (DateFormatSymbols) value.clone(); + } + + private void copySymbols(DateFormatSymbols value, com.ibm.icu.text.DateFormatSymbols icuSymbols) { + icuSymbols.setAmPmStrings(value.getAmPmStrings()); + icuSymbols.setEras(value.getEras()); + icuSymbols.setLocalPatternChars(value.getLocalPatternChars()); + icuSymbols.setMonths(value.getMonths()); + icuSymbols.setShortMonths(value.getShortMonths()); + icuSymbols.setShortWeekdays(value.getShortWeekdays()); + icuSymbols.setWeekdays(value.getWeekdays()); + icuSymbols.setZoneStrings(value.getZoneStrings()); + } + + public SimpleDateFormat(String template, TLocale locale) { + this(locale); + validatePattern(template); + icuFormat = new com.ibm.icu.text.SimpleDateFormat(template, locale); + icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId)); + pattern = template; + formatData = new DateFormatSymbols(locale, icuFormat.getDateFormatSymbols()); + } + + SimpleDateFormat(TLocale locale, com.ibm.icu.text.SimpleDateFormat icuFormat) { + this(locale); + this.icuFormat = icuFormat; + this.icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId)); + pattern = (String) Format.getInternalField("pattern", icuFormat); + formatData = new DateFormatSymbols(locale); + } + + private SimpleDateFormat(TLocale locale) { + numberFormat = NumberFormat.getInstance(locale); + numberFormat.setParseIntegerOnly(true); + numberFormat.setGroupingUsed(false); + calendar = new GregorianCalendar(locale); + calendar.add(Calendar.YEAR, -80); + tzId = calendar.getTimeZone().getID(); + creationYear = calendar.get(Calendar.YEAR); + defaultCenturyStart = calendar.getTime(); + } + + public void applyLocalizedPattern(String template) { + icuFormat.applyLocalizedPattern(template); + pattern = icuFormat.toPattern(); + } + + public void applyPattern(String template) { + validatePattern(template); + /* + * ICU spec explicitly mentions that "ICU interprets a single 'y' + * differently than Java." We need to do a trick here to follow Java + * spec. + */ + String templateForICU = patternForICU(template); + icuFormat.applyPattern(templateForICU); + pattern = template; + } + + @SuppressWarnings("nls") + private String patternForICU(String p) { + String[] subPatterns = p.split("'"); + boolean quote = false; + boolean first = true; + StringBuilder result = new StringBuilder(); + for (String subPattern : subPatterns) { + if (!quote) { + // replace 'y' with 'yy' for ICU to follow Java spec + result.append((first ? "" : "'") + subPattern.replaceAll("(? fields = new TArrayList<>(); + + // format the date, and find fields + formatImpl(date, buffer, null, fields); + + // create and AttributedString with the formatted buffer + AttributedString as = new AttributedString(buffer.toString()); + + // add DateFormat field attributes to the AttributedString + for (int i = 0; i < fields.size(); i++) { + FieldPosition pos = fields.get(i); + Format.Field attribute = pos.getFieldAttribute(); + as.addAttribute(attribute, attribute, pos.getBeginIndex(), pos.getEndIndex()); + } + + // return the CharacterIterator from AttributedString + return as.getIterator(); + } + + private StringBuffer formatImpl(Date date, StringBuffer buffer, FieldPosition field, TList fields) { + + boolean quote = false; + int next, last = -1, count = 0; + calendar.setTime(date); + if (field != null) { + field.clear(); + } + + final int patternLength = pattern.length(); + for (int i = 0; i < patternLength; i++) { + next = (pattern.charAt(i)); + if (next == '\'') { + if (count > 0) { + append(buffer, field, fields, (char) last, count); + count = 0; + } + if (last == next) { + buffer.append('\''); + last = -1; + } else { + last = next; + } + quote = !quote; + continue; + } + if (!quote && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) { + if (last == next) { + count++; + } else { + if (count > 0) { + append(buffer, field, fields, (char) last, count); + } + last = next; + count = 1; + } + } else { + if (count > 0) { + append(buffer, field, fields, (char) last, count); + count = 0; + } + last = -1; + buffer.append((char) next); + } + } + if (count > 0) { + append(buffer, field, fields, (char) last, count); + } + return buffer; + } + + private void append(StringBuffer buffer, FieldPosition position, TList fields, char format, int count) { + int field = -1; + int index = patternChars.indexOf(format); + if (index == -1) { + throw new IllegalArgumentException("Unknown pattern character - " + format); + } + + int beginPosition = buffer.length(); + Field dateFormatField = null; + switch (index) { + case ERA_FIELD: + dateFormatField = Field.ERA; + buffer.append(formatData.eras[calendar.get(Calendar.ERA)]); + break; + case YEAR_FIELD: + dateFormatField = Field.YEAR; + int year = calendar.get(Calendar.YEAR); + if (count < 4) { + appendNumber(buffer, 2, year % 100); + } else { + appendNumber(buffer, count, year); + } + break; + case MONTH_FIELD: + dateFormatField = Field.MONTH; + int month = calendar.get(Calendar.MONTH); + if (count <= 2) { + appendNumber(buffer, count, month + 1); + } else if (count == 3) { + buffer.append(formatData.shortMonths[month]); + } else { + buffer.append(formatData.months[month]); + } + break; + case DATE_FIELD: + dateFormatField = Field.DAY_OF_MONTH; + field = Calendar.DATE; + break; + case HOUR_OF_DAY1_FIELD: // k + dateFormatField = Field.HOUR_OF_DAY1; + int hour = calendar.get(Calendar.HOUR_OF_DAY); + appendNumber(buffer, count, hour == 0 ? 24 : hour); + break; + case HOUR_OF_DAY0_FIELD: // H + dateFormatField = Field.HOUR_OF_DAY0; + field = Calendar.HOUR_OF_DAY; + break; + case MINUTE_FIELD: + dateFormatField = Field.MINUTE; + field = Calendar.MINUTE; + break; + case SECOND_FIELD: + dateFormatField = Field.SECOND; + field = Calendar.SECOND; + break; + case MILLISECOND_FIELD: + dateFormatField = Field.MILLISECOND; + int value = calendar.get(Calendar.MILLISECOND); + appendNumber(buffer, count, value); + break; + case DAY_OF_WEEK_FIELD: + dateFormatField = Field.DAY_OF_WEEK; + int day = calendar.get(Calendar.DAY_OF_WEEK); + if (count < 4) { + buffer.append(formatData.shortWeekdays[day]); + } else { + buffer.append(formatData.weekdays[day]); + } + break; + case DAY_OF_YEAR_FIELD: + dateFormatField = Field.DAY_OF_YEAR; + field = Calendar.DAY_OF_YEAR; + break; + case DAY_OF_WEEK_IN_MONTH_FIELD: + dateFormatField = Field.DAY_OF_WEEK_IN_MONTH; + field = Calendar.DAY_OF_WEEK_IN_MONTH; + break; + case WEEK_OF_YEAR_FIELD: + dateFormatField = Field.WEEK_OF_YEAR; + field = Calendar.WEEK_OF_YEAR; + break; + case WEEK_OF_MONTH_FIELD: + dateFormatField = Field.WEEK_OF_MONTH; + field = Calendar.WEEK_OF_MONTH; + break; + case AM_PM_FIELD: + dateFormatField = Field.AM_PM; + buffer.append(formatData.ampms[calendar.get(Calendar.AM_PM)]); + break; + case HOUR1_FIELD: // h + dateFormatField = Field.HOUR1; + hour = calendar.get(Calendar.HOUR); + appendNumber(buffer, count, hour == 0 ? 12 : hour); + break; + case HOUR0_FIELD: // K + dateFormatField = Field.HOUR0; + field = Calendar.HOUR; + break; + case TIMEZONE_FIELD: // z + dateFormatField = Field.TIME_ZONE; + appendTimeZone(buffer, count, true); + break; + case com.ibm.icu.text.DateFormat.TIMEZONE_RFC_FIELD: // Z + dateFormatField = Field.TIME_ZONE; + appendTimeZone(buffer, count, false); + break; + } + if (field != -1) { + appendNumber(buffer, count, calendar.get(field)); + } + + if (fields != null) { + position = new FieldPosition(dateFormatField); + position.setBeginIndex(beginPosition); + position.setEndIndex(buffer.length()); + fields.add(position); + } else { + // Set to the first occurrence + if ((position.getFieldAttribute() == dateFormatField || (position.getFieldAttribute() == null && position + .getField() == index)) && position.getEndIndex() == 0) { + position.setBeginIndex(beginPosition); + position.setEndIndex(buffer.length()); + } + } + } + + private void appendTimeZone(StringBuffer buffer, int count, boolean generalTimezone) { + // cannot call TimeZone.getDisplayName() because it would not use + // the DateFormatSymbols of this SimpleDateFormat + + if (generalTimezone) { + String id = calendar.getTimeZone().getID(); + String[][] zones = formatData.getZoneStrings(); + String[] zone = null; + for (String[] element : zones) { + if (id.equals(element[0])) { + zone = element; + break; + } + } + if (zone == null) { + int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); + char sign = '+'; + if (offset < 0) { + sign = '-'; + offset = -offset; + } + buffer.append("GMT"); + buffer.append(sign); + appendNumber(buffer, 2, offset / 3600000); + buffer.append(':'); + appendNumber(buffer, 2, (offset % 3600000) / 60000); + } else { + int daylight = calendar.get(Calendar.DST_OFFSET) == 0 ? 0 : 2; + if (count < 4) { + buffer.append(zone[2 + daylight]); + } else { + buffer.append(zone[1 + daylight]); + } + } + } else { + int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); + char sign = '+'; + if (offset < 0) { + sign = '-'; + offset = -offset; + } + buffer.append(sign); + appendNumber(buffer, 2, offset / 3600000); + appendNumber(buffer, 2, (offset % 3600000) / 60000); + } + } + + private void appendNumber(StringBuffer buffer, int count, int value) { + int minimumIntegerDigits = numberFormat.getMinimumIntegerDigits(); + numberFormat.setMinimumIntegerDigits(count); + numberFormat.format(new Integer(value), buffer, new FieldPosition(0)); + numberFormat.setMinimumIntegerDigits(minimumIntegerDigits); + } + + @Override + public StringBuffer format(Date date, StringBuffer buffer, FieldPosition fieldPos) { + String id = calendar.getTimeZone().getID(); + if (!tzId.equals(id)) { + tzId = id; + icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId)); + } + // As ICU has its own implementation for DateFormat.Field, we need to + // pass an ICU instance of DateFormat.Field to the FieldPosition to get + // the begin and end index. + StringBuffer result = null; + Format.Field attribute = fieldPos.getFieldAttribute(); + if (attribute instanceof DateFormat.Field) { + com.ibm.icu.text.DateFormat.Field icuAttribute = toICUField((DateFormat.Field) attribute); + int field = fieldPos.getField(); + FieldPosition icuFieldPos = new FieldPosition(icuAttribute, field); + result = icuFormat.format(date, buffer, icuFieldPos); + fieldPos.setBeginIndex(icuFieldPos.getBeginIndex()); + fieldPos.setEndIndex(icuFieldPos.getEndIndex()); + return result; + } + return icuFormat.format(date, buffer, fieldPos); + } + + private com.ibm.icu.text.DateFormat.Field toICUField(DateFormat.Field attribute) { + com.ibm.icu.text.DateFormat.Field icuAttribute = null; + + if (attribute == DateFormat.Field.ERA) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.ERA; + } else if (attribute == DateFormat.Field.YEAR) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.YEAR; + } else if (attribute == DateFormat.Field.MONTH) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.MONTH; + } else if (attribute == DateFormat.Field.HOUR_OF_DAY0) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.HOUR_OF_DAY0; + } else if (attribute == DateFormat.Field.HOUR_OF_DAY1) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.HOUR_OF_DAY1; + } else if (attribute == DateFormat.Field.MINUTE) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.MINUTE; + } else if (attribute == DateFormat.Field.SECOND) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.SECOND; + } else if (attribute == DateFormat.Field.MILLISECOND) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.MILLISECOND; + } else if (attribute == DateFormat.Field.DAY_OF_WEEK) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.DAY_OF_WEEK; + } else if (attribute == DateFormat.Field.DAY_OF_MONTH) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.DAY_OF_MONTH; + } else if (attribute == DateFormat.Field.DAY_OF_YEAR) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.DAY_OF_YEAR; + } else if (attribute == DateFormat.Field.DAY_OF_WEEK_IN_MONTH) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.DAY_OF_WEEK_IN_MONTH; + } else if (attribute == DateFormat.Field.WEEK_OF_YEAR) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.WEEK_OF_YEAR; + } else if (attribute == DateFormat.Field.WEEK_OF_MONTH) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.WEEK_OF_MONTH; + } else if (attribute == DateFormat.Field.AM_PM) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.AM_PM; + } else if (attribute == DateFormat.Field.HOUR0) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.HOUR0; + } else if (attribute == DateFormat.Field.HOUR1) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.HOUR1; + } else if (attribute == DateFormat.Field.TIME_ZONE) { + icuAttribute = com.ibm.icu.text.DateFormat.Field.TIME_ZONE; + } + + return icuAttribute; + } + + public Date get2DigitYearStart() { + return defaultCenturyStart; + } + + public DateFormatSymbols getDateFormatSymbols() { + // Return a clone so the arrays in the ResourceBundle are not modified + return (DateFormatSymbols) formatData.clone(); + } + + @Override + public int hashCode() { + return super.hashCode() + pattern.hashCode() + formatData.hashCode() + creationYear; + } + + @Override + public Date parse(String string, ParsePosition position) { + String id = calendar.getTimeZone().getID(); + if (!tzId.equals(id)) { + tzId = id; + icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId)); + } + icuFormat.setLenient(calendar.isLenient()); + return icuFormat.parse(string, position); + } + + public void set2DigitYearStart(Date date) { + icuFormat.set2DigitYearStart(date); + defaultCenturyStart = date; + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + creationYear = cal.get(Calendar.YEAR); + } + + public void setDateFormatSymbols(DateFormatSymbols value) { + com.ibm.icu.text.DateFormatSymbols icuSymbols = new com.ibm.icu.text.DateFormatSymbols(); + copySymbols(value, icuSymbols); + icuFormat.setDateFormatSymbols(icuSymbols); + formatData = (DateFormatSymbols) value.clone(); + } + + public String toLocalizedPattern() { + return icuFormat.toLocalizedPattern(); + } + + public String toPattern() { + return pattern; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java index 444558a8a..6c074f2ad 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java @@ -32,12 +32,12 @@ package org.teavm.classlib.java.util; -import java.text.DateFormat; -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.lang.TCloneable; import org.teavm.classlib.java.lang.TComparable; +import org.teavm.classlib.java.text.DateFormat; +import org.teavm.classlib.java.text.DateFormatSymbols; +import org.teavm.classlib.java.text.SimpleDateFormat; public class Date implements TSerializable, TCloneable, TComparable { @@ -104,6 +104,7 @@ public class Date implements TSerializable, TCloneable, TComparable { } } + @Override public int compareTo(Date date) { if (milliseconds < date.milliseconds) { return -1; diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java index 323727add..9a2ec1fd2 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java @@ -271,20 +271,6 @@ public abstract class TimeZone implements TSerializable, TCloneable { private static void setICUDefaultTimeZone(TimeZone timezone) { final com.ibm.icu.util.TimeZone icuTZ = com.ibm.icu.util.TimeZone.getTimeZone(timezone.getID()); - - AccessController.doPrivileged(new PrivilegedAction() { - public java.lang.reflect.Field run() { - java.lang.reflect.Field field = null; - try { - field = com.ibm.icu.util.TimeZone.class.getDeclaredField("defaultZone"); - field.setAccessible(true); - field.set("defaultZone", icuTZ); - } catch (Exception e) { - return null; - } - return field; - } - }); } public void setID(String name) { From 7ef412a9f1ef329c013d1771c73a8939983058d8 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sun, 18 May 2014 20:00:52 +0400 Subject: [PATCH 4/4] Cleanup --- .../classlib/impl/unicode/CLDRHelper.java | 26 + .../teavm/classlib/java/util/Calendar.java | 50 +- .../org/teavm/classlib/java/util/Date.java | 45 +- .../classlib/java/util/GregorianCalendar.java | 533 ++++--------- .../classlib/java/util/SimpleTimeZone.java | 373 --------- .../teavm/classlib/java/util/TimeZone.java | 288 ------- .../teavm/classlib/java/util/TimeZones.java | 707 ------------------ 7 files changed, 212 insertions(+), 1810 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRHelper.java delete mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java delete mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java delete mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZones.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRHelper.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRHelper.java new file mode 100644 index 000000000..d50257933 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/unicode/CLDRHelper.java @@ -0,0 +1,26 @@ +/* + * Copyright 2014 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.unicode; + +/** + * + * @author Alexey Andreev + */ +public class CLDRHelper { + public static String getCode(String language, String country) { + return !country.isEmpty() ? language + "-" + country : language; + } +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java index 9ff267fed..da144726d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Calendar.java @@ -32,6 +32,7 @@ package org.teavm.classlib.java.util; +import org.teavm.classlib.impl.unicode.CLDRHelper; import org.teavm.classlib.java.io.TSerializable; import org.teavm.classlib.java.lang.TCloneable; import org.teavm.classlib.java.lang.TComparable; @@ -57,8 +58,6 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable private int minimalDaysInFirstWeek; - private TimeZone zone; - public static final int JANUARY = 0; public static final int FEBRUARY = 1; @@ -147,24 +146,24 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable "MINUTE=", "SECOND=", "MILLISECOND=", "ZONE_OFFSET=", "DST_OFFSET=" }; protected Calendar() { - this(TimeZone.getDefault(), TLocale.getDefault()); + this(TLocale.getDefault()); } - Calendar(TimeZone timezone) { + protected Calendar(TLocale locale) { fields = new int[FIELD_COUNT]; isSet = new boolean[FIELD_COUNT]; areFieldsSet = isTimeSet = false; setLenient(true); - setTimeZone(timezone); + String localeCode = CLDRHelper.getCode(locale.getLanguage(), locale.getCountry()); + setFirstDayOfWeek(getFirstDayOfWeek(localeCode)); + setMinimalDaysInFirstWeek(getMinimalDaysInFirstWeek(localeCode)); } - protected Calendar(TimeZone timezone, TLocale locale) { - this(timezone); - com.ibm.icu.util.Calendar icuCalendar = com.ibm.icu.util.Calendar.getInstance( - com.ibm.icu.util.SimpleTimeZone.getTimeZone(timezone.getID()), locale); - setFirstDayOfWeek(icuCalendar.getFirstDayOfWeek()); - setMinimalDaysInFirstWeek(icuCalendar.getMinimalDaysInFirstWeek()); - } + // TODO: implement using CLDR + private static native int getFirstDayOfWeek(String localeCode); + + // TODO: implement using CLDR + private static native int getMinimalDaysInFirstWeek(String localeCode); abstract public void add(int field, int value); @@ -202,7 +201,6 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable Calendar clone = (Calendar) super.clone(); clone.fields = fields.clone(); clone.isSet = isSet.clone(); - clone.zone = (TimeZone) zone.clone(); return clone; } catch (CloneNotSupportedException e) { return null; @@ -235,8 +233,7 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable Calendar cal = (Calendar) object; return getTimeInMillis() == cal.getTimeInMillis() && isLenient() == cal.isLenient() && getFirstDayOfWeek() == cal.getFirstDayOfWeek() && - getMinimalDaysInFirstWeek() == cal.getMinimalDaysInFirstWeek() && - getTimeZone().equals(cal.getTimeZone()); + getMinimalDaysInFirstWeek() == cal.getMinimalDaysInFirstWeek(); } public int get(int field) { @@ -298,14 +295,6 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return new GregorianCalendar(locale); } - public static synchronized Calendar getInstance(TimeZone timezone) { - return new GregorianCalendar(timezone); - } - - public static synchronized Calendar getInstance(TimeZone timezone, TLocale locale) { - return new GregorianCalendar(timezone, locale); - } - abstract public int getLeastMaximum(int field); abstract public int getMaximum(int field); @@ -328,14 +317,9 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable return time; } - public TimeZone getTimeZone() { - return zone; - } - @Override public int hashCode() { - return (isLenient() ? 1237 : 1231) + getFirstDayOfWeek() + getMinimalDaysInFirstWeek() + - getTimeZone().hashCode(); + return (isLenient() ? 1237 : 1231) + getFirstDayOfWeek() + getMinimalDaysInFirstWeek(); } protected final int internalGet(int field) { @@ -417,17 +401,11 @@ public abstract class Calendar implements TSerializable, TCloneable, TComparable } } - public void setTimeZone(TimeZone timezone) { - zone = timezone; - areFieldsSet = false; - } - @Override - @SuppressWarnings("nls") public String toString() { StringBuilder result = new StringBuilder(getClass().getName() + "[time=" + (isTimeSet ? String.valueOf(time) : "?") + ",areFieldsSet=" + areFieldsSet + ",lenient=" + lenient + - ",zone=" + zone + ",firstDayOfWeek=" + firstDayOfWeek + ",minimalDaysInFirstWeek=" + + ",firstDayOfWeek=" + firstDayOfWeek + ",minimalDaysInFirstWeek=" + minimalDaysInFirstWeek); for (int i = 0; i < FIELD_COUNT; i++) { result.append(','); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java index 6c074f2ad..aed8c7592 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/Date.java @@ -37,7 +37,6 @@ import org.teavm.classlib.java.lang.TCloneable; import org.teavm.classlib.java.lang.TComparable; import org.teavm.classlib.java.text.DateFormat; import org.teavm.classlib.java.text.DateFormatSymbols; -import org.teavm.classlib.java.text.SimpleDateFormat; public class Date implements TSerializable, TCloneable, TComparable { @@ -405,16 +404,12 @@ public class Date implements TSerializable, TCloneable, TComparable { @Deprecated public String toGMTString() { - SimpleDateFormat format1 = new SimpleDateFormat("d MMM ", TLocale.US); - SimpleDateFormat format2 = new SimpleDateFormat(" HH:mm:ss 'GMT'", TLocale.US); - TimeZone gmtZone = TimeZone.getTimeZone("GMT"); - format1.setTimeZone(gmtZone); - format2.setTimeZone(gmtZone); - GregorianCalendar gc = new GregorianCalendar(gmtZone); - gc.setTimeInMillis(milliseconds); - return format1.format(this) + gc.get(Calendar.YEAR) + format2.format(this); + return toGTMString((int)(milliseconds >> 32), (int)milliseconds); } + // TODO: implement using native JavaScript method + private static native String toGTMString(int hidate, int lodate); + @Deprecated public String toLocaleString() { return DateFormat.getDateTimeInstance().format(this); @@ -422,30 +417,12 @@ public class Date implements TSerializable, TCloneable, TComparable { @Override public String toString() { - Calendar cal = new GregorianCalendar(milliseconds); - TimeZone zone = cal.getTimeZone(); - String zoneName = zone.getDisplayName(zone.inDaylightTime(this), TimeZone.SHORT, TLocale.getDefault()); - - StringBuilder sb = new StringBuilder(34); - sb.append(dayOfWeekNames[cal.get(Calendar.DAY_OF_WEEK) - 1]); - sb.append(' '); - sb.append(monthNames[cal.get(Calendar.MONTH)]); - sb.append(' '); - sb.append(toTwoDigits(cal.get(Calendar.DAY_OF_MONTH))); - sb.append(' '); - sb.append(toTwoDigits(cal.get(Calendar.HOUR_OF_DAY))); - sb.append(':'); - sb.append(toTwoDigits(cal.get(Calendar.MINUTE))); - sb.append(':'); - sb.append(toTwoDigits(cal.get(Calendar.SECOND))); - sb.append(' '); - sb.append(zoneName); - sb.append(' '); - sb.append(cal.get(Calendar.YEAR)); - - return sb.toString(); + return toString((int)(milliseconds >> 32), (int)milliseconds); } + // TODO: implement using native JavaScript method + private static native String toString(int hidate, int lodate); + private String toTwoDigits(int digit) { if (digit >= 10) { return "" + digit; @@ -456,10 +433,8 @@ public class Date implements TSerializable, TCloneable, TComparable { @Deprecated public static long UTC(int year, int month, int day, int hour, int minute, int second) { - GregorianCalendar cal = new GregorianCalendar(false); - cal.setTimeZone(TimeZone.getTimeZone("GMT")); - cal.set(1900 + year, month, day, hour, minute, second); - return cal.getTimeInMillis(); + Date date = new Date(year, month, day, hour, minute, second); + return date.milliseconds - date.getTimezoneOffset(); } private static int zone(String text) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java index 426a2406c..df990289c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/GregorianCalendar.java @@ -34,23 +34,19 @@ public class GregorianCalendar extends Calendar { private transient int changeYear = 1582; - private transient int julianSkew = ((changeYear - 2000) / 400) - + julianError() - ((changeYear - 2000) / 100); + private transient int julianSkew = ((changeYear - 2000) / 400) + julianError() - ((changeYear - 2000) / 100); - static byte[] DaysInMonth = new byte[] { 31, 28, 31, 30, 31, 30, 31, 31, - 30, 31, 30, 31 }; + static byte[] DaysInMonth = new byte[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - private static int[] DaysInYear = new int[] { 0, 31, 59, 90, 120, 151, 181, - 212, 243, 273, 304, 334 }; + private static int[] DaysInYear = new int[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - private static int[] maximums = new int[] { 1, 292278994, 11, 53, 6, 31, - 366, 7, 6, 1, 11, 23, 59, 59, 999, 14 * 3600 * 1000, 7200000 }; + private static int[] maximums = new int[] { 1, 292278994, 11, 53, 6, 31, 366, 7, 6, 1, 11, 23, 59, 59, 999, + 14 * 3600 * 1000, 7200000 }; - private static int[] minimums = new int[] { 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, - 0, 0, 0, 0, 0, -13 * 3600 * 1000, 0 }; + private static int[] minimums = new int[] { 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, -13 * 3600 * 1000, 0 }; - private static int[] leastMaximums = new int[] { 1, 292269054, 11, 50, 3, - 28, 355, 7, 3, 1, 11, 23, 59, 59, 999, 50400000, 1200000 }; + private static int[] leastMaximums = new int[] { 1, 292269054, 11, 50, 3, 28, 355, 7, 3, 1, 11, 23, 59, 59, 999, + 50400000, 1200000 }; private boolean isCached; @@ -64,70 +60,19 @@ public class GregorianCalendar extends Calendar { private int lastYearSkew = 0; - /** - * Constructs a new {@code GregorianCalendar} initialized to the current date and - * time with the default {@code Locale} and {@code TimeZone}. - */ public GregorianCalendar() { - this(TimeZone.getDefault(), TLocale.getDefault()); + this(TLocale.getDefault()); } - /** - * Constructs a new {@code GregorianCalendar} initialized to midnight in the default - * {@code TimeZone} and {@code Locale} on the specified date. - * - * @param year - * the year. - * @param month - * the month. - * @param day - * the day of the month. - */ public GregorianCalendar(int year, int month, int day) { - super(TimeZone.getDefault(), TLocale.getDefault()); set(year, month, day); } - /** - * Constructs a new {@code GregorianCalendar} initialized to the specified date and - * time in the default {@code TimeZone} and {@code Locale}. - * - * @param year - * the year. - * @param month - * the month. - * @param day - * the day of the month. - * @param hour - * the hour. - * @param minute - * the minute. - */ public GregorianCalendar(int year, int month, int day, int hour, int minute) { - super(TimeZone.getDefault(), TLocale.getDefault()); set(year, month, day, hour, minute); } - /** - * Constructs a new {@code GregorianCalendar} initialized to the specified date and - * time in the default {@code TimeZone} and {@code Locale}. - * - * @param year - * the year. - * @param month - * the month. - * @param day - * the day of the month. - * @param hour - * the hour. - * @param minute - * the minute. - * @param second - * the second. - */ - public GregorianCalendar(int year, int month, int day, int hour, - int minute, int second) { - super(TimeZone.getDefault(), TLocale.getDefault()); + public GregorianCalendar(int year, int month, int day, int hour, int minute, int second) { set(year, month, day, hour, minute, second); } @@ -136,59 +81,16 @@ public class GregorianCalendar extends Calendar { setTimeInMillis(milliseconds); } - /** - * Constructs a new {@code GregorianCalendar} initialized to the current date and - * time and using the specified {@code Locale} and the default {@code TimeZone}. - * - * @param locale - * the {@code Locale}. - */ public GregorianCalendar(TLocale locale) { - this(TimeZone.getDefault(), locale); - } - - /** - * Constructs a new {@code GregorianCalendar} initialized to the current date and - * time and using the specified {@code TimeZone} and the default {@code Locale}. - * - * @param timezone - * the {@code TimeZone}. - */ - public GregorianCalendar(TimeZone timezone) { - this(timezone, TLocale.getDefault()); - } - - /** - * Constructs a new {@code GregorianCalendar} initialized to the current date and - * time and using the specified {@code TimeZone} and {@code Locale}. - * - * @param timezone - * the {@code TimeZone}. - * @param locale - * the {@code Locale}. - */ - public GregorianCalendar(TimeZone timezone, TLocale locale) { - super(timezone, locale); + super(locale); setTimeInMillis(System.currentTimeMillis()); } GregorianCalendar(@SuppressWarnings("unused") boolean ignored) { - super(TimeZone.getDefault()); setFirstDayOfWeek(SUNDAY); setMinimalDaysInFirstWeek(1); } - /** - * Adds the specified amount to a {@code Calendar} field. - * - * @param field - * the {@code Calendar} field to modify. - * @param value - * the amount to add to the field. - * - * @throws IllegalArgumentException - * if the specified field is DST_OFFSET or ZONE_OFFSET. - */ @Override public void add(int field, int value) { if (value == 0) { @@ -269,10 +171,9 @@ public class GregorianCalendar extends Calendar { break; } if (multiplier > 0) { - int zoneOffset = getTimeZone().getRawOffset(); - int offset = getOffset(time + zoneOffset); + int offset = getTimeZoneOffset((int)(time >> 32), (int)time); time += value * multiplier; - int newOffset = getOffset(time + zoneOffset); + int newOffset = getTimeZoneOffset((int)(time >> 32), (int)time); // Adjust for moving over a DST boundary if (newOffset != offset) { time += offset - newOffset; @@ -282,14 +183,9 @@ public class GregorianCalendar extends Calendar { complete(); } - /** - * Creates new instance of {@code GregorianCalendar} with the same properties. - * - * @return a shallow copy of this {@code GregorianCalendar}. - */ @Override public Object clone() { - GregorianCalendar thisClone = (GregorianCalendar) super.clone(); + GregorianCalendar thisClone = (GregorianCalendar)super.clone(); thisClone.cachedFields = cachedFields.clone(); return thisClone; } @@ -314,7 +210,7 @@ public class GregorianCalendar extends Calendar { int dayOfYear = computeYearAndDay(days, timeVal + zoneOffset); fields[DAY_OF_YEAR] = dayOfYear; - if(fields[YEAR] == changeYear && gregorianCutover <= timeVal + zoneOffset){ + if (fields[YEAR] == changeYear && gregorianCutover <= timeVal + zoneOffset) { dayOfYear += currentYearSkew; } int month = dayOfYear / 32; @@ -325,8 +221,7 @@ public class GregorianCalendar extends Calendar { month++; } fields[DAY_OF_WEEK] = mod7(days - 3) + 1; - int dstOffset = fields[YEAR] <= 0 ? 0 : getTimeZone().getOffset(AD, - fields[YEAR], month, date, fields[DAY_OF_WEEK], millis); + int dstOffset = getTimeZoneOffset((int)(timeVal >> 32), (int)timeVal); if (fields[YEAR] > 0) { dstOffset -= zoneOffset; } @@ -342,10 +237,9 @@ public class GregorianCalendar extends Calendar { days++; } if (oldDays != days) { - dayOfYear = computeYearAndDay(days, timeVal - zoneOffset - + dstOffset); + dayOfYear = computeYearAndDay(days, timeVal - zoneOffset + dstOffset); fields[DAY_OF_YEAR] = dayOfYear; - if(fields[YEAR] == changeYear && gregorianCutover <= timeVal - zoneOffset + dstOffset){ + if (fields[YEAR] == changeYear && gregorianCutover <= timeVal - zoneOffset + dstOffset) { dayOfYear += currentYearSkew; } month = dayOfYear / 32; @@ -378,18 +272,14 @@ public class GregorianCalendar extends Calendar { fields[MONTH] = month; fields[DATE] = date; fields[DAY_OF_WEEK_IN_MONTH] = (date - 1) / 7 + 1; - fields[WEEK_OF_MONTH] = (date - 1 + mod7(days - date - 2 - - (getFirstDayOfWeek() - 1))) / 7 + 1; - int daysFromStart = mod7(days - 3 - (fields[DAY_OF_YEAR] - 1) - - (getFirstDayOfWeek() - 1)); - int week = (fields[DAY_OF_YEAR] - 1 + daysFromStart) / 7 - + (7 - daysFromStart >= getMinimalDaysInFirstWeek() ? 1 : 0); + fields[WEEK_OF_MONTH] = (date - 1 + mod7(days - date - 2 - (getFirstDayOfWeek() - 1))) / 7 + 1; + int daysFromStart = mod7(days - 3 - (fields[DAY_OF_YEAR] - 1) - (getFirstDayOfWeek() - 1)); + int week = (fields[DAY_OF_YEAR] - 1 + daysFromStart) / 7 + + (7 - daysFromStart >= getMinimalDaysInFirstWeek() ? 1 : 0); if (week == 0) { - fields[WEEK_OF_YEAR] = 7 - mod7(daysFromStart - - (isLeapYear(fields[YEAR] - 1) ? 2 : 1)) >= getMinimalDaysInFirstWeek() ? 53 - : 52; - } else if (fields[DAY_OF_YEAR] >= (leapYear ? 367 : 366) - - mod7(daysFromStart + (leapYear ? 2 : 1))) { + fields[WEEK_OF_YEAR] = 7 - mod7(daysFromStart - + (isLeapYear(fields[YEAR] - 1) ? 2 : 1)) >= getMinimalDaysInFirstWeek() ? 53 : 52; + } else if (fields[DAY_OF_YEAR] >= (leapYear ? 367 : 366) - mod7(daysFromStart + (leapYear ? 2 : 1))) { fields[WEEK_OF_YEAR] = 7 - mod7(daysFromStart + (leapYear ? 2 : 1)) >= getMinimalDaysInFirstWeek() ? 1 : week; } else { @@ -397,16 +287,12 @@ public class GregorianCalendar extends Calendar { } } - private final void cachedFieldsCheckAndGet(long timeVal, - long newTimeMillis, long newTimeMillisAdjusted, int millis, - int zoneOffset) { + private final void cachedFieldsCheckAndGet(long timeVal, long newTimeMillis, long newTimeMillisAdjusted, + int millis, int zoneOffset) { int dstOffset = fields[DST_OFFSET]; - if (!isCached - || newTimeMillis >= nextMidnightMillis - || newTimeMillis <= lastMidnightMillis - || cachedFields[4] != zoneOffset - || (dstOffset == 0 && (newTimeMillisAdjusted >= nextMidnightMillis)) - || (dstOffset != 0 && (newTimeMillisAdjusted <= lastMidnightMillis))) { + if (!isCached || newTimeMillis >= nextMidnightMillis || newTimeMillis <= lastMidnightMillis || + cachedFields[4] != zoneOffset || (dstOffset == 0 && (newTimeMillisAdjusted >= nextMidnightMillis)) || + (dstOffset != 0 && (newTimeMillisAdjusted <= lastMidnightMillis))) { fullFieldsCalc(timeVal, millis, zoneOffset); isCached = false; } else { @@ -422,15 +308,18 @@ public class GregorianCalendar extends Calendar { } } + // TODO: implement using JavaScript native method + private static native int getTimeZoneOffset(int hitime, int lotime); + @Override protected void computeFields() { - int zoneOffset = getTimeZone().getRawOffset(); + int zoneOffset = getTimeZoneOffset((int)(time >>> 32), (int)time); - if(!isSet[ZONE_OFFSET]) { + if (!isSet[ZONE_OFFSET]) { fields[ZONE_OFFSET] = zoneOffset; } - int millis = (int) (time % 86400000); + int millis = (int)(time % 86400000); int savedMillis = millis; int dstOffset = fields[DST_OFFSET]; // compute without a change in daylight saving time @@ -470,20 +359,13 @@ public class GregorianCalendar extends Calendar { fields[HOUR] = fields[HOUR_OF_DAY] % 12; long newTimeAdjusted = newTime; - if (getTimeZone().useDaylightTime()) { - int dstSavings = ((SimpleTimeZone) getTimeZone()) - .getDSTSavings(); - newTimeAdjusted += (dstOffset == 0) ? dstSavings : -dstSavings; - } - if (newTime > 0L && newTimeAdjusted < 0L && dstOffset == 0) { newTimeAdjusted = 0x7fffffffffffffffL; } else if (newTime < 0L && newTimeAdjusted > 0L && dstOffset != 0) { newTimeAdjusted = 0x8000000000000000L; } - cachedFieldsCheckAndGet(time, newTime, newTimeAdjusted, - savedMillis, zoneOffset); + cachedFieldsCheckAndGet(time, newTime, newTimeAdjusted, savedMillis, zoneOffset); } else { fullFieldsCalc(time, savedMillis, zoneOffset); } @@ -493,10 +375,7 @@ public class GregorianCalendar extends Calendar { } // Caching - if (!isCached - && newTime != 0x7fffffffffffffffL - && newTime != 0x8000000000000000L - && (!getTimeZone().useDaylightTime() || getTimeZone() instanceof SimpleTimeZone)) { + if (!isCached && newTime != 0x7fffffffffffffffL && newTime != 0x8000000000000000L) { int cacheMillis = 0; cachedFields[0] = fields[YEAR]; @@ -540,24 +419,19 @@ public class GregorianCalendar extends Calendar { if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59)) { throw new IllegalArgumentException(); } - if (isSet[MILLISECOND] - && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) { + if (isSet[MILLISECOND] && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) { throw new IllegalArgumentException(); } - if (isSet[WEEK_OF_YEAR] - && (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > 53)) { + if (isSet[WEEK_OF_YEAR] && (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > 53)) { throw new IllegalArgumentException(); } - if (isSet[DAY_OF_WEEK] - && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) { + if (isSet[DAY_OF_WEEK] && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) { throw new IllegalArgumentException(); } - if (isSet[DAY_OF_WEEK_IN_MONTH] - && (fields[DAY_OF_WEEK_IN_MONTH] < 1 || fields[DAY_OF_WEEK_IN_MONTH] > 6)) { + if (isSet[DAY_OF_WEEK_IN_MONTH] && (fields[DAY_OF_WEEK_IN_MONTH] < 1 || fields[DAY_OF_WEEK_IN_MONTH] > 6)) { throw new IllegalArgumentException(); } - if (isSet[WEEK_OF_MONTH] - && (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > 6)) { + if (isSet[WEEK_OF_MONTH] && (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > 6)) { throw new IllegalArgumentException(); } if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM) { @@ -567,8 +441,7 @@ public class GregorianCalendar extends Calendar { throw new IllegalArgumentException(); } if (isSet[YEAR]) { - if (isSet[ERA] && fields[ERA] == BC - && (fields[YEAR] < 1 || fields[YEAR] > 292269054)) { + if (isSet[ERA] && fields[ERA] == BC && (fields[YEAR] < 1 || fields[YEAR] > 292269054)) { throw new IllegalArgumentException(); } else if (fields[YEAR] < 1 || fields[YEAR] > 292278994) { throw new IllegalArgumentException(); @@ -589,10 +462,10 @@ public class GregorianCalendar extends Calendar { timeVal = hour * 3600000; if (isSet[MINUTE]) { - timeVal += ((long) fields[MINUTE]) * 60000; + timeVal += ((long)fields[MINUTE]) * 60000; } if (isSet[SECOND]) { - timeVal += ((long) fields[SECOND]) * 1000; + timeVal += ((long)fields[SECOND]) * 1000; } if (isSet[MILLISECOND]) { timeVal += fields[MILLISECOND]; @@ -610,15 +483,11 @@ public class GregorianCalendar extends Calendar { } } - boolean weekMonthSet = isSet[WEEK_OF_MONTH] - || isSet[DAY_OF_WEEK_IN_MONTH]; - boolean useMonth = (isSet[DATE] || isSet[MONTH] || weekMonthSet) - && lastDateFieldSet != DAY_OF_YEAR; - if (useMonth - && (lastDateFieldSet == DAY_OF_WEEK || lastDateFieldSet == WEEK_OF_YEAR)) { + boolean weekMonthSet = isSet[WEEK_OF_MONTH] || isSet[DAY_OF_WEEK_IN_MONTH]; + boolean useMonth = (isSet[DATE] || isSet[MONTH] || weekMonthSet) && lastDateFieldSet != DAY_OF_YEAR; + if (useMonth && (lastDateFieldSet == DAY_OF_WEEK || lastDateFieldSet == WEEK_OF_YEAR)) { if (isSet[WEEK_OF_YEAR] && isSet[DAY_OF_WEEK]) { - useMonth = lastDateFieldSet != WEEK_OF_YEAR && weekMonthSet - && isSet[DAY_OF_WEEK]; + useMonth = lastDateFieldSet != WEEK_OF_YEAR && weekMonthSet && isSet[DAY_OF_WEEK]; } else if (isSet[DAY_OF_YEAR]) { useMonth = isSet[DATE] && isSet[MONTH]; } @@ -635,15 +504,12 @@ public class GregorianCalendar extends Calendar { boolean leapYear = isLeapYear(year); days = daysFromBaseYear(year) + daysInYear(leapYear, month); boolean useDate = isSet[DATE]; - if (useDate - && (lastDateFieldSet == DAY_OF_WEEK - || lastDateFieldSet == WEEK_OF_MONTH || lastDateFieldSet == DAY_OF_WEEK_IN_MONTH)) { + if (useDate && + (lastDateFieldSet == DAY_OF_WEEK || lastDateFieldSet == WEEK_OF_MONTH || lastDateFieldSet == DAY_OF_WEEK_IN_MONTH)) { useDate = !(isSet[DAY_OF_WEEK] && weekMonthSet); } if (useDate) { - if (!isLenient() - && (fields[DATE] < 1 || fields[DATE] > daysInMonth( - leapYear, month))) { + if (!isLenient() && (fields[DATE] < 1 || fields[DATE] > daysInMonth(leapYear, month))) { throw new IllegalArgumentException(); } days += fields[DATE] - 1; @@ -654,20 +520,16 @@ public class GregorianCalendar extends Calendar { } else { dayOfWeek = getFirstDayOfWeek() - 1; } - if (isSet[WEEK_OF_MONTH] - && lastDateFieldSet != DAY_OF_WEEK_IN_MONTH) { + if (isSet[WEEK_OF_MONTH] && lastDateFieldSet != DAY_OF_WEEK_IN_MONTH) { int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1)); - days += (fields[WEEK_OF_MONTH] - 1) * 7 - + mod7(skew + dayOfWeek - (days - 3)) - skew; + days += (fields[WEEK_OF_MONTH] - 1) * 7 + mod7(skew + dayOfWeek - (days - 3)) - skew; } else if (isSet[DAY_OF_WEEK_IN_MONTH]) { if (fields[DAY_OF_WEEK_IN_MONTH] >= 0) { - days += mod7(dayOfWeek - (days - 3)) - + (fields[DAY_OF_WEEK_IN_MONTH] - 1) * 7; + days += mod7(dayOfWeek - (days - 3)) + (fields[DAY_OF_WEEK_IN_MONTH] - 1) * 7; } else { - days += daysInMonth(leapYear, month) - + mod7(dayOfWeek - - (days + daysInMonth(leapYear, month) - 3)) - + fields[DAY_OF_WEEK_IN_MONTH] * 7; + days += daysInMonth(leapYear, month) + + mod7(dayOfWeek - (days + daysInMonth(leapYear, month) - 3)) + + fields[DAY_OF_WEEK_IN_MONTH] * 7; } } else if (isSet[DAY_OF_WEEK]) { int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1)); @@ -675,8 +537,7 @@ public class GregorianCalendar extends Calendar { } } } else { - boolean useWeekYear = isSet[WEEK_OF_YEAR] - && lastDateFieldSet != DAY_OF_YEAR; + boolean useWeekYear = isSet[WEEK_OF_YEAR] && lastDateFieldSet != DAY_OF_YEAR; if (useWeekYear && isSet[DAY_OF_YEAR]) { useWeekYear = isSet[DAY_OF_WEEK]; } @@ -689,15 +550,13 @@ public class GregorianCalendar extends Calendar { dayOfWeek = getFirstDayOfWeek() - 1; } int skew = mod7(days - 3 - (getFirstDayOfWeek() - 1)); - days += (fields[WEEK_OF_YEAR] - 1) * 7 - + mod7(skew + dayOfWeek - (days - 3)) - skew; + days += (fields[WEEK_OF_YEAR] - 1) * 7 + mod7(skew + dayOfWeek - (days - 3)) - skew; if (7 - skew < getMinimalDaysInFirstWeek()) { days += 7; } } else if (isSet[DAY_OF_YEAR]) { - if (!isLenient() - && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > (365 + (isLeapYear(year) ? 1 - : 0)))) { + if (!isLenient() && + (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > (365 + (isLeapYear(year) ? 1 : 0)))) { throw new IllegalArgumentException(); } days += fields[DAY_OF_YEAR] - 1; @@ -709,22 +568,11 @@ public class GregorianCalendar extends Calendar { timeVal += days * 86400000; // Use local time to compare with the gregorian change - if (year == changeYear - && timeVal >= gregorianCutover + julianError() * 86400000L) { + if (year == changeYear && timeVal >= gregorianCutover + julianError() * 86400000L) { timeVal -= julianError() * 86400000L; } - // It is not possible to simply subtract getOffset(timeVal) from timeVal - // to get UTC. - // The trick is needed for the moment when DST transition occurs, - // say 1:00 is a transition time when DST offset becomes +1 hour, - // then wall time in the interval 1:00 - 2:00 is invalid and is - // treated as UTC time. - long timeValWithoutDST = timeVal - getOffset(timeVal) - + getTimeZone().getRawOffset(); - timeVal -= getOffset(timeValWithoutDST); - // Need to update wall time in fields, since it was invalid due to DST - // transition + long timeValWithoutDST = timeVal - getTimeZoneOffset((int)(timeVal >> 32), (int)timeVal); this.time = timeVal; if (timeValWithoutDST != timeVal) { computeFields(); @@ -740,7 +588,7 @@ public class GregorianCalendar extends Calendar { } int approxYears; - while ((approxYears = (int) (days / 365)) != 0) { + while ((approxYears = (int)(days / 365)) != 0) { year = year + approxYears; days = dayCount - daysFromBaseYear(year); } @@ -749,7 +597,7 @@ public class GregorianCalendar extends Calendar { days = days + daysInYear(year); } fields[YEAR] = year; - return (int) days + 1; + return (int)days + 1; } private long daysFromBaseYear(int iyear) { @@ -760,11 +608,11 @@ public class GregorianCalendar extends Calendar { if (year > changeYear) { days -= ((year - 1901) / 100) - ((year - 1601) / 400); } else { - if(year == changeYear){ + if (year == changeYear) { days += currentYearSkew; - }else if(year == changeYear -1){ + } else if (year == changeYear - 1) { days += lastYearSkew; - }else{ + } else { days += julianSkew; } } @@ -772,8 +620,7 @@ public class GregorianCalendar extends Calendar { } else if (year <= changeYear) { return (year - 1970) * 365 + ((year - 1972) / 4) + julianSkew; } - return (year - 1970) * 365 + ((year - 1972) / 4) - - ((year - 2000) / 100) + ((year - 2000) / 400); + return (year - 1970) * 365 + ((year - 1972) / 4) - ((year - 2000) / 100) + ((year - 2000) / 400); } private int daysInMonth() { @@ -808,23 +655,23 @@ public class GregorianCalendar extends Calendar { } /** - * Compares the specified {@code Object} to this {@code GregorianCalendar} and returns whether - * they are equal. To be equal, the {@code Object} must be an instance of {@code GregorianCalendar} and - * have the same properties. + * Compares the specified {@code Object} to this {@code GregorianCalendar} + * and returns whether they are equal. To be equal, the {@code Object} must + * be an instance of {@code GregorianCalendar} and have the same properties. * * @param object - * the {@code Object} to compare with this {@code GregorianCalendar}. + * the {@code Object} to compare with this + * {@code GregorianCalendar}. * @return {@code true} if {@code object} is equal to this * {@code GregorianCalendar}, {@code false} otherwise. * @throws IllegalArgumentException - * if the time is not set and the time cannot be computed - * from the current field values. + * if the time is not set and the time cannot be computed from + * the current field values. * @see #hashCode */ @Override public boolean equals(Object object) { - return super.equals(object) - && gregorianCutover == ((GregorianCalendar) object).gregorianCutover; + return super.equals(object) && gregorianCutover == ((GregorianCalendar)object).gregorianCutover; } /** @@ -873,11 +720,10 @@ public class GregorianCalendar extends Calendar { case DAY_OF_YEAR: return daysInYear(fields[YEAR]); case DAY_OF_WEEK_IN_MONTH: - result = get(DAY_OF_WEEK_IN_MONTH) - + ((daysInMonth() - get(DATE)) / 7); + result = get(DAY_OF_WEEK_IN_MONTH) + ((daysInMonth() - get(DATE)) / 7); break; case YEAR: - GregorianCalendar clone = (GregorianCalendar) clone(); + GregorianCalendar clone = (GregorianCalendar)clone(); if (get(ERA) == AD) { clone.setTimeInMillis(Long.MAX_VALUE); } else { @@ -899,8 +745,7 @@ public class GregorianCalendar extends Calendar { /** * Gets the minimum value of the specified field for the current date. For - * the gregorian calendar, this value is the same as - * {@code getMinimum()}. + * the gregorian calendar, this value is the same as {@code getMinimum()}. * * @param field * the field. @@ -946,8 +791,7 @@ public class GregorianCalendar extends Calendar { public int getLeastMaximum(int field) { // return value for WEEK_OF_YEAR should make corresponding changes when // the gregorian change date have been reset. - if (gregorianCutover != defaultGregorianCutover - && field == WEEK_OF_YEAR) { + if (gregorianCutover != defaultGregorianCutover && field == WEEK_OF_YEAR) { long currentTimeInMillis = time; setTimeInMillis(gregorianCutover); int actual = getActualMaximum(field); @@ -982,55 +826,6 @@ public class GregorianCalendar extends Calendar { return minimums[field]; } - int getOffset(long localTime) { - TimeZone timeZone = getTimeZone(); - if (!timeZone.useDaylightTime()) { - return timeZone.getRawOffset(); - } - - long dayCount = localTime / 86400000; - int millis = (int) (localTime % 86400000); - if (millis < 0) { - millis += 86400000; - dayCount--; - } - - int year = 1970; - long days = dayCount; - if (localTime < gregorianCutover) { - days -= julianSkew; - } - int approxYears; - - while ((approxYears = (int) (days / 365)) != 0) { - year = year + approxYears; - days = dayCount - daysFromBaseYear(year); - } - if (days < 0) { - year = year - 1; - days = days + 365 + (isLeapYear(year) ? 1 : 0); - if (year == changeYear && localTime < gregorianCutover) { - days -= julianError(); - } - } - if (year <= 0) { - return timeZone.getRawOffset(); - } - int dayOfYear = (int) days + 1; - - int month = dayOfYear / 32; - boolean leapYear = isLeapYear(year); - int date = dayOfYear - daysInYear(leapYear, month); - if (date > daysInMonth(leapYear, month)) { - date -= daysInMonth(leapYear, month); - month++; - } - int dayOfWeek = mod7(dayCount - 3) + 1; - int offset = timeZone.getOffset(AD, year, month, date, dayOfWeek, - millis); - return offset; - } - /** * Returns an integer hash code for the receiver. Objects which are equal * return the same value for this method. @@ -1041,8 +836,7 @@ public class GregorianCalendar extends Calendar { */ @Override public int hashCode() { - return super.hashCode() - + ((int) (gregorianCutover >>> 32) ^ (int) gregorianCutover); + return super.hashCode() + ((int)(gregorianCutover >>> 32) ^ (int)gregorianCutover); } /** @@ -1074,7 +868,7 @@ public class GregorianCalendar extends Calendar { } private int mod7(long num1) { - int rem = (int) (num1 % 7); + int rem = (int)(num1 % 7); if (num1 < 0 && rem < 0) { return rem + 7; } @@ -1093,7 +887,7 @@ public class GregorianCalendar extends Calendar { * the amount to add. * * @throws IllegalArgumentException - * if an invalid field is specified. + * if an invalid field is specified. */ @Override public void roll(int field, int value) { @@ -1110,87 +904,85 @@ public class GregorianCalendar extends Calendar { int days, day, mod, maxWeeks, newWeek; int max = -1; switch (field) { - case YEAR: - max = maximums[field]; - break; - case WEEK_OF_YEAR: - days = daysInYear(fields[YEAR]); - day = DAY_OF_YEAR; - mod = mod7(fields[DAY_OF_WEEK] - fields[day] - - (getFirstDayOfWeek() - 1)); - maxWeeks = (days - 1 + mod) / 7 + 1; - newWeek = mod(fields[field] - 1 + value, maxWeeks) + 1; - if (newWeek == maxWeeks) { - int addDays = (newWeek - fields[field]) * 7; - if (fields[day] > addDays && fields[day] + addDays > days) { - set(field, 1); - } else { - set(field, newWeek - 1); - } - } else if (newWeek == 1) { - int week = (fields[day] - ((fields[day] - 1) / 7 * 7) - 1 + mod) / 7 + 1; - if (week > 1) { - set(field, 1); + case YEAR: + max = maximums[field]; + break; + case WEEK_OF_YEAR: + days = daysInYear(fields[YEAR]); + day = DAY_OF_YEAR; + mod = mod7(fields[DAY_OF_WEEK] - fields[day] - (getFirstDayOfWeek() - 1)); + maxWeeks = (days - 1 + mod) / 7 + 1; + newWeek = mod(fields[field] - 1 + value, maxWeeks) + 1; + if (newWeek == maxWeeks) { + int addDays = (newWeek - fields[field]) * 7; + if (fields[day] > addDays && fields[day] + addDays > days) { + set(field, 1); + } else { + set(field, newWeek - 1); + } + } else if (newWeek == 1) { + int week = (fields[day] - ((fields[day] - 1) / 7 * 7) - 1 + mod) / 7 + 1; + if (week > 1) { + set(field, 1); + } else { + set(field, newWeek); + } } else { set(field, newWeek); } - } else { - set(field, newWeek); - } - break; - case WEEK_OF_MONTH: - days = daysInMonth(); - day = DATE; - mod = mod7(fields[DAY_OF_WEEK] - fields[day] - - (getFirstDayOfWeek() - 1)); - maxWeeks = (days - 1 + mod) / 7 + 1; - newWeek = mod(fields[field] - 1 + value, maxWeeks) + 1; - if (newWeek == maxWeeks) { - if (fields[day] + (newWeek - fields[field]) * 7 > days) { - set(day, days); + break; + case WEEK_OF_MONTH: + days = daysInMonth(); + day = DATE; + mod = mod7(fields[DAY_OF_WEEK] - fields[day] - (getFirstDayOfWeek() - 1)); + maxWeeks = (days - 1 + mod) / 7 + 1; + newWeek = mod(fields[field] - 1 + value, maxWeeks) + 1; + if (newWeek == maxWeeks) { + if (fields[day] + (newWeek - fields[field]) * 7 > days) { + set(day, days); + } else { + set(field, newWeek); + } + } else if (newWeek == 1) { + int week = (fields[day] - ((fields[day] - 1) / 7 * 7) - 1 + mod) / 7 + 1; + if (week > 1) { + set(day, 1); + } else { + set(field, newWeek); + } } else { set(field, newWeek); } - } else if (newWeek == 1) { - int week = (fields[day] - ((fields[day] - 1) / 7 * 7) - 1 + mod) / 7 + 1; - if (week > 1) { - set(day, 1); - } else { - set(field, newWeek); - } - } else { - set(field, newWeek); - } - break; - case DATE: - max = daysInMonth(); - break; - case DAY_OF_YEAR: - max = daysInYear(fields[YEAR]); - break; - case DAY_OF_WEEK: - max = maximums[field]; - lastDateFieldSet = WEEK_OF_MONTH; - break; - case DAY_OF_WEEK_IN_MONTH: - max = (fields[DATE] + ((daysInMonth() - fields[DATE]) / 7 * 7) - 1) / 7 + 1; - break; + break; + case DATE: + max = daysInMonth(); + break; + case DAY_OF_YEAR: + max = daysInYear(fields[YEAR]); + break; + case DAY_OF_WEEK: + max = maximums[field]; + lastDateFieldSet = WEEK_OF_MONTH; + break; + case DAY_OF_WEEK_IN_MONTH: + max = (fields[DATE] + ((daysInMonth() - fields[DATE]) / 7 * 7) - 1) / 7 + 1; + break; - case ERA: - case MONTH: - case AM_PM: - case HOUR: - case HOUR_OF_DAY: - case MINUTE: - case SECOND: - case MILLISECOND: - set(field, mod(fields[field] + value, maximums[field] + 1)); - if (field == MONTH && fields[DATE] > daysInMonth()) { - set(DATE, daysInMonth()); - } else if (field == AM_PM) { - lastTimeFieldSet = HOUR; - } - break; + case ERA: + case MONTH: + case AM_PM: + case HOUR: + case HOUR_OF_DAY: + case MINUTE: + case SECOND: + case MILLISECOND: + set(field, mod(fields[field] + value, maximums[field] + 1)); + if (field == MONTH && fields[DATE] > daysInMonth()) { + set(DATE, daysInMonth()); + } else if (field == AM_PM) { + lastTimeFieldSet = HOUR; + } + break; } if (max != -1) { set(field, mod(fields[field] - 1 + value, max) + 1); @@ -1211,7 +1003,7 @@ public class GregorianCalendar extends Calendar { * {@code true} to increment the field, {@code false} to * decrement. * @throws IllegalArgumentException - * if an invalid field is specified. + * if an invalid field is specified. */ @Override public void roll(int field, boolean increment) { @@ -1226,18 +1018,17 @@ public class GregorianCalendar extends Calendar { */ public void setGregorianChange(Date date) { gregorianCutover = date.getTime(); - GregorianCalendar cal = new GregorianCalendar(TimeZone.GMT); + GregorianCalendar cal = new GregorianCalendar(); cal.setTime(date); changeYear = cal.get(YEAR); if (cal.get(ERA) == BC) { changeYear = 1 - changeYear; } - julianSkew = ((changeYear - 2000) / 400) + julianError() - - ((changeYear - 2000) / 100); + julianSkew = ((changeYear - 2000) / 400) + julianError() - ((changeYear - 2000) / 100); isCached = false; int dayOfYear = cal.get(DAY_OF_YEAR); if (dayOfYear < julianSkew) { - currentYearSkew = dayOfYear-1; + currentYearSkew = dayOfYear - 1; lastYearSkew = julianSkew - dayOfYear + 1; } else { lastYearSkew = 0; diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java deleted file mode 100644 index edb563faa..000000000 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/SimpleTimeZone.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * 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; - -public class SimpleTimeZone extends TimeZone { - - private int rawOffset; - - private int startYear, startMonth, startDay, startDayOfWeek, startTime; - - private int endMonth, endDay, endDayOfWeek, endTime; - - private int startMode, endMode; - - private static final int DOM_MODE = 1, DOW_IN_MONTH_MODE = 2, DOW_GE_DOM_MODE = 3, DOW_LE_DOM_MODE = 4; - - public static final int UTC_TIME = 2; - - public static final int STANDARD_TIME = 1; - - public static final int WALL_TIME = 0; - - private boolean useDaylight; - - private GregorianCalendar daylightSavings; - - private int dstSavings = 3600000; - - private final transient boolean isSimple; - - public SimpleTimeZone(int offset, final String name) { - setID(name); - rawOffset = offset; - icuTZ = getICUTimeZone(name); - if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) { - isSimple = true; - icuTZ.setRawOffset(offset); - } else { - isSimple = false; - } - useDaylight = icuTZ.useDaylightTime(); - } - - public SimpleTimeZone(int offset, String name, int startMonth, int startDay, int startDayOfWeek, int startTime, - int endMonth, int endDay, int endDayOfWeek, int endTime) { - this(offset, name, startMonth, startDay, startDayOfWeek, startTime, endMonth, endDay, endDayOfWeek, endTime, - 3600000); - } - - public SimpleTimeZone(int offset, String name, int startMonth, int startDay, int startDayOfWeek, int startTime, - int endMonth, int endDay, int endDayOfWeek, int endTime, int daylightSavings) { - icuTZ = getICUTimeZone(name); - if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) { - isSimple = true; - com.ibm.icu.util.SimpleTimeZone tz = (com.ibm.icu.util.SimpleTimeZone) icuTZ; - tz.setRawOffset(offset); - tz.setStartRule(startMonth, startDay, startDayOfWeek, startTime); - tz.setEndRule(endMonth, endDay, endDayOfWeek, endTime); - tz.setDSTSavings(daylightSavings); - } else { - isSimple = false; - } - setID(name); - rawOffset = offset; - if (daylightSavings <= 0) { - throw new IllegalArgumentException(String.valueOf(daylightSavings)); - } - dstSavings = daylightSavings; - - setStartRule(startMonth, startDay, startDayOfWeek, startTime); - setEndRule(endMonth, endDay, endDayOfWeek, endTime); - - useDaylight = daylightSavings > 0 || icuTZ.useDaylightTime(); - } - - public SimpleTimeZone(int offset, String name, int startMonth, int startDay, int startDayOfWeek, int startTime, - int startTimeMode, int endMonth, int endDay, int endDayOfWeek, int endTime, int endTimeMode, - int daylightSavings) { - - this(offset, name, startMonth, startDay, startDayOfWeek, startTime, endMonth, endDay, endDayOfWeek, endTime, - daylightSavings); - startMode = startTimeMode; - endMode = endTimeMode; - } - - @Override - public Object clone() { - SimpleTimeZone zone = (SimpleTimeZone) super.clone(); - if (daylightSavings != null) { - zone.daylightSavings = (GregorianCalendar) daylightSavings.clone(); - } - return zone; - } - - @Override - public boolean equals(Object object) { - if (!(object instanceof SimpleTimeZone)) { - return false; - } - SimpleTimeZone tz = (SimpleTimeZone) object; - return getID().equals(tz.getID()) && - rawOffset == tz.rawOffset && - useDaylight == tz.useDaylight && - (!useDaylight || (startYear == tz.startYear && startMonth == tz.startMonth && startDay == tz.startDay && - startMode == tz.startMode && startDayOfWeek == tz.startDayOfWeek && startTime == tz.startTime && - endMonth == tz.endMonth && endDay == tz.endDay && endDayOfWeek == tz.endDayOfWeek && - endTime == tz.endTime && endMode == tz.endMode && dstSavings == tz.dstSavings)); - } - - @Override - public int getDSTSavings() { - if (!useDaylight) { - return 0; - } - return dstSavings; - } - - @Override - public int getOffset(int era, int year, int month, int day, int dayOfWeek, int time) { - if (era != GregorianCalendar.BC && era != GregorianCalendar.AD) { - throw new IllegalArgumentException(String.valueOf(era)); - } - checkRange(month, dayOfWeek, time); - if (month != Calendar.FEBRUARY || day != 29 || !isLeapYear(year)) { - checkDay(month, day); - } - return icuTZ.getOffset(era, year, month, day, dayOfWeek, time); - } - - @Override - public int getOffset(long time) { - return icuTZ.getOffset(time); - } - - @Override - public int getRawOffset() { - return rawOffset; - } - - @Override - public synchronized int hashCode() { - int hashCode = getID().hashCode() + rawOffset; - if (useDaylight) { - hashCode += startYear + startMonth + startDay + startDayOfWeek + startTime + startMode + endMonth + endDay + - endDayOfWeek + endTime + endMode + dstSavings; - } - return hashCode; - } - - @Override - public boolean hasSameRules(TimeZone zone) { - if (!(zone instanceof SimpleTimeZone)) { - return false; - } - SimpleTimeZone tz = (SimpleTimeZone) zone; - if (useDaylight != tz.useDaylight) { - return false; - } - if (!useDaylight) { - return rawOffset == tz.rawOffset; - } - return rawOffset == tz.rawOffset && dstSavings == tz.dstSavings && startYear == tz.startYear && - startMonth == tz.startMonth && startDay == tz.startDay && startMode == tz.startMode && - startDayOfWeek == tz.startDayOfWeek && startTime == tz.startTime && endMonth == tz.endMonth && - endDay == tz.endDay && endDayOfWeek == tz.endDayOfWeek && endTime == tz.endTime && - endMode == tz.endMode; - } - - @Override - public boolean inDaylightTime(Date time) { - return icuTZ.inDaylightTime(time); - } - - private boolean isLeapYear(int year) { - if (year > 1582) { - return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); - } - return year % 4 == 0; - } - - public void setDSTSavings(int milliseconds) { - if (milliseconds > 0) { - dstSavings = milliseconds; - } else { - throw new IllegalArgumentException(); - } - } - - private void checkRange(int month, int dayOfWeek, int time) { - if (month < Calendar.JANUARY || month > Calendar.DECEMBER) { - throw new IllegalArgumentException(String.valueOf(month)); - } - if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) { - throw new IllegalArgumentException(String.valueOf(dayOfWeek)); - } - if (time < 0 || time >= 24 * 3600000) { - throw new IllegalArgumentException(String.valueOf(time)); - } - } - - private void checkDay(int month, int day) { - if (day <= 0 || day > GregorianCalendar.DaysInMonth[month]) { - throw new IllegalArgumentException(String.valueOf(day)); - } - } - - private void setEndMode() { - if (endDayOfWeek == 0) { - endMode = DOM_MODE; - } else if (endDayOfWeek < 0) { - endDayOfWeek = -endDayOfWeek; - if (endDay < 0) { - endDay = -endDay; - endMode = DOW_LE_DOM_MODE; - } else { - endMode = DOW_GE_DOM_MODE; - } - } else { - endMode = DOW_IN_MONTH_MODE; - } - useDaylight = startDay != 0 && endDay != 0; - if (endDay != 0) { - checkRange(endMonth, endMode == DOM_MODE ? 1 : endDayOfWeek, endTime); - if (endMode != DOW_IN_MONTH_MODE) { - checkDay(endMonth, endDay); - } else { - if (endDay < -5 || endDay > 5) { - throw new IllegalArgumentException(Messages.getString("luni.40", endDay)); //$NON-NLS-1$ - } - } - } - if (endMode != DOM_MODE) { - endDayOfWeek--; - } - } - - public void setEndRule(int month, int dayOfMonth, int time) { - endMonth = month; - endDay = dayOfMonth; - endDayOfWeek = 0; // Initialize this value for hasSameRules() - endTime = time; - setEndMode(); - if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, dayOfMonth, time); - } - } - - public void setEndRule(int month, int day, int dayOfWeek, int time) { - endMonth = month; - endDay = day; - endDayOfWeek = dayOfWeek; - endTime = time; - setEndMode(); - if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, dayOfWeek, time); - } - } - - public void setEndRule(int month, int day, int dayOfWeek, int time, boolean after) { - endMonth = month; - endDay = after ? day : -day; - endDayOfWeek = -dayOfWeek; - endTime = time; - setEndMode(); - if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day, dayOfWeek, time, after); - } - } - - @Override - public void setRawOffset(int offset) { - rawOffset = offset; - icuTZ.setRawOffset(offset); - } - - private void setStartMode() { - if (startDayOfWeek == 0) { - startMode = DOM_MODE; - } else if (startDayOfWeek < 0) { - startDayOfWeek = -startDayOfWeek; - if (startDay < 0) { - startDay = -startDay; - startMode = DOW_LE_DOM_MODE; - } else { - startMode = DOW_GE_DOM_MODE; - } - } else { - startMode = DOW_IN_MONTH_MODE; - } - useDaylight = startDay != 0 && endDay != 0; - if (startDay != 0) { - checkRange(startMonth, startMode == DOM_MODE ? 1 : startDayOfWeek, startTime); - if (startMode != DOW_IN_MONTH_MODE) { - checkDay(startMonth, startDay); - } else { - if (startDay < -5 || startDay > 5) { - throw new IllegalArgumentException(Messages.getString("luni.40", startDay)); //$NON-NLS-1$ - } - } - } - if (startMode != DOM_MODE) { - startDayOfWeek--; - } - } - - public void setStartRule(int month, int dayOfMonth, int time) { - startMonth = month; - startDay = dayOfMonth; - startDayOfWeek = 0; // Initialize this value for hasSameRules() - startTime = time; - setStartMode(); - if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, dayOfMonth, time); - } - } - - public void setStartRule(int month, int day, int dayOfWeek, int time) { - startMonth = month; - startDay = day; - startDayOfWeek = dayOfWeek; - startTime = time; - setStartMode(); - if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, dayOfWeek, time); - } - } - - public void setStartRule(int month, int day, int dayOfWeek, int time, boolean after) { - startMonth = month; - startDay = after ? day : -day; - startDayOfWeek = -dayOfWeek; - startTime = time; - setStartMode(); - if (isSimple) { - ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day, dayOfWeek, time, after); - } - } - - public void setStartYear(int year) { - startYear = year; - useDaylight = true; - } - - @Override - public String toString() { - return getClass().getName() + "[id=" + getID() + ",offset=" + rawOffset + ",dstSavings=" + dstSavings + - ",useDaylight=" + useDaylight + ",startYear=" + startYear + ",startMode=" + startMode + ",startMonth=" + - startMonth + ",startDay=" + startDay + ",startDayOfWeek=" + - (useDaylight && (startMode != DOM_MODE) ? startDayOfWeek + 1 : 0) + ",startTime=" + startTime + - ",endMode=" + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay + ",endDayOfWeek=" + - (useDaylight && (endMode != DOM_MODE) ? endDayOfWeek + 1 : 0) + ",endTime=" + endTime + "]"; - } - - @Override - public boolean useDaylightTime() { - return useDaylight; - } -} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java deleted file mode 100644 index 9a2ec1fd2..000000000 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZone.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright 2014 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. - */ -/* - * 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 org.teavm.classlib.java.io.TSerializable; -import org.teavm.classlib.java.lang.TCloneable; - -public abstract class TimeZone implements TSerializable, TCloneable { - private static final long serialVersionUID = 3581463369166924961L; - - public static final int SHORT = 0; - - public static final int LONG = 1; - - private static THashMap AvailableZones; - - private static TimeZone Default; - - static TimeZone GMT = new SimpleTimeZone(0, "GMT"); // Greenwich Mean Time - - private String ID; - - private static void initializeAvailable() { - TimeZone[] zones = TimeZones.getTimeZones(); - AvailableZones = new THashMap<>((zones.length + 1) * 4 / 3); - AvailableZones.put(GMT.getID(), GMT); - for (int i = 0; i < zones.length; i++) { - AvailableZones.put(zones[i].getID(), zones[i]); - } - } - - public TimeZone() { - } - - @Override - public Object clone() { - try { - TimeZone zone = (TimeZone) super.clone(); - return zone; - } catch (CloneNotSupportedException e) { - return null; - } - } - - public static synchronized String[] getAvailableIDs() { - return AvailableZones.keySet().toArray(new String[0]); - } - - public static synchronized String[] getAvailableIDs(int offset) { - TList result = new TArrayList<>(); - for (TIterator iter = AvailableZones.values().iterator(); iter.hasNext();) { - TimeZone tz = iter.next(); - if (tz.getRawOffset() == offset) { - result.add(tz.getID()); - } - } - return result.toArray(new String[0]); - } - - public static synchronized TimeZone getDefault() { - if (Default == null) { - setDefault(null); - } - return (TimeZone) Default.clone(); - } - - public final String getDisplayName() { - return getDisplayName(false, LONG, TLocale.getDefault()); - } - - public final String getDisplayName(TLocale locale) { - return getDisplayName(false, LONG, locale); - } - - public final String getDisplayName(boolean daylightTime, int style) { - return getDisplayName(daylightTime, style, TLocale.getDefault()); - } - - public String getDisplayName(boolean daylightTime, int style, TLocale locale) { - if (icuTimeZone == null || !ID.equals(icuTimeZone.getID())) { - icuTimeZone = com.ibm.icu.util.TimeZone.getTimeZone(ID); - } - return icuTimeZone.getDisplayName(daylightTime, style, locale); - } - - public String getID() { - return ID; - } - - public int getDSTSavings() { - if (useDaylightTime()) { - return 3600000; - } - return 0; - } - - public int getOffset(long time) { - if (inDaylightTime(new Date(time))) { - return getRawOffset() + getDSTSavings(); - } - return getRawOffset(); - } - - abstract public int getOffset(int era, int year, int month, int day, int dayOfWeek, int time); - - abstract public int getRawOffset(); - - public static synchronized TimeZone getTimeZone(String name) { - if (AvailableZones == null) { - initializeAvailable(); - } - - TimeZone zone = AvailableZones.get(name); - if (zone == null) { - 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 (TimeZone) 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 (TimeZone) GMT.clone(); - } - raw += minute * 60000; - } else if (hour >= 30 || index > 6) { - raw = (hour / 100 * 3600000) + (hour % 100 * 60000); - } - if (sign == '-') { - raw = -raw; - } - return new SimpleTimeZone(raw, formattedName); - } - } - } - zone = GMT; - } - return (TimeZone) zone.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(); - } - - public boolean hasSameRules(TimeZone zone) { - if (zone == null) { - return false; - } - return getRawOffset() == zone.getRawOffset(); - } - - abstract public boolean inDaylightTime(Date 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; - } - - public static synchronized void setDefault(TimeZone timezone) { - if (timezone != null) { - setICUDefaultTimeZone(timezone); - Default = timezone; - return; - } - - String zone = AccessController.doPrivileged(new PriviAction("user.timezone")); - - // sometimes DRLVM incorrectly adds "\n" to the end of timezone ID - if (zone != null && zone.contains("\n")) { - zone = zone.substring(0, zone.indexOf("\n")); - } - - // if property user.timezone is not set, we call the native method - // getCustomTimeZone - if (zone == null || zone.length() == 0) { - int[] tzinfo = new int[10]; - boolean[] isCustomTimeZone = new boolean[1]; - - String zoneId = getCustomTimeZone(tzinfo, isCustomTimeZone); - - // if returned TimeZone is a user customized TimeZone - if (isCustomTimeZone[0]) { - // build a new SimpleTimeZone - switch (tzinfo[1]) { - case 0: - // does not observe DST - Default = new SimpleTimeZone(tzinfo[0], zoneId); - break; - default: - // observes DST - Default = new SimpleTimeZone(tzinfo[0], zoneId, tzinfo[5], tzinfo[4], tzinfo[3], tzinfo[2], - tzinfo[9], tzinfo[8], tzinfo[7], tzinfo[6], tzinfo[1]); - } - } else { - // get TimeZone - Default = getTimeZone(zoneId); - } - } else { - // if property user.timezone is set in command line (with -D option) - Default = getTimeZone(zone); - } - setICUDefaultTimeZone(Default); - } - - private static void setICUDefaultTimeZone(TimeZone timezone) { - final com.ibm.icu.util.TimeZone icuTZ = com.ibm.icu.util.TimeZone.getTimeZone(timezone.getID()); - } - - public void setID(String name) { - if (name == null) { - throw new NullPointerException(); - } - ID = name; - } - - abstract public void setRawOffset(int offset); - - abstract public boolean useDaylightTime(); - - private static native String getCustomTimeZone(int[] tzinfo, boolean[] isCustomTimeZone); -} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZones.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZones.java deleted file mode 100644 index f9e70f561..000000000 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TimeZones.java +++ /dev/null @@ -1,707 +0,0 @@ -/* - * Copyright 2014 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. - */ -/* - * 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; - -final class TimeZones { - - private static final int HALF_HOUR = 1800000; - private static final int ONE_HOUR = HALF_HOUR * 2; - - public static TimeZone[] getTimeZones() { - return new TimeZone[] { - new SimpleTimeZone(-11 * ONE_HOUR, "MIT"), //$NON-NLS-1$ - new SimpleTimeZone(-10 * ONE_HOUR, "HST"), //$NON-NLS-1$ - new SimpleTimeZone(-9 * ONE_HOUR, "AST", Calendar.APRIL, 1, //$NON-NLS-1$ - -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-8 * ONE_HOUR, "PST", Calendar.APRIL, 1, //$NON-NLS-1$ - -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-7 * ONE_HOUR, "MST", Calendar.APRIL, 1, //$NON-NLS-1$ - -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-7 * ONE_HOUR, "PNT"), //$NON-NLS-1$ - new SimpleTimeZone(-6 * ONE_HOUR, "CST", Calendar.APRIL, 1, //$NON-NLS-1$ - -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-5 * ONE_HOUR, "EST", Calendar.APRIL, 1, //$NON-NLS-1$ - -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-5 * ONE_HOUR, "IET"), //$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "PRT"), //$NON-NLS-1$ - new SimpleTimeZone(-3 * ONE_HOUR - 1800000, - "CNT", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 60000, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 60000), - new SimpleTimeZone(-3 * ONE_HOUR, "AGT"), //$NON-NLS-1$ - new SimpleTimeZone(-3 * ONE_HOUR, "BET", Calendar.OCTOBER, 8, //$NON-NLS-1$ - -Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.FEBRUARY, 15, - -Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(0 * ONE_HOUR, "UTC"), //$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "WET", Calendar.MARCH, -1, //$NON-NLS-1$ - Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, "ECT", Calendar.MARCH, -1, //$NON-NLS-1$ - Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, "MET", Calendar.MARCH, 21, 0, //$NON-NLS-1$ - 0 * ONE_HOUR, Calendar.SEPTEMBER, 23, 0, 0 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, "ART", Calendar.APRIL, -1, //$NON-NLS-1$ - Calendar.FRIDAY, 0 * ONE_HOUR, Calendar.SEPTEMBER, -1, - Calendar.THURSDAY, 23 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, "CAT"), //$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "EET", Calendar.MARCH, -1, //$NON-NLS-1$ - Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(3 * ONE_HOUR, "EAT"), //$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR + 1800000, - "Asia/Tehran", //$NON-NLS-1$ - Calendar.MARCH, 21, 0, 0 * ONE_HOUR, - Calendar.SEPTEMBER, 23, 0, 0 * ONE_HOUR), - new SimpleTimeZone(4 * ONE_HOUR, "NET", Calendar.MARCH, -1, //$NON-NLS-1$ - Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(5 * ONE_HOUR, "PLT"), //$NON-NLS-1$ - new SimpleTimeZone(5 * ONE_HOUR + 1800000, "IST"), //$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR, "BST"), //$NON-NLS-1$ - new SimpleTimeZone(7 * ONE_HOUR, "VST"), //$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "CTT"), //$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR, "JST"), //$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR + 1800000, "ACT"), //$NON-NLS-1$ - new SimpleTimeZone(10 * ONE_HOUR, "AET", Calendar.OCTOBER, -1, //$NON-NLS-1$ - Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(11 * ONE_HOUR, "SST"), //$NON-NLS-1$ - new SimpleTimeZone(12 * ONE_HOUR, "NST", Calendar.OCTOBER, 1, //$NON-NLS-1$ - -Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, 15, - -Calendar.SUNDAY, 2 * ONE_HOUR), - - new SimpleTimeZone(-6 * ONE_HOUR, "America/Costa_Rica"), //$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, - "America/Halifax", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-2 * ONE_HOUR, "Atlantic/South_Georgia"), //$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, - "Europe/London", //$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Algiers"), //$NON-NLS-1$ - new SimpleTimeZone( - 2 * ONE_HOUR, - "Africa/Cairo", //$NON-NLS-1$ - Calendar.APRIL, -1, Calendar.FRIDAY, 0 * ONE_HOUR, - Calendar.SEPTEMBER, -1, Calendar.THURSDAY, - 23 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Harare"), //$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, - "Asia/Jerusalem", //$NON-NLS-1$ - Calendar.APRIL, 9, 0, 1 * ONE_HOUR, Calendar.SEPTEMBER, - 24, 0, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Bucharest", //$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(3 * ONE_HOUR, - "Europe/Moscow", //$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(4 * ONE_HOUR + 1800000, "Asia/Kabul"), //$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR + 1800000, - "Australia/Adelaide", Calendar.OCTOBER, -1, //$NON-NLS-1$ - Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(10 * ONE_HOUR, "Australia/Brisbane"), //$NON-NLS-1$ - new SimpleTimeZone(10 * ONE_HOUR, - "Australia/Hobart", //$NON-NLS-1$ - Calendar.OCTOBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - - new SimpleTimeZone(-9 * ONE_HOUR - 1800000, "Pacific/Marquesas"), //$NON-NLS-1$ - new SimpleTimeZone(-1 * ONE_HOUR, - "Atlantic/Azores", //$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(4 * ONE_HOUR, "Asia/Dubai"), //$NON-NLS-1$ - new SimpleTimeZone(20700000, "Asia/Katmandu"), //$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR + 1800000, "Asia/Rangoon"), //$NON-NLS-1$ - new SimpleTimeZone(45900000, - "Pacific/Chatham", //$NON-NLS-1$ - Calendar.OCTOBER, 1, -Calendar.SUNDAY, 9900000, - Calendar.MARCH, 15, -Calendar.SUNDAY, 9900000), - - new SimpleTimeZone(-11 * ONE_HOUR, "Pacific/Apia"), //$NON-NLS-1$ - new SimpleTimeZone(-11 * ONE_HOUR, "Pacific/Niue"), //$NON-NLS-1$ - new SimpleTimeZone(-11 * ONE_HOUR, "Pacific/Pago_Pago"), //$NON-NLS-1$ - new SimpleTimeZone(-10 * ONE_HOUR, - "America/Adak", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-10 * ONE_HOUR, "Pacific/Fakaofo"), //$NON-NLS-1$ - new SimpleTimeZone(-10 * ONE_HOUR, "Pacific/Honolulu"), //$NON-NLS-1$ - new SimpleTimeZone(-10 * ONE_HOUR, "Pacific/Rarotonga"), //$NON-NLS-1$ - new SimpleTimeZone(-10 * ONE_HOUR, "Pacific/Tahiti"), //$NON-NLS-1$ - new SimpleTimeZone(-9 * ONE_HOUR, - "America/Anchorage", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-9 * ONE_HOUR, "Pacific/Gambier"), //$NON-NLS-1$ - new SimpleTimeZone(-8 * ONE_HOUR, - "America/Los_Angeles", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-8 * ONE_HOUR, - "America/Tijuana", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-8 * ONE_HOUR, - "America/Vancouver", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-8 * ONE_HOUR, "Pacific/Pitcairn"), //$NON-NLS-1$ - new SimpleTimeZone(-7 * ONE_HOUR, "America/Dawson_Creek"), //$NON-NLS-1$ - new SimpleTimeZone(-7 * ONE_HOUR, - "America/Denver", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-7 * ONE_HOUR, - "America/Edmonton", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-7 * ONE_HOUR, - "America/Mazatlan", //$NON-NLS-1$ - Calendar.MAY, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.SEPTEMBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-7 * ONE_HOUR, "America/Phoenix"), //$NON-NLS-1$ - new SimpleTimeZone(-6 * ONE_HOUR, "America/Belize"), //$NON-NLS-1$ - new SimpleTimeZone(-6 * ONE_HOUR, - "America/Chicago", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-6 * ONE_HOUR, "America/El_Salvador"), //$NON-NLS-1$ - new SimpleTimeZone(-6 * ONE_HOUR, "America/Managua"), //$NON-NLS-1$ - new SimpleTimeZone(-6 * ONE_HOUR, - "America/Mexico_City", //$NON-NLS-1$ - Calendar.MAY, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.SEPTEMBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-6 * ONE_HOUR, "America/Regina"), //$NON-NLS-1$ - new SimpleTimeZone(-6 * ONE_HOUR, "America/Tegucigalpa"), //$NON-NLS-1$ - new SimpleTimeZone(-6 * ONE_HOUR, - "America/Winnipeg", //$NON-NLS-1$ //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-6 * ONE_HOUR, - "Pacific/Easter", //$NON-NLS-1$ - Calendar.OCTOBER, 9, -Calendar.SUNDAY, 4 * ONE_HOUR, - Calendar.MARCH, 9, -Calendar.SUNDAY, 3 * ONE_HOUR), - new SimpleTimeZone(-6 * ONE_HOUR, "Pacific/Galapagos"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, "America/Bogota"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, "America/Cayman"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, - "America/Grand_Turk",//$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 0 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(-5 * ONE_HOUR, "America/Guayaquil"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, - "America/Havana", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 0 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(-5 * ONE_HOUR, "America/Indianapolis"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, "America/Jamaica"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, "America/Lima"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, - "America/Montreal", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-5 * ONE_HOUR, - "America/Nassau", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-5 * ONE_HOUR, - "America/New_York", //$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-5 * ONE_HOUR, "America/Panama"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, "America/Port-au-Prince"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, "America/Porto_Acre"), //$NON-NLS-1$ - new SimpleTimeZone(-5 * ONE_HOUR, "America/Rio_Branco"), //$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Anguilla"), //$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Antigua"), //$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Aruba"), //$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, - "America/Asuncion", //$NON-NLS-1$ - Calendar.OCTOBER, 1, -Calendar.SUNDAY, 0 * ONE_HOUR, - Calendar.MARCH, 1, -Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(-4 * ONE_HOUR, "America/Barbados"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Caracas"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, - "America/Cuiaba",//$NON-NLS-1$ - Calendar.OCTOBER, 8, -Calendar.SUNDAY, 0 * ONE_HOUR, - Calendar.FEBRUARY, 15, -Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(-4 * ONE_HOUR, "America/Curacao"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Dominica"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Grenada"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Guadeloupe"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Guyana"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/La_Paz"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Manaus"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Martinique"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Montserrat"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Port_of_Spain"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/Puerto_Rico"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, - "America/Santiago",//$NON-NLS-1$ - Calendar.OCTOBER, 9, -Calendar.SUNDAY, 4 * ONE_HOUR, - Calendar.MARCH, 9, -Calendar.SUNDAY, 3 * ONE_HOUR), - new SimpleTimeZone(-4 * ONE_HOUR, "America/Santo_Domingo"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/St_Kitts"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/St_Lucia"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/St_Thomas"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, "America/St_Vincent"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, - "America/Thule",//$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-4 * ONE_HOUR, "America/Tortola"),//$NON-NLS-1$ - new SimpleTimeZone(-4 * ONE_HOUR, - "Antarctica/Palmer",//$NON-NLS-1$ - Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * ONE_HOUR, - Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(-4 * ONE_HOUR, - "Atlantic/Bermuda",//$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-4 * ONE_HOUR, - "Atlantic/Stanley",//$NON-NLS-1$ - Calendar.SEPTEMBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.APRIL, 15, -Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-3 * ONE_HOUR - 1800000, - "America/St_Johns",//$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 60000, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 60000), - new SimpleTimeZone(-3 * ONE_HOUR, "America/Buenos_Aires"),//$NON-NLS-1$ - new SimpleTimeZone(-3 * ONE_HOUR, "America/Cayenne"),//$NON-NLS-1$ - new SimpleTimeZone(-3 * ONE_HOUR, "America/Fortaleza"),//$NON-NLS-1$ - new SimpleTimeZone(-3 * ONE_HOUR, - "America/Godthab",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(-3 * ONE_HOUR, - "America/Miquelon",//$NON-NLS-1$ - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(-3 * ONE_HOUR, "America/Montevideo"),//$NON-NLS-1$ - new SimpleTimeZone(-3 * ONE_HOUR, "America/Paramaribo"),//$NON-NLS-1$ - new SimpleTimeZone(-3 * ONE_HOUR, - "America/Sao_Paulo",//$NON-NLS-1$ - Calendar.OCTOBER, 8, -Calendar.SUNDAY, 0 * ONE_HOUR, - Calendar.FEBRUARY, 15, -Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(-2 * ONE_HOUR, "America/Noronha"),//$NON-NLS-1$ - new SimpleTimeZone(-1 * ONE_HOUR, - "America/Scoresbysund",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(-1 * ONE_HOUR, "Atlantic/Cape_Verde"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Abidjan"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Accra"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Banjul"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Bissau"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Casablanca"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Conakry"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Dakar"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Freetown"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Lome"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Monrovia"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Nouakchott"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Ouagadougou"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Sao_Tome"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Africa/Timbuktu"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, - "Atlantic/Canary",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(0 * ONE_HOUR, - "Atlantic/Faeroe",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(0 * ONE_HOUR, "Atlantic/Reykjavik"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, "Atlantic/St_Helena"),//$NON-NLS-1$ - new SimpleTimeZone(0 * ONE_HOUR, - "Europe/Dublin",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(0 * ONE_HOUR, - "Europe/Lisbon",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Bangui"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Douala"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Kinshasa"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Lagos"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Libreville"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Luanda"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Malabo"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Ndjamena"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Niamey"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Porto-Novo"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, "Africa/Tunis"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, - "Africa/Windhoek",//$NON-NLS-1$ - Calendar.SEPTEMBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.APRIL, 1, -Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, "Atlantic/Jan_Mayen"),//$NON-NLS-1$ - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Amsterdam",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Andorra",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Belgrade",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Berlin",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Brussels",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Budapest",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Copenhagen",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Gibraltar",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Luxembourg",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Madrid",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Malta",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Monaco",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, "Europe/Oslo", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Paris",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Prague",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, "Europe/Rome", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Stockholm",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Tirane",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Vaduz",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Vienna",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Warsaw",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(1 * ONE_HOUR, - "Europe/Zurich",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Blantyre"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Bujumbura"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Gaborone"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Johannesburg"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Kigali"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Lubumbashi"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Lusaka"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Maputo"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Maseru"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Mbabane"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Africa/Tripoli"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Asia/Amman", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.THURSDAY, 0 * ONE_HOUR, - Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 0 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, "Asia/Beirut", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Asia/Damascus",//$NON-NLS-1$ - Calendar.APRIL, 1, 0, 0 * ONE_HOUR, Calendar.OCTOBER, - 1, 0, 0 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Asia/Nicosia",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Athens",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Chisinau",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Helsinki",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Istanbul",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Kaliningrad",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, "Europe/Kiev", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Minsk",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, "Europe/Riga", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Simferopol",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, - "Europe/Sofia",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 1 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(2 * ONE_HOUR, "Europe/Tallinn"),//$NON-NLS-1$ - new SimpleTimeZone(2 * ONE_HOUR, "Europe/Vilnius"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Africa/Addis_Ababa"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Africa/Asmera"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Africa/Dar_es_Salaam"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Africa/Djibouti"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Africa/Kampala"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Africa/Khartoum"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Africa/Mogadishu"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Africa/Nairobi"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Asia/Aden"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, - "Asia/Baghdad",//$NON-NLS-1$ - Calendar.APRIL, 1, 0, 3 * ONE_HOUR, Calendar.OCTOBER, - 1, 0, 3 * ONE_HOUR), - new SimpleTimeZone(3 * ONE_HOUR, "Asia/Bahrain"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Asia/Kuwait"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Asia/Qatar"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Asia/Riyadh"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Indian/Antananarivo"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Indian/Comoro"),//$NON-NLS-1$ - new SimpleTimeZone(3 * ONE_HOUR, "Indian/Mayotte"),//$NON-NLS-1$ - new SimpleTimeZone(4 * ONE_HOUR, "Asia/Aqtau", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(4 * ONE_HOUR, "Asia/Baku", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 1 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 1 * ONE_HOUR), - new SimpleTimeZone(4 * ONE_HOUR, "Asia/Muscat"),//$NON-NLS-1$ - new SimpleTimeZone(4 * ONE_HOUR, - "Asia/Tbilisi",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 0 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(4 * ONE_HOUR, - "Asia/Yerevan",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(4 * ONE_HOUR, - "Europe/Samara",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(4 * ONE_HOUR, "Indian/Mahe"),//$NON-NLS-1$ - new SimpleTimeZone(4 * ONE_HOUR, "Indian/Mauritius"),//$NON-NLS-1$ - new SimpleTimeZone(4 * ONE_HOUR, "Indian/Reunion"),//$NON-NLS-1$ - new SimpleTimeZone(5 * ONE_HOUR, "Asia/Aqtobe", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(5 * ONE_HOUR, "Asia/Ashgabat"),//$NON-NLS-1$ - new SimpleTimeZone(5 * ONE_HOUR, "Asia/Ashkhabad"),//$NON-NLS-1$ - new SimpleTimeZone( - 5 * ONE_HOUR, - "Asia/Bishkek",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, - 2 * ONE_HOUR + 1800000, Calendar.OCTOBER, -1, - Calendar.SUNDAY, 2 * ONE_HOUR + 1800000), - new SimpleTimeZone(5 * ONE_HOUR, "Asia/Dushanbe"),//$NON-NLS-1$ - new SimpleTimeZone(5 * ONE_HOUR, "Asia/Karachi"),//$NON-NLS-1$ - new SimpleTimeZone(5 * ONE_HOUR, "Asia/Tashkent"),//$NON-NLS-1$ - new SimpleTimeZone(5 * ONE_HOUR, - "Asia/Yekaterinburg",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(5 * ONE_HOUR, "Indian/Kerguelen"),//$NON-NLS-1$ - new SimpleTimeZone(5 * ONE_HOUR, "Indian/Maldives"),//$NON-NLS-1$ - new SimpleTimeZone(5 * ONE_HOUR + 1800000, "Asia/Calcutta"),//$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR, "Antarctica/Mawson"),//$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR, "Asia/Almaty", Calendar.MARCH,//$NON-NLS-1$ - -1, Calendar.SUNDAY, 0 * ONE_HOUR, Calendar.OCTOBER, - -1, Calendar.SUNDAY, 0 * ONE_HOUR), - new SimpleTimeZone(5 * ONE_HOUR + HALF_HOUR, "Asia/Colombo"),//$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR, "Asia/Dacca"),//$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR, "Asia/Dhaka"),//$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR, - "Asia/Novosibirsk",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(6 * ONE_HOUR, "Asia/Thimbu"),//$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR, "Asia/Thimphu"),//$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR, "Indian/Chagos"),//$NON-NLS-1$ - new SimpleTimeZone(6 * ONE_HOUR + 1800000, "Indian/Cocos"),//$NON-NLS-1$ - new SimpleTimeZone(7 * ONE_HOUR, "Asia/Bangkok"),//$NON-NLS-1$ - new SimpleTimeZone(7 * ONE_HOUR, "Asia/Jakarta"),//$NON-NLS-1$ - new SimpleTimeZone(7 * ONE_HOUR, - "Asia/Krasnoyarsk",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(7 * ONE_HOUR, "Asia/Phnom_Penh"),//$NON-NLS-1$ - new SimpleTimeZone(7 * ONE_HOUR, "Asia/Saigon"),//$NON-NLS-1$ - new SimpleTimeZone(7 * ONE_HOUR, "Asia/Vientiane"),//$NON-NLS-1$ - new SimpleTimeZone(7 * ONE_HOUR, "Indian/Christmas"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Antarctica/Casey"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Brunei"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Hong_Kong"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, - "Asia/Irkutsk",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Kuala_Lumpur"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Macao"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Manila"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Shanghai"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Singapore"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Taipei"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Ujung_Pandang"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Ulaanbaatar"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Asia/Ulan_Bator"),//$NON-NLS-1$ - new SimpleTimeZone(8 * ONE_HOUR, "Australia/Perth"),//$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR, "Asia/Jayapura"),//$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR, "Asia/Pyongyang"),//$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR, "Asia/Seoul"),//$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR, "Asia/Tokyo"),//$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR, - "Asia/Yakutsk",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR),//$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR, "Pacific/Palau"),//$NON-NLS-1$ - new SimpleTimeZone(9 * ONE_HOUR + 1800000, - "Australia/Broken_Hill", Calendar.OCTOBER, -1,//$NON-NLS-1$ - Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, -1, - Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(9 * ONE_HOUR + 1800000, "Australia/Darwin"),//$NON-NLS-1$ - new SimpleTimeZone(10 * ONE_HOUR, "Antarctica/DumontDUrville"),//$NON-NLS-1$ - new SimpleTimeZone(10 * ONE_HOUR, - "Asia/Vladivostok",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(10 * ONE_HOUR, - "Australia/Sydney",//$NON-NLS-1$ - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(10 * ONE_HOUR, "Pacific/Guam"),//$NON-NLS-1$ - new SimpleTimeZone(10 * ONE_HOUR, "Pacific/Port_Moresby"),//$NON-NLS-1$ - new SimpleTimeZone(10 * ONE_HOUR, "Pacific/Saipan"),//$NON-NLS-1$ - new SimpleTimeZone(10 * ONE_HOUR, "Pacific/Truk"),//$NON-NLS-1$ - new SimpleTimeZone(10 * ONE_HOUR + 1800000, - "Australia/Lord_Howe", Calendar.OCTOBER, -1,//$NON-NLS-1$ - Calendar.SUNDAY, 2 * ONE_HOUR, Calendar.MARCH, -1, - Calendar.SUNDAY, 2 * ONE_HOUR, 1800000), - new SimpleTimeZone(11 * ONE_HOUR, - "Asia/Magadan",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Efate"),//$NON-NLS-1$ - new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Guadalcanal"),//$NON-NLS-1$ - new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Kosrae"),//$NON-NLS-1$ - new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Noumea"),//$NON-NLS-1$ - new SimpleTimeZone(11 * ONE_HOUR, "Pacific/Ponape"),//$NON-NLS-1$ - new SimpleTimeZone(11 * ONE_HOUR + 1800000, "Pacific/Norfolk"),//$NON-NLS-1$ - new SimpleTimeZone(12 * ONE_HOUR, - "Antarctica/McMurdo",//$NON-NLS-1$ - Calendar.OCTOBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.MARCH, 15, -Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(12 * ONE_HOUR, - "Asia/Anadyr",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(12 * ONE_HOUR, - "Asia/Kamchatka",//$NON-NLS-1$ - Calendar.MARCH, -1, Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(12 * ONE_HOUR, - "Pacific/Auckland",//$NON-NLS-1$ - Calendar.OCTOBER, 1, -Calendar.SUNDAY, 2 * ONE_HOUR, - Calendar.MARCH, 15, -Calendar.SUNDAY, 2 * ONE_HOUR), - new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Fiji"),//$NON-NLS-1$ - new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Funafuti"),//$NON-NLS-1$ - new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Majuro"),//$NON-NLS-1$ - new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Nauru"),//$NON-NLS-1$ - new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Tarawa"),//$NON-NLS-1$ - new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Wake"),//$NON-NLS-1$ - new SimpleTimeZone(12 * ONE_HOUR, "Pacific/Wallis"),//$NON-NLS-1$ - new SimpleTimeZone(13 * ONE_HOUR, "Pacific/Enderbury"),//$NON-NLS-1$ - new SimpleTimeZone(13 * ONE_HOUR, "Pacific/Tongatapu"),//$NON-NLS-1$ - new SimpleTimeZone(14 * ONE_HOUR, "Pacific/Kiritimati"), };//$NON-NLS-1$ - } -}