📄 simpletimezone.java
字号:
this.endMonth = month; // FIXME: XXX: JDK 1.2 allows negative values and has 2 new variations // of this method. this.endDay = Math.abs(day); this.endDayOfWeek = Math.abs(dayOfWeek); this.endTime = time; useDaylight = true; } /** * 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: * <code>offset = cal.get(Calendar.ZONE_OFFSET) * + cal.get(Calendar.DST_OFFSET);</code> * * You could also use in * * This version doesn't suffer this inaccuracy. * * @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 be matching the * other fields. * @param millis the millis in the day (in local standard time) * @return the time zone offset in milliseconds. */ public int getOffset(int era, int year, int month, int day, int dayOfWeek, int millis) { // This method is called by Calendar, so we mustn't use that class. int daylightSavings = 0; if (useDaylight && era == GregorianCalendar.AD && year >= startYear) { // 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, startTime); boolean beforeEnd = isBefore(year, month, day, dayOfWeek, millis, endMode, endMonth, endDay, endDayOfWeek, endTime); if (startMonth < endMonth) { // use daylight savings, if the date is after the start of // savings, and before the end of savings. daylightSavings = afterStart && beforeEnd ? dstSavings : 0; } else { // use daylight savings, if the date is before the end of // savings, or after the start of savings. daylightSavings = beforeEnd || afterStart ? dstSavings : 0; } } return rawOffset + daylightSavings; } /** * Returns the time zone offset to GMT in milliseconds, ignoring * day light savings. * @return the time zone offset. */ public int getRawOffset() { return rawOffset; } /** * Sets the standard time zone offset to GMT. * @param rawOffset The time offset from GMT in milliseconds. */ public void setRawOffset(int rawOffset) { this.rawOffset = rawOffset; } /** * Gets 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 our. * @return the daylight savings offset in milliseconds. * @since JDK1.1.4? */ public int getDSTSavings() { return dstSavings; } /** * Returns if this time zone uses daylight savings time. * @return true, if we use daylight savings time, false otherwise. */ public boolean useDaylightTime() { return useDaylight; } /** * Returns the number of days in the given month. It does always * use the Gregorian leap year rule. * @param month The month, zero based; use one of the Calendar constants. * @param year The year. */ private int getDaysInMonth(int month, int year) { // Most of this is copied from GregorianCalendar.getActualMaximum() if (month == Calendar.FEBRUARY) { return ((year & 3) == 0 && (year % 100 != 0 || year % 400 == 0)) ? 29 : 28; } else if (month < Calendar.AUGUST) return 31 - (month & 1); else return 30 + (month & 1); } /** * Checks if the date given in calXXXX, is before the change between * dst and standard time. * @param calYear the year of the date to check (for leap day cheking). * @param calMonth the month of the date to check. * @param calDay the day of month of the date to check. * @param calDayOfWeek the day of week of the date to check. * @param calMillis the millis of day of the date to check (standard time). * @param mode the change mode; same semantic as startMode. * @param month the change month; same semantic as startMonth. * @param day the change day; same semantic as startDay. * @param dayOfWeek the change day of week; * @param millis the change time in millis since midnight standard time. * same semantic as startDayOfWeek. * @return true, if cal is before the change, false if cal is on * or after the change. */ private boolean isBefore(int calYear, int calMonth, int calDayOfMonth, int calDayOfWeek, int calMillis, int mode, int month, int day, int dayOfWeek, int millis) { // This method is called by Calendar, so we mustn't use that class. // We have to do all calculations by hand. // check the months: // XXX - this is not correct: // for the DOW_GE_DOM and DOW_LE_DOM modes the change date may // be in a different month. if (calMonth != month) return calMonth < month; // check the day: switch (mode) { case DOM_MODE: if (calDayOfMonth != day) return calDayOfMonth < day; break; case DOW_IN_MONTH_MODE: { // This computes the day of month of the day of type // "dayOfWeek" that lies in the same (sunday based) week as cal. calDayOfMonth += (dayOfWeek - calDayOfWeek); // Now we convert it to 7 based number (to get a one based offset // after dividing by 7). If we count from the end of the // month, we get want a -7 based number counting the days from // the end: if (day < 0) calDayOfMonth -= getDaysInMonth(calMonth, calYear) + 7; else calDayOfMonth += 6; // day > 0 day < 0 // S M T W T F S S M T W T F S // 7 8 9 10 11 12 -36-35-34-33-32-31 // 13 14 15 16 17 18 19 -30-29-28-27-26-25-24 // 20 21 22 23 24 25 26 -23-22-21-20-19-18-17 // 27 28 29 30 31 32 33 -16-15-14-13-12-11-10 // 34 35 36 -9 -8 -7 // Now we calculate the day of week in month: int week = calDayOfMonth / 7; // day > 0 day < 0 // S M T W T F S S M T W T F S // 1 1 1 1 1 1 -5 -5 -4 -4 -4 -4 // 1 2 2 2 2 2 2 -4 -4 -4 -3 -3 -3 -3 // 2 3 3 3 3 3 3 -3 -3 -3 -2 -2 -2 -2 // 3 4 4 4 4 4 4 -2 -2 -2 -1 -1 -1 -1 // 4 5 5 -1 -1 -1 if (week != day) return week < day; if (calDayOfWeek != dayOfWeek) return calDayOfWeek < dayOfWeek; // daylight savings starts/ends on the given day. break; } case DOW_LE_DOM_MODE: // The greatest sunday before or equal December, 12 // is the same as smallest sunday after or equal December, 6. day -= 6; case DOW_GE_DOM_MODE: // Calculate the day of month of the day of type // "dayOfWeek" that lies before (or on) the given date. calDayOfMonth -= (calDayOfWeek < dayOfWeek ? 7 : 0) + calDayOfWeek - dayOfWeek; if (calDayOfMonth < day) return true; if (calDayOfWeek != dayOfWeek || calDayOfMonth >= day + 7) return false; // now we have the same day break; } // the millis decides: return (calMillis < millis); } /** * Determines if the given date is in daylight savings time. * @return true, if it is in daylight savings time, false otherwise. */ public boolean inDaylightTime(Date date) { Calendar cal = Calendar.getInstance(this); cal.setTime(date); return (cal.get(Calendar.DST_OFFSET) != 0); } /** * Generates the hashCode for the SimpleDateFormat object. It is * the rawOffset, possibly, if useDaylightSavings is true, xored * with startYear, startMonth, startDayOfWeekInMonth, ..., endTime. */ public synchronized int hashCode() { return rawOffset ^ (useDaylight ? startMonth ^ startDay ^ startDayOfWeek ^ startTime ^ endMonth ^ endDay ^ endDayOfWeek ^ endTime : 0); } public synchronized boolean equals(Object o) { if (this == o) return true; if (!(o instanceof SimpleTimeZone)) return false; SimpleTimeZone zone = (SimpleTimeZone) o; if (zone.hashCode() != hashCode() || !getID().equals(zone.getID()) || rawOffset != zone.rawOffset || useDaylight != zone.useDaylight) return false; if (!useDaylight) return true; return (startYear == zone.startYear && startMonth == zone.startMonth && startDay == zone.startDay && startDayOfWeek == zone.startDayOfWeek && startTime == zone.startTime && endMonth == zone.endMonth && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek && endTime == zone.endTime); } /** * Test if the other time zone uses the same rule and only * possibly differs in ID. This implementation for this particular * class will return true if the other object is a SimpleTimeZone, * the raw offsets and useDaylight are identical and if useDaylight * is true, also the start and end datas are identical. * @return true if this zone uses the same rule. */ public boolean hasSameRules(TimeZone other) { if (this == other) return true; if (!(other instanceof SimpleTimeZone)) return false; SimpleTimeZone zone = (SimpleTimeZone) other; if (zone.hashCode() != hashCode() || rawOffset != zone.rawOffset || useDaylight != zone.useDaylight) return false; if (!useDaylight) return true; return (startYear == zone.startYear && startMonth == zone.startMonth && startDay == zone.startDay && startDayOfWeek == zone.startDayOfWeek && startTime == zone.startTime && endMonth == zone.endMonth && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek && endTime == zone.endTime); } /** * Returns a string representation of this SimpleTimeZone object. * @return a string representation of this SimpleTimeZone object. */ public String toString() { // the test for useDaylight is an incompatibility to jdk1.2, but // I think this shouldn't hurt. return getClass().getName() + "[" + "id=" + getID() + ",offset=" + rawOffset + ",dstSavings=" + dstSavings + ",useDaylight=" + useDaylight + (useDaylight ? ",startYear=" + startYear + ",startMode=" + startMode + ",startMonth=" + startMonth + ",startDay=" + startDay + ",startDayOfWeek=" + startDayOfWeek + ",startTime=" + startTime + ",endMode=" + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay + ",endDayOfWeek=" + endDayOfWeek + ",endTime=" + endTime : "") + "]"; } /** * Reads a serialized simple time zone from stream. * @see #writeObject */ private void readObject(java.io.ObjectInputStream input) throws java.io.IOException, ClassNotFoundException { input.defaultReadObject(); if (serialVersionOnStream == 0) { // initialize the new fields to default values. dstSavings = 60 * 60 * 1000; endMode = DOW_IN_MONTH_MODE; startMode = DOW_IN_MONTH_MODE; serialVersionOnStream = 1; } else { int length = input.readInt(); byte[] byteArray = new byte[length]; input.read(byteArray, 0, length); if (length >= 4) { // Lets hope that Sun does extensions to the serialized // form in a sane manner. startDay = byteArray[0]; startDayOfWeek = byteArray[1]; endDay = byteArray[2]; endDayOfWeek = byteArray[3]; } } } /** * Serializes this object to a stream. @serialdata The object is * first written in the old JDK 1.1 format, so that it can be read * by by the old classes. This means, that the * <code>start/endDay(OfWeek)</code>-Fields are written in the * DOW_IN_MONTH_MODE rule, since this was the only supported rule * in 1.1. * * In the optional section, we write first the length of an byte * array as int and afterwards the byte array itself. The byte * array contains in this release four elements, namely the real * startDay, startDayOfWeek endDay, endDayOfWeek in that Order. * These fields are needed, because for compatibility reasons only * approximative values are written to the required section, as * described above. */ private void writeObject(java.io.ObjectOutputStream output) throws java.io.IOException { byte[] byteArray = new byte[] { (byte) startDay, (byte) startDayOfWeek, (byte) endDay, (byte) endDayOfWeek}; /* calculate the approximation for JDK 1.1 */ switch (startMode) { case DOM_MODE: startDayOfWeek = Calendar.SUNDAY; // random day of week // fall through case DOW_GE_DOM_MODE: case DOW_LE_DOM_MODE: startDay = (startDay + 6) / 7; } switch (endMode) { case DOM_MODE: endDayOfWeek = Calendar.SUNDAY; // fall through case DOW_GE_DOM_MODE: case DOW_LE_DOM_MODE: endDay = (endDay + 6) / 7; } // the required part: output.defaultWriteObject(); // the optional part: output.writeInt(byteArray.length); output.write(byteArray, 0, byteArray.length); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -