FileDocCategorySizeDatePackage
TimeZoneImpl.javaAPI DocJ2ME CLDC 1.1116666Wed Feb 05 15:55:58 GMT 2003com.sun.cldc.util.j2me

TimeZoneImpl

public class TimeZoneImpl extends TimeZone
This class provides the time zone implementations for J2ME CLDC/MIDP. By default, the only supported time zone is UTC/GMT. Vendor-specific implementations may provide additional time zones.
see
java.util.TimeZone

Fields Summary
static String
HOME_ID
private static final int
ONE_MINUTE
private static final int
ONE_HOUR
private static final int
ONE_DAY
private String
ID
The string identifier of this TimeZone. This is a programmatic identifier used internally to look up TimeZone objects from the system table and also to map them to their localized display names. ID values are unique in the system table but may not be for dynamically created zones.
static String[]
ids
private int
startMonth
The month in which daylight savings time starts. This value must be between Calendar.JANUARY and Calendar.DECEMBER inclusive. This value must not equal endMonth.

If useDaylight is false, this value is ignored.

private int
startDay
This field has two possible interpretations:
startMode == DOW_IN_MONTH
startDay indicates the day of the month of startMonth on which daylight savings time starts, from 1 to 28, 30, or 31, depending on the startMonth.
startMode != DOW_IN_MONTH
startDay indicates which startDayOfWeek in th month startMonth daylight savings time starts on. For example, a value of +1 and a startDayOfWeek of Calendar.SUNDAY indicates the first Sunday of startMonth. Likewise, +2 would indicate the second Sunday, and -1 the last Sunday. A value of 0 is illegal.

If useDaylight is false, this value is ignored.

private int
startDayOfWeek
The day of the week on which daylight savings time starts. This value must be between Calendar.SUNDAY and Calendar.SATURDAY inclusive.

If useDaylight is false or startMode == DAY_OF_MONTH, this value is ignored.

private int
startTime
The time in milliseconds after midnight at which daylight savings time starts. This value is expressed as wall time, which means it is compared to standard time for the daylight savings start.

If useDaylight is false, this value is ignored.

private int
endMonth
The month in which daylight savings time ends. This value must be between Calendar.JANUARY and Calendar.UNDECIMBER. This value must not equal startMonth.

If useDaylight is false, this value is ignored.

private int
endDay
This field has two possible interpretations:
endMode == DOW_IN_MONTH
endDay indicates the day of the month of endMonth on which daylight savings time ends, from 1 to 28, 30, or 31, depending on the endMonth.
endMode != DOW_IN_MONTH
endDay indicates which endDayOfWeek in th month endMonth daylight savings time ends on. For example, a value of +1 and a endDayOfWeek of Calendar.SUNDAY indicates the first Sunday of endMonth. Likewise, +2 would indicate the second Sunday, and -1 the last Sunday. A value of 0 is illegal.

If useDaylight is false, this value is ignored.

private int
endDayOfWeek
The day of the week on which daylight savings time ends. This value must be between Calendar.SUNDAY and Calendar.SATURDAY inclusive.

If useDaylight is false or endMode == DAY_OF_MONTH, this value is ignored.

private int
endTime
The time in milliseconds after midnight at which daylight savings time ends. This value is expressed as wall time, which means it is compared to daylight time for the daylight savings end.

If useDaylight is false, this value is ignored.

private int
startYear
The year in which daylight savings time is first observed. This is an AD value. If this value is less than 1 then daylight savings is observed for all AD years.

If useDaylight is false, this value is ignored.

private int
rawOffset
The offset in milliseconds between this zone and GMT. Negative offsets are to the west of Greenwich. To obtain local standard time, add the offset to GMT time. To obtain local wall time it may also be necessary to add dstSavings.
private boolean
useDaylight
A boolean value which is true if and only if this zone uses daylight savings time. If this value is false, several other fields are ignored.
private static final int
millisPerHour
private static final int
millisPerDay
private final byte[]
monthLength
This field was serialized in JDK 1.1, so we have to keep it that way to maintain serialization compatibility. However, there's no need to recreate the array each time we create a new time zone.
private static final byte[]
staticMonthLength
private int
startMode
Variables specifying the mode of the start rule. Takes the following values:
DOM_MODE
Exact day of week; e.g., March 1.
DOW_IN_MONTH_MODE
Day of week in month; e.g., last Sunday in March.
DOW_GE_DOM_MODE
Day of week after day of month; e.g., Sunday on or after March 15.
DOW_LE_DOM_MODE
Day of week before day of month; e.g., Sunday on or before March 15.
The setting of this field affects the interpretation of the startDay field.

If useDaylight is false, this value is ignored.

private int
endMode
Variables specifying the mode of the end rule. Takes the following values:
DOM_MODE
Exact day of week; e.g., March 1.
DOW_IN_MONTH_MODE
Day of week in month; e.g., last Sunday in March.
DOW_GE_DOM_MODE
Day of week after day of month; e.g., Sunday on or after March 15.
DOW_LE_DOM_MODE
Day of week before day of month; e.g., Sunday on or before March 15.
The setting of this field affects the interpretation of the endDay field.

If useDaylight is false, this value is ignored.

private int
dstSavings
A positive value indicating the amount of time saved during DST in milliseconds. Typically one hour (3600000); sometimes 30 minutes (1800000).

If useDaylight is false, this value is ignored.

private static final int
DOM_MODE
Constants specifying values of startMode and endMode.
private static final int
DOW_IN_MONTH_MODE
private static final int
DOW_GE_DOM_MODE
private static final int
DOW_LE_DOM_MODE
static TimeZone[]
zones
Constructors Summary
public TimeZoneImpl()


      
private TimeZoneImpl(int rawOffset, String ID)
Constructs a TimeZone with the given base time zone offset from GMT and time zone ID. Timezone IDs can be obtained from TimeZone.getAvailableIDs. Normally you should use TimeZone.getDefault to construct a TimeZone.

param
rawOffset The given base time zone offset to GMT.
param
ID The time zone ID which is obtained from TimeZone.getAvailableIDs.

        this.rawOffset = rawOffset;
        this.ID = ID;
        dstSavings = millisPerHour; // In case user sets rules later
    
private TimeZoneImpl(int rawOffset, String ID, int startMonth, int startDay, int startDayOfWeek, int startTime, int endMonth, int endDay, int endDayOfWeek, int endTime, int dstSavings)
Constructor. This constructor is identical to the 10-argument constructor, but also takes a dstSavings parameter.

param
dstSavings The amount of time in ms saved during DST.
exception
IllegalArgumentException the month, day, dayOfWeek, or time parameters are out of range for the start or end rule

        this.ID             = ID;
        this.rawOffset      = rawOffset;
        this.startMonth     = startMonth;
        this.startDay       = startDay;
        this.startDayOfWeek = startDayOfWeek;
        this.startTime      = startTime;
        this.endMonth       = endMonth;
        this.endDay         = endDay;
        this.endDayOfWeek   = endDayOfWeek;
        this.endTime        = endTime;
        this.dstSavings     = dstSavings;
        decodeRules();
        if (dstSavings <= 0) {
           throw new IllegalArgumentException("Illegal DST savings");
        }
    
Methods Summary
private static intcompareToRule(int month, int monthLen, int dayOfMonth, int dayOfWeek, int millis, int ruleMode, int ruleMonth, int ruleDayOfWeek, int ruleDay, int ruleMillis)
Compare a given date in the year to a rule. Return 1, 0, or -1, depending on whether the date is after, equal to, or before the rule date. The millis are compared directly against the ruleMillis, so any standard-daylight adjustments must be handled by the caller.

return
1 if the date is after the rule date, -1 if the date is before the rule date, or 0 if the date is equal to the rule date.

        if (month < ruleMonth) return -1;
        else if (month > ruleMonth) return 1;

        int ruleDayOfMonth = 0;
        switch (ruleMode) {
        case DOM_MODE:
            ruleDayOfMonth = ruleDay;
            break;
        case DOW_IN_MONTH_MODE:
            // In this case ruleDay is the day-of-week-in-month
            if (ruleDay > 0) {
                ruleDayOfMonth = 1 + (ruleDay - 1) * 7 +
                (7 + ruleDayOfWeek - (dayOfWeek - dayOfMonth + 1)) % 7;
            } else {
                // Assume ruleDay < 0 here
                ruleDayOfMonth = monthLen + (ruleDay + 1) * 7 -
                    (7 + (dayOfWeek + monthLen - dayOfMonth) - ruleDayOfWeek) % 7;
            }
            break;
        case DOW_GE_DOM_MODE:
            ruleDayOfMonth = ruleDay +
                (49 + ruleDayOfWeek - ruleDay - dayOfWeek + dayOfMonth) % 7;
            break;
        case DOW_LE_DOM_MODE:
            ruleDayOfMonth = ruleDay -
                (49 - ruleDayOfWeek + ruleDay + dayOfWeek - dayOfMonth) % 7;
            // Note at this point ruleDayOfMonth may be <1, although it will
            // be >=1 for well-formed rules.
            break;
        }

        if (dayOfMonth < ruleDayOfMonth) return -1;
        else if (dayOfMonth > ruleDayOfMonth) return 1;

        if (millis < ruleMillis) return -1;
        else if (millis > ruleMillis) return 1;
        else return 0;
    
private voiddecodeEndRule()
Decode the end rule and validate the parameters. This method is exactly analogous to decodeStartRule().

see
decodeStartRule

        useDaylight = (startDay != 0) && (endDay != 0);
        if (endDay != 0) {
            if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
                throw new IllegalArgumentException(
                              "Illegal end month " + endMonth);
            }
            if (endTime < 0 || endTime > millisPerDay) {
                throw new IllegalArgumentException(
                              "Illegal end time " + endTime);
            }
            if (endDayOfWeek == 0) {
                endMode = DOM_MODE;
            } else {
                if (endDayOfWeek > 0) {
                    endMode = DOW_IN_MONTH_MODE;
                } else {
                    endDayOfWeek = -endDayOfWeek;
                    if (endDay > 0) {
                        endMode = DOW_GE_DOM_MODE;
                    } else {
                        endDay = -endDay;
                        endMode = DOW_LE_DOM_MODE;
                    }
                }
                if (endDayOfWeek > Calendar.SATURDAY) {
                    throw new IllegalArgumentException(
                                  "Illegal end day of week " + endDayOfWeek);
                }
            }
            if (endMode == DOW_IN_MONTH_MODE) {
                if (endDay < -5 || endDay > 5) {
                    throw new IllegalArgumentException(
                                  "Illegal end day of week in month " + endDay);
                }
            } else if (endDay > staticMonthLength[endMonth]) {
                throw new IllegalArgumentException(
                              "Illegal end day " + endDay);
            }
        }
    
private voiddecodeRules()
Given a set of encoded rules in startDay and startDayOfMonth, decode them and set the startMode appropriately. Do the same for endDay and endDayOfMonth. Upon entry, the day of week variables may be zero or negative, in order to indicate special modes. The day of month variables may also be negative. Upon exit, the mode variables will be set, and the day of week and day of month variables will be positive. This method also recognizes a startDay or endDay of zero as indicating no DST.

 // Day of week before day of month, "Sun<=21"

    //----------------------------------------------------------------------
    // Rule representation
    //
    // We represent the following flavors of rules:
    //       5        the fifth of the month
    //       lastSun  the last Sunday in the month
    //       lastMon  the last Monday in the month
    //       Sun>=8   first Sunday on or after the eighth
    //       Sun<=25  last Sunday on or before the 25th
    // This is further complicated by the fact that we need to remain
    // backward compatible with the 1.1 FCS.  Finally, we need to minimize
    // API changes.  In order to satisfy these requirements, we support
    // three representation systems, and we translate between them.
    //
    // INTERNAL REPRESENTATION
    // This is the format TimeZone objects take after construction or
    // streaming in is complete.  Rules are represented directly, using an
    // unencoded format.  We will discuss the start rule only below; the end
    // rule is analogous.
    //   startMode      Takes on enumerated values DAY_OF_MONTH,
    //                  DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
    //   startDay       The day of the month, or for DOW_IN_MONTH mode, a
    //                  value indicating which DOW, such as +1 for first,
    //                  +2 for second, -1 for last, etc.
    //   startDayOfWeek The day of the week.  Ignored for DAY_OF_MONTH.
    //
    // ENCODED REPRESENTATION
    // This is the format accepted by the constructor and by setStartRule()
    // and setEndRule().  It uses various combinations of positive, negative,
    // and zero values to encode the different rules.  This representation
    // allows us to specify all the different rule flavors without altering
    // the API.
    //   MODE              startMonth    startDay    startDayOfWeek
    //   DOW_IN_MONTH_MODE >=0           !=0         >0
    //   DOM_MODE          >=0           >0          ==0
    //   DOW_GE_DOM_MODE   >=0           >0          <0
    //   DOW_LE_DOM_MODE   >=0           <0          <0
    //   (no DST)          don't care    ==0         don't care
    //
    // STREAMED REPRESENTATION
    // We must retain binary compatibility with the 1.1 FCS.  The 1.1 code only
    // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
    // flag useDaylight.  When we stream an object out, we translate into an
    // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
    // and used by 1.1 code.  Following that, we write out the full
    // representation separately so that contemporary code can recognize and
    // parse it.  The full representation is written in a "packed" format,
    // consisting of a version number, a length, and an array of bytes.  Future
    // versions of this class may specify different versions.  If they wish to
    // include additional data, they should do so by storing them after the
    // packed representation below.
    //----------------------------------------------------------------------

                                                                                                   
       
        decodeStartRule();
        decodeEndRule();
    
private voiddecodeStartRule()
Decode the start rule and validate the parameters. The parameters are expected to be in encoded form, which represents the various rule modes by negating or zeroing certain values. Representation formats are:

DOW_IN_MONTH DOM DOW>=DOM DOW<=DOM no DST
------------ ----- -------- -------- ----------
month 0..11 same same same don't care
day -5..5 1..31 1..31 -1..-31 0
dayOfWeek 1..7 0 -1..-7 -1..-7 don't care
time 0..ONEDAY same same same don't care
The range for month does not include UNDECIMBER since this class is really specific to Calendar, which does not use that month. The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the end rule is an exclusive limit point. That is, the range of times that are in DST include those >= the start and < the end. For this reason, it should be possible to specify an end of ONEDAY in order to include the entire day. Although this is equivalent to time 0 of the following day, it's not always possible to specify that, for example, on December 31. While arguably the start range should still be 0..ONEDAY-1, we keep the start and end ranges the same for consistency.

        useDaylight = (startDay != 0) && (endDay != 0);
        if (startDay != 0) {
            if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
                throw new IllegalArgumentException(
                              "Illegal start month " + startMonth);
            }
            if (startTime < 0 || startTime > millisPerDay) {
                throw new IllegalArgumentException(
                              "Illegal start time " + startTime);
            }
            if (startDayOfWeek == 0) {
                startMode = DOM_MODE;
            } else {
                if (startDayOfWeek > 0) {
                    startMode = DOW_IN_MONTH_MODE;
                } else {
                    startDayOfWeek = -startDayOfWeek;
                    if (startDay > 0) {
                        startMode = DOW_GE_DOM_MODE;
                    } else {
                        startDay = -startDay;
                        startMode = DOW_LE_DOM_MODE;
                    }
                }
                if (startDayOfWeek > Calendar.SATURDAY) {
                    throw new IllegalArgumentException(
                                  "Illegal start day of week " + startDayOfWeek);
                }
            }
            if (startMode == DOW_IN_MONTH_MODE) {
                if (startDay < -5 || startDay > 5) {
                    throw new IllegalArgumentException(
                                  "Illegal start day of week in month " + startDay);
                }
            } else if (startDay > staticMonthLength[startMonth]) {
                throw new IllegalArgumentException(
                              "Illegal start day " + startDay);
            }
        }
    
public java.lang.StringgetID()
Gets the ID of this time zone.

return
the ID of this time zone.

        return ID;
    
public synchronized java.lang.String[]getIDs()
Gets all the available IDs supported.

return
an array of IDs.

        if (ids == null) {
            ids = new String[zones.length];
            for (int i = 0; i < zones.length; i++)
                ids[i] = zones[i].getID();
        }
        return ids;
    
public synchronized java.util.TimeZonegetInstance(java.lang.String ID)
Gets the TimeZone for the given ID.

param
ID the ID for a TimeZone, either an abbreviation such as "GMT", or a full name such as "America/Los_Angeles".

The only time zone ID that is required to be supported is "GMT", though typically, the timezones for the regions where the device is sold should be supported.

return
the specified TimeZone, or null if the given ID cannot be understood.

        if (ID == null) {
            if (HOME_ID == null) {
                HOME_ID = System.getProperty("com.sun.cldc.util.j2me.TimeZoneImpl.timezone");
                if (HOME_ID == null)
                    HOME_ID = "UTC";
            }
            ID = HOME_ID;
        }
        for (int i = 0; i < zones.length; i++) {
            if (zones[i].getID().equals(ID))
                return zones[i];
            }
        return null;
    
public intgetOffset(int era, int year, int month, int day, int dayOfWeek, int millis)
Gets offset, for current date, modified in case of daylight savings. This is the offset to add *to* GMT to get local time. Gets the time zone offset, for current date, modified in case of daylight savings. This is the offset to add *to* GMT to get local time. Assume that the start and end month are distinct. This method may return incorrect results for rules that start at the end of February (e.g., last Sunday in February) or the beginning of March (e.g., March 1).

param
era The era of the given date (0 = BC, 1 = AD).
param
year The year in the given date.
param
month The month in the given date. Month is 0-based. e.g., 0 for January.
param
day The day-in-month of the given date.
param
dayOfWeek The day-of-week of the given date.
param
millis The milliseconds in day in standard local time.
return
The offset to add *to* GMT to get local time.
exception
IllegalArgumentException the era, month, day, dayOfWeek, or millis parameters are out of range


                                                                                                                                                                                                                                                                         
             
                             
        if (month < Calendar.JANUARY
            || month > Calendar.DECEMBER) {

            throw new IllegalArgumentException("Illegal month " + month);
        }
        return getOffset(era, year, month, day, dayOfWeek, millis,
                         staticMonthLength[month]);
    
intgetOffset(int era, int year, int month, int day, int dayOfWeek, int millis, int monthLength)
Gets offset, for current date, modified in case of daylight savings. This is the offset to add to GMT to get local time. Gets the time zone offset, for current date, modified in case of daylight savings. This is the offset to add *to* GMT to get local time. Assume that the start and end month are distinct.

param
era The era of the given date (0 = BC, 1 = AD).
param
year The year in the given date.
param
month The month in the given date. Month is 0-based. e.g., 0 for January.
param
day The day-in-month of the given date.
param
dayOfWeek The day-of-week of the given date.
param
millis The milliseconds in day in standard local time.
param
monthLength The length of the given month in days.
return
The offset to add *to* GMT to get local time.
exception
IllegalArgumentException the era, month, day, dayOfWeek, millis, or monthLength parameters are out of range

        if (true) {
            // Use this parameter checking code for normal operation.  Only one
            // of these two blocks should actually get compiled into the class
            // file.
            if ((era != 0 && era != 1)
                || month < Calendar.JANUARY
                || month > Calendar.DECEMBER
                || day < 1
                || day > monthLength
                || dayOfWeek < Calendar.SUNDAY
                || dayOfWeek > Calendar.SATURDAY
                || millis < 0
                || millis >= millisPerDay
                || monthLength < 28
                || monthLength > 31) {

                throw new IllegalArgumentException();
            }
        } else {
            // This parameter checking code is better for debugging, but
            // overkill for normal operation.  Only one of these two blocks
            // should actually get compiled into the class file.
            if (era != 0 && era != 1) {
                throw new IllegalArgumentException("Illegal era " + era);
            }
            if (month < Calendar.JANUARY || month > Calendar.DECEMBER) {
                throw new IllegalArgumentException("Illegal month " + month);
            }
            if (day < 1 || day > monthLength) {
                throw new IllegalArgumentException("Illegal day " + day);
            }
            if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) {
                throw new IllegalArgumentException("Illegal day of week " + dayOfWeek);
            }
            if (millis < 0 || millis >= millisPerDay) {
                throw new IllegalArgumentException("Illegal millis " + millis);
            }
            if (monthLength < 28 || monthLength > 31) {
                throw new IllegalArgumentException("Illegal month length " + monthLength);
            }
        }

        int result = rawOffset;

        // Bail out if we are before the onset of daylight savings time
        if (!useDaylight || year < startYear || era != 1) return result;

        // Check for southern hemisphere.  We assume that the start and end
        // month are different.
        boolean southern = (startMonth > endMonth);

        // Compare the date to the starting and ending rules.+1 = date>rule, -1
        // = date<rule, 0 = date==rule.
        int startCompare = compareToRule(month, monthLength, day, dayOfWeek, millis,
                                         startMode, startMonth, startDayOfWeek,
                                         startDay, startTime);
        int endCompare = 0;

        // We don't always have to compute endCompare.  For many instances,
        // startCompare is enough to determine if we are in DST or not.  In the
        // northern hemisphere, if we are before the start rule, we can't have
        // DST.  In the southern hemisphere, if we are after the start rule, we
        // must have DST.  This is reflected in the way the next if statement
        // (not the one immediately following) short circuits.
        if (southern != (startCompare >= 0)) {
            // For the ending rule comparison, we add the dstSavings to the millis
            // passed in to convert them from standard to wall time.  We then must
            // normalize the millis to the range 0..millisPerDay-1.
            millis += dstSavings; // Assume dstSavings > 0
            while (millis >= millisPerDay) {
                millis -= millisPerDay;
                ++day;
                dayOfWeek = 1 + (dayOfWeek % 7); // Assume dayOfWeek is one-based
                if (day > monthLength) {
                    day = 1;
                    // When incrementing the month, it is desirable to overflow
                    // from DECEMBER to DECEMBER+1, since we use the result to
                    // compare against a real month. Wraparound of the value
                    // leads to bug 4173604.
                    ++month;
                }
            }
            endCompare = compareToRule(month, monthLength, day, dayOfWeek, millis,
                                       endMode, endMonth, endDayOfWeek,
                                       endDay, endTime);
        }

        // Check for both the northern and southern hemisphere cases.  We
        // assume that in the northern hemisphere, the start rule is before the
        // end rule within the calendar year, and vice versa for the southern
        // hemisphere.
        if ((!southern && (startCompare >= 0 && endCompare < 0)) ||
             (southern && (startCompare >= 0 || endCompare < 0))) {

            result += dstSavings;
        }

        return result;
    
public intgetRawOffset()
Gets the GMT offset for this time zone.

        // The given date will be taken into account while
        // we have the historical time zone data in place.
        return rawOffset;
    
public booleanuseDaylightTime()
Queries if this time zone uses Daylight Savings Time.

        return useDaylight;