/* java.util.SimpleTimeZone Copyright (C) 1998, 1999, 2000, 2003, 2004, 2005, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Classpath; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ package java.util; /** * This class represents a simple time zone offset and handles * daylight savings. It can only handle one daylight savings rule, so * it can't represent historical changes. * * This object is tightly bound to the Gregorian calendar. It assumes * a regular seven days week, and the month lengths are that of the * Gregorian Calendar. It can only handle daylight savings for years * lying in the AD era. * * @see Calendar * @see GregorianCalendar * @author Jochen Hoenicke */ public class SimpleTimeZone extends TimeZone { /** * The raw time zone offset in milliseconds to GMT, ignoring * daylight savings. * @serial */ private int rawOffset; /** * True, if this timezone uses daylight savings, false otherwise. * @serial */ private boolean useDaylight; /** * The daylight savings offset. This is a positive offset in * milliseconds with respect to standard time. Typically this * is one hour, but for some time zones this may be half an hour. * @serial * @since JDK1.1.4 */ private int dstSavings = 60 * 60 * 1000; /** * The first year, in which daylight savings rules applies. * @serial */ private int startYear; private static final int DOM_MODE = 1; private static final int DOW_IN_MONTH_MODE = 2; private static final int DOW_GE_DOM_MODE = 3; private static final int DOW_LE_DOM_MODE = 4; /** * The mode of the start rule. This takes one of the following values: *
SimpleTimeZone with the given time offset
* from GMT and without daylight savings.
* @param rawOffset the time offset from GMT in milliseconds.
* @param id The identifier of this time zone.
*/
public SimpleTimeZone(int rawOffset, String id)
{
this.rawOffset = rawOffset;
setID(id);
useDaylight = false;
startYear = 0;
}
/**
* Create a SimpleTimeZone with the given time offset
* from GMT and with daylight savings. The start/end parameters
* can have different meaning (replace WEEKDAY with a real day of
* week). Only the first two meanings were supported by earlier
* versions of jdk.
*
* day > 0, dayOfWeek = Calendar.WEEKDAYday-th
* WEEKDAY in the given month. day < 0, dayOfWeek = Calendar.WEEKDAY-day-th
* WEEKDAY counted from the end of the month. day > 0, dayOfWeek = 0day-th day of
* the month. day > 0, dayOfWeek = -Calendar.WEEKDAYday-th day of the month. You must make sure that
* this day lies in the same month. day < 0, dayOfWeek = -Calendar.WEEKDAY-day-th day of the month. You
* must make sure that this day lies in the same month. setEndRule or the result of
* getOffset is undefined. For the parameters see the ten-argument
* constructor above.
*
* @param month The month where daylight savings start, zero
* based. You should use the constants in Calendar.
* @param day A day of month or day of week in month.
* @param dayOfWeek The day of week where daylight savings start.
* @param time The time in milliseconds standard time where daylight
* savings start.
* @exception IllegalArgumentException if parameters are out of range.
* @see SimpleTimeZone
*/
public void setStartRule(int month, int day, int dayOfWeek, int time)
{
this.startMode = checkRule(month, day, dayOfWeek);
this.startMonth = month;
this.startDay = day;
this.startDayOfWeek = Math.abs(dayOfWeek);
this.startTime = time;
this.startTimeMode = WALL_TIME;
}
/**
* Sets the daylight savings start rule. You must also set the
* end rule with setEndRule or the result of
* getOffset is undefined. For the parameters see the ten-argument
* constructor above.
*
* Note that this API isn't incredibly well specified. It appears that the
* after flag must override the parameters, since normally, the day and
* dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or
* before mode is chosen. But if after == true, this implementation
* overrides the signs of the other arguments. And if dayOfWeek == 0, it
* falls back to the behavior in the other APIs. I guess this should be
* checked against Sun's implementation.
*
* @param month The month where daylight savings start, zero
* based. You should use the constants in Calendar.
* @param day A day of month or day of week in month.
* @param dayOfWeek The day of week where daylight savings start.
* @param time The time in milliseconds standard time where daylight
* savings start.
* @param after If true, day and dayOfWeek specify first day of week on or
* after day, else first day of week on or before.
* @since 1.2
* @see SimpleTimeZone
*/
public void setStartRule(int month, int day, int dayOfWeek, int time,
boolean after)
{
if (after)
setStartRule(month, day, -dayOfWeek, time);
else
setStartRule(month, -day, -dayOfWeek, time);
}
/**
* Sets the daylight savings start rule. You must also set the
* end rule with setEndRule or the result of
* getOffset is undefined. For the parameters see the ten-argument
* constructor above.
*
* @param month The month where daylight savings start, zero
* based. You should use the constants in Calendar.
* @param day A day of month or day of week in month.
* @param time The time in milliseconds standard time where daylight
* savings start.
* @see SimpleTimeZone
* @since 1.2
*/
public void setStartRule(int month, int day, int time)
{
setStartRule(month, day, 0, time);
}
/**
* Sets the daylight savings end rule. You must also set the
* start rule with setStartRule or the result of
* getOffset is undefined. For the parameters see the ten-argument
* constructor above.
*
* @param month The end month of daylight savings.
* @param day A day in month, or a day of week in month.
* @param dayOfWeek A day of week, when daylight savings ends.
* @param time A time in millis in standard time.
* @see #setStartRule(int, int, int, int)
*/
public void setEndRule(int month, int day, int dayOfWeek, int time)
{
this.endMode = checkRule(month, day, dayOfWeek);
this.endMonth = month;
this.endDay = day;
this.endDayOfWeek = Math.abs(dayOfWeek);
this.endTime = time;
this.endTimeMode = WALL_TIME;
useDaylight = true;
}
/**
* Sets the daylight savings end rule. You must also set the
* start rule with setStartRule or the result of
* getOffset is undefined. For the parameters see the ten-argument
* constructor above.
*
* Note that this API isn't incredibly well specified. It appears that the
* after flag must override the parameters, since normally, the day and
* dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or
* before mode is chosen. But if after == true, this implementation
* overrides the signs of the other arguments. And if dayOfWeek == 0, it
* falls back to the behavior in the other APIs. I guess this should be
* checked against Sun's implementation.
*
* @param month The end month of daylight savings.
* @param day A day in month, or a day of week in month.
* @param dayOfWeek A day of week, when daylight savings ends.
* @param time A time in millis in standard time.
* @param after If true, day and dayOfWeek specify first day of week on or
* after day, else first day of week on or before.
* @since 1.2
* @see #setStartRule(int, int, int, int, boolean)
*/
public void setEndRule(int month, int day, int dayOfWeek, int time,
boolean after)
{
if (after)
setEndRule(month, day, -dayOfWeek, time);
else
setEndRule(month, -day, -dayOfWeek, time);
}
/**
* Sets the daylight savings end rule. You must also set the
* start rule with setStartRule or the result of
* getOffset is undefined. For the parameters see the ten-argument
* constructor above.
*
* @param month The end month of daylight savings.
* @param day A day in month, or a day of week in month.
* @param time A time in millis in standard time.
* @see #setStartRule(int, int, int)
*/
public void setEndRule(int month, int day, int time)
{
setEndRule(month, day, 0, time);
}
/**
* Gets the time zone offset, for current date, modified in case of
* daylight savings. This is the offset to add to UTC to get the local
* time.
*
* In the standard JDK the results given by this method may result in
* inaccurate results at the end of February or the beginning of March.
* To avoid this, you should use Calendar instead:
* offset = cal.get(Calendar.ZONE_OFFSET)
* + cal.get(Calendar.DST_OFFSET);
*
* This version doesn't suffer this inaccuracy.
*
* The arguments don't follow the approach for setting start and end rules.
* The day must be a positive number and dayOfWeek must be a positive value
* from Calendar. dayOfWeek is redundant, but must match the other values
* or an inaccurate result may be returned.
*
* @param era the era of the given date
* @param year the year of the given date
* @param month the month of the given date, 0 for January.
* @param day the day of month
* @param dayOfWeek the day of week; this must match the other fields.
* @param millis the millis in the day (in local standard time)
* @return the time zone offset in milliseconds.
* @throws IllegalArgumentException if arguments are incorrect.
*/
public int getOffset(int era, int year, int month, int day, int dayOfWeek,
int millis)
{
int daysInMonth = getDaysInMonth(month, year);
if (day < 1 || day > daysInMonth)
throw new IllegalArgumentException("day out of range");
if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
throw new IllegalArgumentException("dayOfWeek out of range");
if (month < Calendar.JANUARY || month > Calendar.DECEMBER)
throw new IllegalArgumentException("month out of range:" + month);
// This method is called by Calendar, so we mustn't use that class.
int daylightSavings = 0;
if (useDaylight && era == GregorianCalendar.AD && year >= startYear)
{
int orig_year = year;
int time = startTime + (startTimeMode == UTC_TIME ? rawOffset : 0);
// This does only work for Gregorian calendars :-(
// This is mainly because setStartYear doesn't take an era.
boolean afterStart = ! isBefore(year, month, day, dayOfWeek, millis,
startMode, startMonth, startDay,
startDayOfWeek, time);
millis += dstSavings;
if (millis >= 24 * 60 * 60 * 1000)
{
millis -= 24 * 60 * 60 * 1000;
dayOfWeek = (dayOfWeek % 7) + 1;
if (++day > daysInMonth)
{
day = 1;
if (month++ == Calendar.DECEMBER)
{
mo