simpletimezone.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 842 行 · 第 1/2 页

JAVA
842
字号
    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 + =
减小字号Ctrl + -
显示快捷键?