Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)
Frames | No Frames

Source for java.util.SimpleTimeZone

 1:  /* java.util.SimpleTimeZone
 2:  Copyright (C) 1998, 1999, 2000, 2003, 2004, 2005, 2007
 3:  Free Software Foundation, Inc.
 4: 
 5: This file is part of GNU Classpath.
 6: 
 7: GNU Classpath is free software; you can redistribute it and/or modify
 8: it under the terms of the GNU General Public License as published by
 9: the Free Software Foundation; either version 2, or (at your option)
 10: any later version.
 11: 
 12: GNU Classpath is distributed in the hope that it will be useful, but
 13: WITHOUT ANY WARRANTY; without even the implied warranty of
 14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 15: General Public License for more details.
 16: 
 17: You should have received a copy of the GNU General Public License
 18: along with GNU Classpath; see the file COPYING. If not, write to the
 19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 20: 02110-1301 USA.
 21: 
 22: Linking this library statically or dynamically with other modules is
 23: making a combined work based on this library. Thus, the terms and
 24: conditions of the GNU General Public License cover the whole
 25: combination.
 26: 
 27: As a special exception, the copyright holders of this library give you
 28: permission to link this library with independent modules to produce an
 29: executable, regardless of the license terms of these independent
 30: modules, and to copy and distribute the resulting executable under
 31: terms of your choice, provided that you also meet, for each linked
 32: independent module, the terms and conditions of the license of that
 33: module. An independent module is a module which is not derived from
 34: or based on this library. If you modify this library, you may extend
 35: this exception to your version of the library, but you are not
 36: obligated to do so. If you do not wish to do so, delete this
 37: exception statement from your version. */
 38: 
 39: 
 40:  package java.util;
 41: 
 42: 
 43:  /**
 44:  * This class represents a simple time zone offset and handles
 45:  * daylight savings. It can only handle one daylight savings rule, so
 46:  * it can't represent historical changes.
 47:  *
 48:  * This object is tightly bound to the Gregorian calendar. It assumes
 49:  * a regular seven days week, and the month lengths are that of the
 50:  * Gregorian Calendar. It can only handle daylight savings for years
 51:  * lying in the AD era.
 52:  *
 53:  * @see Calendar
 54:  * @see GregorianCalendar
 55:  * @author Jochen Hoenicke
 56:  */
 57:  public class SimpleTimeZone extends TimeZone
 58: {
 59:  /**
 60:  * The raw time zone offset in milliseconds to GMT, ignoring
 61:  * daylight savings.
 62:  * @serial
 63:  */
 64:  private int rawOffset;
 65: 
 66:  /**
 67:  * True, if this timezone uses daylight savings, false otherwise.
 68:  * @serial
 69:  */
 70:  private boolean useDaylight;
 71: 
 72:  /**
 73:  * The daylight savings offset. This is a positive offset in
 74:  * milliseconds with respect to standard time. Typically this
 75:  * is one hour, but for some time zones this may be half an hour.
 76:  * @serial
 77:  * @since JDK1.1.4
 78:  */
 79:  private int dstSavings = 60 * 60 * 1000;
 80: 
 81:  /**
 82:  * The first year, in which daylight savings rules applies.
 83:  * @serial
 84:  */
 85:  private int startYear;
 86:  private static final int DOM_MODE = 1;
 87:  private static final int DOW_IN_MONTH_MODE = 2;
 88:  private static final int DOW_GE_DOM_MODE = 3;
 89:  private static final int DOW_LE_DOM_MODE = 4;
 90: 
 91:  /**
 92:  * The mode of the start rule. This takes one of the following values:
 93:  * <dl>
 94:  * <dt>DOM_MODE (1)</dt>
 95:  * <dd> startDay contains the day in month of the start date,
 96:  * startDayOfWeek is unused. </dd>
 97:  * <dt>DOW_IN_MONTH_MODE (2)</dt>
 98:  * <dd> The startDay gives the day of week in month, and
 99:  * startDayOfWeek the day of week. For example startDay=2 and
 100:  * startDayOfWeek=Calender.SUNDAY specifies that the change is on
 101:  * the second sunday in that month. You must make sure, that this
 102:  * day always exists (ie. don't specify the 5th sunday).
 103:  * </dd>
 104:  * <dt>DOW_GE_DOM_MODE (3)</dt>
 105:  * <dd> The start is on the first startDayOfWeek on or after
 106:  * startDay. For example startDay=13 and
 107:  * startDayOfWeek=Calendar.FRIDAY specifies that the daylight
 108:  * savings start on the first FRIDAY on or after the 13th of that
 109:  * Month. Make sure that the change is always in the given month, or
 110:  * the result is undefined.
 111:  * </dd>
 112:  * <dt>DOW_LE_DOM_MONTH (4)</dt>
 113:  * <dd> The start is on the first startDayOfWeek on or before the
 114:  * startDay. Make sure that the change is always in the given
 115:  * month, or the result is undefined.
 116:  </dd>
 117:  * </dl>
 118:  * @serial */
 119:  private int startMode;
 120: 
 121:  /**
 122:  * The month in which daylight savings start. This is one of the
 123:  * constants Calendar.JANUARY, ..., Calendar.DECEMBER.
 124:  * @serial
 125:  */
 126:  private int startMonth;
 127: 
 128:  /**
 129:  * This variable can have different meanings. See startMode for details
 130:  * @see #startMode
 131:  * @serial
 132:  */
 133:  private int startDay;
 134: 
 135:  /**
 136:  * This variable specifies the day of week the change takes place. If
 137:  * startMode == DOM_MODE, this is undefined.
 138:  * @serial
 139:  * @see #startMode
 140:  */
 141:  private int startDayOfWeek;
 142: 
 143:  /**
 144:  * This variable specifies the time of change to daylight savings.
 145:  * This time is given in milliseconds after midnight in startTimeMode
 146:  * chosen time mode.
 147:  * @serial
 148:  */
 149:  private int startTime;
 150: 
 151:  /**
 152:  * This variable specifies the mode that startTime is specified in. By
 153:  * default it is WALL_TIME, but can also be STANDARD_TIME or UTC_TIME. For
 154:  * startTime, STANDARD_TIME and WALL_TIME are equivalent.
 155:  * @serial
 156:  */
 157:  private int startTimeMode = WALL_TIME;
 158: 
 159:  /**
 160:  * The month in which daylight savings ends. This is one of the
 161:  * constants Calendar.JANUARY, ..., Calendar.DECEMBER.
 162:  * @serial
 163:  */
 164:  private int endMonth;
 165: 
 166:  /**
 167:  * This variable gives the mode for the end of daylight savings rule.
 168:  * It can take the same values as startMode.
 169:  * @serial
 170:  * @see #startMode
 171:  */
 172:  private int endMode;
 173: 
 174:  /**
 175:  * This variable can have different meanings. See startMode for details
 176:  * @serial
 177:  * @see #startMode
 178:  */
 179:  private int endDay;
 180: 
 181:  /**
 182:  * This variable specifies the day of week the change takes place. If
 183:  * endMode == DOM_MODE, this is undefined.
 184:  * @serial
 185:  * @see #startMode
 186:  */
 187:  private int endDayOfWeek;
 188: 
 189:  /**
 190:  * This variable specifies the time of change back to standard time.
 191:  * This time is given in milliseconds after midnight in endTimeMode
 192:  * chosen time mode.
 193:  * @serial
 194:  */
 195:  private int endTime;
 196: 
 197:  /**
 198:  * This variable specifies the mode that endTime is specified in. By
 199:  * default it is WALL_TIME, but can also be STANDARD_TIME or UTC_TIME.
 200:  * @serial
 201:  */
 202:  private int endTimeMode = WALL_TIME;
 203: 
 204:  /**
 205:  * This variable points to a deprecated array from JDK 1.1. It is
 206:  * ignored in JDK 1.2 but streamed out for compatibility with JDK 1.1.
 207:  * The array contains the lengths of the months in the year and is
 208:  * assigned from a private static final field to avoid allocating
 209:  * the array for every instance of the object.
 210:  * Note that static final fields are not serialized.
 211:  * @serial
 212:  */
 213:  private byte[] monthLength = monthArr;
 214:  private static final byte[] monthArr = 
 215:  {
 216:  31, 28, 31, 30, 31, 30, 31, 31, 30,
 217:  31, 30, 31
 218:  };
 219: 
 220:  /**
 221:  * The version of the serialized data on the stream.
 222:  * <dl>
 223:  * <dt>0 or not present on stream</dt>
 224:  * <dd> JDK 1.1.3 or earlier, only provides this fields:
 225:  * rawOffset, startDay, startDayOfWeek, startMonth, startTime,
 226:  * startYear, endDay, endDayOfWeek, endMonth, endTime
 227:  * </dd>
 228:  * <dd> JDK 1.1.4 or later. This includes three new fields, namely
 229:  * startMode, endMode and dstSavings. And there is a optional section
 230:  * as described in writeObject.
 231:  * </dd>
 232:  * </dl>
 233:  *
 234:  * XXX - JDK 1.2 Beta 4 docu states 1.1.4, but my 1.1.5 has the old
 235:  * version.
 236:  *
 237:  * When streaming out this class it is always written in the latest
 238:  * version.
 239:  * @serial
 240:  * @since JDK1.1.4
 241:  */
 242:  private int serialVersionOnStream = 2;
 243:  private static final long serialVersionUID = -403250971215465050L;
 244: 
 245:  /**
 246:  * Constant to indicate that start and end times are specified in standard
 247:  * time, without adjusting for daylight savings.
 248:  */
 249:  public static final int STANDARD_TIME = 1;
 250: 
 251:  /**
 252:  * Constant to indicate that start and end times are specified in wall
 253:  * time, adjusting for daylight savings. This is the default.
 254:  */
 255:  public static final int WALL_TIME = 0;
 256: 
 257:  /**
 258:  * Constant to indicate that start and end times are specified in UTC.
 259:  */
 260:  public static final int UTC_TIME = 2;
 261: 
 262:  /**
 263:  * Create a <code>SimpleTimeZone</code> with the given time offset
 264:  * from GMT and without daylight savings.
 265:  * @param rawOffset the time offset from GMT in milliseconds.
 266:  * @param id The identifier of this time zone.
 267:  */
 268:  public SimpleTimeZone(int rawOffset, String id)
 269:  {
 270:  this.rawOffset = rawOffset;
 271:  setID(id);
 272:  useDaylight = false;
 273:  startYear = 0;
 274:  }
 275: 
 276:  /**
 277:  * Create a <code>SimpleTimeZone</code> with the given time offset
 278:  * from GMT and with daylight savings. The start/end parameters
 279:  * can have different meaning (replace WEEKDAY with a real day of
 280:  * week). Only the first two meanings were supported by earlier
 281:  * versions of jdk.
 282:  *
 283:  * <dl>
 284:  * <dt><code>day &gt; 0, dayOfWeek = Calendar.WEEKDAY</code></dt>
 285:  * <dd>The start/end of daylight savings is on the <code>day</code>-th
 286:  * <code>WEEKDAY</code> in the given month. </dd>
 287:  * <dt><code>day &lt; 0, dayOfWeek = Calendar.WEEKDAY</code></dt>
 288:  * <dd>The start/end of daylight savings is on the <code>-day</code>-th
 289:  * <code>WEEKDAY</code> counted from the <i>end</i> of the month. </dd>
 290:  * <dt><code>day &gt; 0, dayOfWeek = 0</code></dt>
 291:  * <dd>The start/end of daylight is on the <code>day</code>-th day of
 292:  * the month. </dd>
 293:  * <dt><code>day &gt; 0, dayOfWeek = -Calendar.WEEKDAY</code></dt>
 294:  * <dd>The start/end of daylight is on the first WEEKDAY on or after
 295:  * the <code>day</code>-th day of the month. You must make sure that
 296:  * this day lies in the same month. </dd>
 297:  * <dt><code>day &lt; 0, dayOfWeek = -Calendar.WEEKDAY</code></dt>
 298:  * <dd>The start/end of daylight is on the first WEEKDAY on or
 299:  * <i>before</i> the <code>-day</code>-th day of the month. You
 300:  * must make sure that this day lies in the same month. </dd>
 301:  * </dl>
 302:  *
 303:  * If you give a non existing month, a day that is zero, or too big,
 304:  * or a dayOfWeek that is too big, the result is undefined.
 305:  *
 306:  * The start rule must have a different month than the end rule.
 307:  * This restriction shouldn't hurt for all possible time zones.
 308:  *
 309:  * @param rawOffset The time offset from GMT in milliseconds.
 310:  * @param id The identifier of this time zone.
 311:  * @param startMonth The start month of daylight savings; use the
 312:  * constants in Calendar.
 313:  * @param startDayOfWeekInMonth A day in month or a day of week number, as
 314:  * described above.
 315:  * @param startDayOfWeek The start rule day of week; see above.
 316:  * @param startTime A time in millis in standard time.
 317:  * @param endMonth The end month of daylight savings; use the
 318:  * constants in Calendar.
 319:  * @param endDayOfWeekInMonth A day in month or a day of week number, as
 320:  * described above.
 321:  * @param endDayOfWeek The end rule day of week; see above.
 322:  * @param endTime A time in millis in standard time.
 323:  * @throws IllegalArgumentException if parameters are invalid or out of
 324:  * range.
 325:  */
 326:  public SimpleTimeZone(int rawOffset, String id, int startMonth,
 327:  int startDayOfWeekInMonth, int startDayOfWeek,
 328:  int startTime, int endMonth, int endDayOfWeekInMonth,
 329:  int endDayOfWeek, int endTime)
 330:  {
 331:  this.rawOffset = rawOffset;
 332:  setID(id);
 333:  useDaylight = true;
 334: 
 335:  setStartRule(startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime);
 336:  setEndRule(endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
 337:  if (startMonth == endMonth)
 338:  throw new IllegalArgumentException("startMonth and endMonth must be different");
 339:  this.startYear = 0;
 340:  }
 341: 
 342:  /**
 343:  * This constructs a new SimpleTimeZone that supports a daylight savings
 344:  * rule. The parameter are the same as for the constructor above, except
 345:  * there is the additional dstSavaings parameter.
 346:  *
 347:  * @param dstSavings the amount of savings for daylight savings
 348:  * time in milliseconds. This must be positive.
 349:  * @since 1.2
 350:  */
 351:  public SimpleTimeZone(int rawOffset, String id, int startMonth,
 352:  int startDayOfWeekInMonth, int startDayOfWeek,
 353:  int startTime, int endMonth, int endDayOfWeekInMonth,
 354:  int endDayOfWeek, int endTime, int dstSavings)
 355:  {
 356:  this(rawOffset, id, startMonth, startDayOfWeekInMonth, startDayOfWeek,
 357:  startTime, endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
 358: 
 359:  this.dstSavings = dstSavings;
 360:  }
 361: 
 362:  /**
 363:  * This constructs a new SimpleTimeZone that supports a daylight savings
 364:  * rule. The parameter are the same as for the constructor above, except
 365:  * there are the additional startTimeMode, endTimeMode, and dstSavings
 366:  * parameters.
 367:  *
 368:  * @param startTimeMode the mode that start times are specified in. One of
 369:  * WALL_TIME, STANDARD_TIME, or UTC_TIME.
 370:  * @param endTimeMode the mode that end times are specified in. One of
 371:  * WALL_TIME, STANDARD_TIME, or UTC_TIME.
 372:  * @param dstSavings the amount of savings for daylight savings
 373:  * time in milliseconds. This must be positive.
 374:  * @throws IllegalArgumentException if parameters are invalid or out of
 375:  * range.
 376:  * @since 1.4
 377:  */
 378:  public SimpleTimeZone(int rawOffset, String id, int startMonth,
 379:  int startDayOfWeekInMonth, int startDayOfWeek,
 380:  int startTime, int startTimeMode, int endMonth,
 381:  int endDayOfWeekInMonth, int endDayOfWeek,
 382:  int endTime, int endTimeMode, int dstSavings)
 383:  {
 384:  this(rawOffset, id, startMonth, startDayOfWeekInMonth, startDayOfWeek,
 385:  startTime, endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime);
 386: 
 387:  if (startTimeMode < WALL_TIME || startTimeMode > UTC_TIME)
 388:  throw new IllegalArgumentException("startTimeMode must be one of WALL_TIME, STANDARD_TIME, or UTC_TIME");
 389:  if (endTimeMode < WALL_TIME || endTimeMode > UTC_TIME)
 390:  throw new IllegalArgumentException("endTimeMode must be one of WALL_TIME, STANDARD_TIME, or UTC_TIME");
 391: 
 392:  this.dstSavings = dstSavings;
 393:  this.startTimeMode = startTimeMode;
 394:  this.endTimeMode = endTimeMode;
 395:  }
 396: 
 397:  /**
 398:  * Sets the first year, where daylight savings applies. The daylight
 399:  * savings rule never apply for years in the BC era. Note that this
 400:  * is gregorian calendar specific.
 401:  * @param year the start year.
 402:  */
 403:  public void setStartYear(int year)
 404:  {
 405:  startYear = year;
 406:  useDaylight = true;
 407:  }
 408: 
 409:  /**
 410:  * Checks if the month, day, dayOfWeek arguments are in range and
 411:  * returns the mode of the rule.
 412:  * @param month the month parameter as in the constructor
 413:  * @param day the day parameter as in the constructor
 414:  * @param dayOfWeek the day of week parameter as in the constructor
 415:  * @return the mode of this rule see startMode.
 416:  * @exception IllegalArgumentException if parameters are out of range.
 417:  * @see #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int)
 418:  * @see #startMode
 419:  */
 420:  private int checkRule(int month, int day, int dayOfWeek)
 421:  {
 422:  if (month < 0 || month > 11)
 423:  throw new IllegalArgumentException("month out of range");
 424: 
 425:  int daysInMonth = getDaysInMonth(month, 1);
 426:  if (dayOfWeek == 0)
 427:  {
 428:  if (day <= 0 || day > daysInMonth)
 429:  throw new IllegalArgumentException("day out of range");
 430:  return DOM_MODE;
 431:  }
 432:  else if (dayOfWeek > 0)
 433:  {
 434:  if (Math.abs(day) > (daysInMonth + 6) / 7)
 435:  throw new IllegalArgumentException("dayOfWeekInMonth out of range");
 436:  if (dayOfWeek > Calendar.SATURDAY)
 437:  throw new IllegalArgumentException("dayOfWeek out of range");
 438:  return DOW_IN_MONTH_MODE;
 439:  }
 440:  else
 441:  {
 442:  if (day == 0 || Math.abs(day) > daysInMonth)
 443:  throw new IllegalArgumentException("day out of range");
 444:  if (dayOfWeek < -Calendar.SATURDAY)
 445:  throw new IllegalArgumentException("dayOfWeek out of range");
 446:  if (day < 0)
 447:  return DOW_LE_DOM_MODE;
 448:  else
 449:  return DOW_GE_DOM_MODE;
 450:  }
 451:  }
 452: 
 453:  /**
 454:  * Sets the daylight savings start rule. You must also set the
 455:  * end rule with <code>setEndRule</code> or the result of
 456:  * getOffset is undefined. For the parameters see the ten-argument
 457:  * constructor above.
 458:  *
 459:  * @param month The month where daylight savings start, zero
 460:  * based. You should use the constants in Calendar.
 461:  * @param day A day of month or day of week in month.
 462:  * @param dayOfWeek The day of week where daylight savings start.
 463:  * @param time The time in milliseconds standard time where daylight
 464:  * savings start.
 465:  * @exception IllegalArgumentException if parameters are out of range.
 466:  * @see SimpleTimeZone
 467:  */
 468:  public void setStartRule(int month, int day, int dayOfWeek, int time)
 469:  {
 470:  this.startMode = checkRule(month, day, dayOfWeek);
 471:  this.startMonth = month;
 472:  this.startDay = day;
 473:  this.startDayOfWeek = Math.abs(dayOfWeek);
 474:  this.startTime = time;
 475:  this.startTimeMode = WALL_TIME;
 476:  }
 477: 
 478:  /**
 479:  * Sets the daylight savings start rule. You must also set the
 480:  * end rule with <code>setEndRule</code> or the result of
 481:  * getOffset is undefined. For the parameters see the ten-argument
 482:  * constructor above.
 483:  *
 484:  * Note that this API isn't incredibly well specified. It appears that the
 485:  * after flag must override the parameters, since normally, the day and
 486:  * dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or
 487:  * before mode is chosen. But if after == true, this implementation
 488:  * overrides the signs of the other arguments. And if dayOfWeek == 0, it
 489:  * falls back to the behavior in the other APIs. I guess this should be
 490:  * checked against Sun's implementation.
 491:  *
 492:  * @param month The month where daylight savings start, zero
 493:  * based. You should use the constants in Calendar.
 494:  * @param day A day of month or day of week in month.
 495:  * @param dayOfWeek The day of week where daylight savings start.
 496:  * @param time The time in milliseconds standard time where daylight
 497:  * savings start.
 498:  * @param after If true, day and dayOfWeek specify first day of week on or
 499:  * after day, else first day of week on or before.
 500:  * @since 1.2
 501:  * @see SimpleTimeZone
 502:  */
 503:  public void setStartRule(int month, int day, int dayOfWeek, int time,
 504:  boolean after)
 505:  {
 506:  if (after)
 507:  setStartRule(month, day, -dayOfWeek, time);
 508:  else
 509:  setStartRule(month, -day, -dayOfWeek, time);
 510:  }
 511: 
 512:  /**
 513:  * Sets the daylight savings start rule. You must also set the
 514:  * end rule with <code>setEndRule</code> or the result of
 515:  * getOffset is undefined. For the parameters see the ten-argument
 516:  * constructor above.
 517:  *
 518:  * @param month The month where daylight savings start, zero
 519:  * based. You should use the constants in Calendar.
 520:  * @param day A day of month or day of week in month.
 521:  * @param time The time in milliseconds standard time where daylight
 522:  * savings start.
 523:  * @see SimpleTimeZone
 524:  * @since 1.2
 525:  */
 526:  public void setStartRule(int month, int day, int time)
 527:  {
 528:  setStartRule(month, day, 0, time);
 529:  }
 530: 
 531:  /**
 532:  * Sets the daylight savings end rule. You must also set the
 533:  * start rule with <code>setStartRule</code> or the result of
 534:  * getOffset is undefined. For the parameters see the ten-argument
 535:  * constructor above.
 536:  *
 537:  * @param month The end month of daylight savings.
 538:  * @param day A day in month, or a day of week in month.
 539:  * @param dayOfWeek A day of week, when daylight savings ends.
 540:  * @param time A time in millis in standard time.
 541:  * @see #setStartRule(int, int, int, int)
 542:  */
 543:  public void setEndRule(int month, int day, int dayOfWeek, int time)
 544:  {
 545:  this.endMode = checkRule(month, day, dayOfWeek);
 546:  this.endMonth = month;
 547:  this.endDay = day;
 548:  this.endDayOfWeek = Math.abs(dayOfWeek);
 549:  this.endTime = time;
 550:  this.endTimeMode = WALL_TIME;
 551:  useDaylight = true;
 552:  }
 553: 
 554:  /**
 555:  * Sets the daylight savings end rule. You must also set the
 556:  * start rule with <code>setStartRule</code> or the result of
 557:  * getOffset is undefined. For the parameters see the ten-argument
 558:  * constructor above.
 559:  *
 560:  * Note that this API isn't incredibly well specified. It appears that the
 561:  * after flag must override the parameters, since normally, the day and
 562:  * dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or
 563:  * before mode is chosen. But if after == true, this implementation
 564:  * overrides the signs of the other arguments. And if dayOfWeek == 0, it
 565:  * falls back to the behavior in the other APIs. I guess this should be
 566:  * checked against Sun's implementation.
 567:  *
 568:  * @param month The end month of daylight savings.
 569:  * @param day A day in month, or a day of week in month.
 570:  * @param dayOfWeek A day of week, when daylight savings ends.
 571:  * @param time A time in millis in standard time.
 572:  * @param after If true, day and dayOfWeek specify first day of week on or
 573:  * after day, else first day of week on or before.
 574:  * @since 1.2
 575:  * @see #setStartRule(int, int, int, int, boolean)
 576:  */
 577:  public void setEndRule(int month, int day, int dayOfWeek, int time,
 578:  boolean after)
 579:  {
 580:  if (after)
 581:  setEndRule(month, day, -dayOfWeek, time);
 582:  else
 583:  setEndRule(month, -day, -dayOfWeek, time);
 584:  }
 585: 
 586:  /**
 587:  * Sets the daylight savings end rule. You must also set the
 588:  * start rule with <code>setStartRule</code> or the result of
 589:  * getOffset is undefined. For the parameters see the ten-argument
 590:  * constructor above.
 591:  *
 592:  * @param month The end month of daylight savings.
 593:  * @param day A day in month, or a day of week in month.
 594:  * @param time A time in millis in standard time.
 595:  * @see #setStartRule(int, int, int)
 596:  */
 597:  public void setEndRule(int month, int day, int time)
 598:  {
 599:  setEndRule(month, day, 0, time);
 600:  }
 601: 
 602:  /**
 603:  * Gets the time zone offset, for current date, modified in case of
 604:  * daylight savings. This is the offset to add to UTC to get the local
 605:  * time.
 606:  *
 607:  * In the standard JDK the results given by this method may result in
 608:  * inaccurate results at the end of February or the beginning of March.
 609:  * To avoid this, you should use Calendar instead:
 610:  * <code>offset = cal.get(Calendar.ZONE_OFFSET)
 611:  * + cal.get(Calendar.DST_OFFSET);</code>
 612:  *
 613:  * This version doesn't suffer this inaccuracy.
 614:  *
 615:  * The arguments don't follow the approach for setting start and end rules.
 616:  * The day must be a positive number and dayOfWeek must be a positive value
 617:  * from Calendar. dayOfWeek is redundant, but must match the other values
 618:  * or an inaccurate result may be returned.
 619:  *
 620:  * @param era the era of the given date
 621:  * @param year the year of the given date
 622:  * @param month the month of the given date, 0 for January.
 623:  * @param day the day of month
 624:  * @param dayOfWeek the day of week; this must match the other fields.
 625:  * @param millis the millis in the day (in local standard time)
 626:  * @return the time zone offset in milliseconds.
 627:  * @throws IllegalArgumentException if arguments are incorrect.
 628:  */
 629:  public int getOffset(int era, int year, int month, int day, int dayOfWeek,
 630:  int millis)
 631:  {
 632:  int daysInMonth = getDaysInMonth(month, year);
 633:  if (day < 1 || day > daysInMonth)
 634:  throw new IllegalArgumentException("day out of range");
 635:  if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
 636:  throw new IllegalArgumentException("dayOfWeek out of range");
 637:  if (month < Calendar.JANUARY || month > Calendar.DECEMBER)
 638:  throw new IllegalArgumentException("month out of range:" + month);
 639: 
 640:  // This method is called by Calendar, so we mustn't use that class.
 641:  int daylightSavings = 0;
 642:  if (useDaylight && era == GregorianCalendar.AD && year >= startYear)
 643:  {
 644:  int orig_year = year;
 645:  int time = startTime + (startTimeMode == UTC_TIME ? rawOffset : 0);
 646:  // This does only work for Gregorian calendars :-(
 647:  // This is mainly because setStartYear doesn't take an era.
 648:  boolean afterStart = ! isBefore(year, month, day, dayOfWeek, millis,
 649:  startMode, startMonth, startDay,
 650:  startDayOfWeek, time);
 651:  millis += dstSavings;
 652:  if (millis >= 24 * 60 * 60 * 1000)
 653:  {
 654:  millis -= 24 * 60 * 60 * 1000;
 655:  dayOfWeek = (dayOfWeek % 7) + 1;
 656:  if (++day > daysInMonth)
 657:  {
 658:  day = 1;
 659:  if (month++ == Calendar.DECEMBER)
 660:  {
 661:  month = Calendar.JANUARY;
 662:  year++;
 663:  }
 664:  }
 665:  }
 666:  time = endTime + (endTimeMode == UTC_TIME ? rawOffset : 0);
 667:  if (endTimeMode != WALL_TIME)
 668:  time += dstSavings;
 669:  boolean beforeEnd = isBefore(year, month, day, dayOfWeek, millis,
 670:  endMode, endMonth, endDay, endDayOfWeek,
 671:  time);
 672: 
 673:  if (year != orig_year)
 674:  afterStart = false;
 675:  if (startMonth < endMonth)
 676:  // use daylight savings, if the date is after the start of
 677:  // savings, and before the end of savings.
 678:  daylightSavings = afterStart && beforeEnd ? dstSavings : 0;
 679:  else
 680:  // use daylight savings, if the date is before the end of
 681:  // savings, or after the start of savings.
 682:  daylightSavings = beforeEnd || afterStart ? dstSavings : 0;
 683:  }
 684:  return rawOffset + daylightSavings;
 685:  }
 686: 
 687:  /**
 688:  * Returns the time zone offset to GMT in milliseconds, ignoring
 689:  * day light savings.
 690:  * @return the time zone offset.
 691:  */
 692:  public int getRawOffset()
 693:  {
 694:  return rawOffset;
 695:  }
 696: 
 697:  /**
 698:  * Sets the standard time zone offset to GMT.
 699:  * @param rawOffset The time offset from GMT in milliseconds.
 700:  */
 701:  public void setRawOffset(int rawOffset)
 702:  {
 703:  this.rawOffset = rawOffset;
 704:  }
 705: 
 706:  /**
 707:  * Gets the daylight savings offset. This is a positive offset in
 708:  * milliseconds with respect to standard time. Typically this
 709:  * is one hour, but for some time zones this may be half an our.
 710:  * @return the daylight savings offset in milliseconds.
 711:  *
 712:  * @since 1.2
 713:  */
 714:  public int getDSTSavings()
 715:  {
 716:  return dstSavings;
 717:  }
 718: 
 719:  /**
 720:  * Sets the daylight savings offset. This is a positive offset in
 721:  * milliseconds with respect to standard time.
 722:  *
 723:  * @param dstSavings the daylight savings offset in milliseconds.
 724:  *
 725:  * @since 1.2
 726:  */
 727:  public void setDSTSavings(int dstSavings)
 728:  {
 729:  if (dstSavings <= 0)
 730:  throw new IllegalArgumentException("illegal value for dstSavings");
 731: 
 732:  this.dstSavings = dstSavings;
 733:  }
 734: 
 735:  /**
 736:  * Returns if this time zone uses daylight savings time.
 737:  * @return true, if we use daylight savings time, false otherwise.
 738:  */
 739:  public boolean useDaylightTime()
 740:  {
 741:  return useDaylight;
 742:  }
 743: 
 744:  /**
 745:  * Returns the number of days in the given month.
 746:  * Uses gregorian rules prior to 1582 (The default and earliest cutover)
 747:  * @param month The month, zero based; use one of the Calendar constants.
 748:  * @param year The year.
 749:  */
 750:  private int getDaysInMonth(int month, int year)
 751:  { 
 752:  if (month == Calendar.FEBRUARY)
 753:  {
 754:  if ((year & 3) != 0)
 755:  return 28;
 756: 
 757:  // Assume default Gregorian cutover, 
 758:  // all years prior to this must be Julian
 759:  if (year < 1582)
 760:  return 29;
 761: 
 762:  // Gregorian rules 
 763:  return ((year % 100) != 0 || (year % 400) == 0) ? 29 : 28;
 764:  }
 765:  else
 766:  return monthArr[month];
 767:  }
 768: 
 769:  /**
 770:  * Checks if the date given in calXXXX, is before the change between
 771:  * dst and standard time.
 772:  * @param calYear the year of the date to check (for leap day checking).
 773:  * @param calMonth the month of the date to check.
 774:  * @param calDayOfMonth the day of month of the date to check.
 775:  * @param calDayOfWeek the day of week of the date to check.
 776:  * @param calMillis the millis of day of the date to check (standard time).
 777:  * @param mode the change mode; same semantic as startMode.
 778:  * @param month the change month; same semantic as startMonth.
 779:  * @param day the change day; same semantic as startDay.
 780:  * @param dayOfWeek the change day of week;
 781:  * @param millis the change time in millis since midnight standard time.
 782:  * same semantic as startDayOfWeek.
 783:  * @return true, if cal is before the change, false if cal is on
 784:  * or after the change.
 785:  */
 786:  private boolean isBefore(int calYear, int calMonth, int calDayOfMonth,
 787:  int calDayOfWeek, int calMillis, int mode,
 788:  int month, int day, int dayOfWeek, int millis)
 789:  {
 790:  // This method is called by Calendar, so we mustn't use that class.
 791:  // We have to do all calculations by hand.
 792:  // check the months:
 793:  // XXX - this is not correct:
 794:  // for the DOW_GE_DOM and DOW_LE_DOM modes the change date may
 795:  // be in a different month.
 796:  if (calMonth != month)
 797:  return calMonth < month;
 798: 
 799:  // check the day:
 800:  switch (mode)
 801:  {
 802:  case DOM_MODE:
 803:  if (calDayOfMonth != day)
 804:  return calDayOfMonth < day;
 805:  break;
 806:  case DOW_IN_MONTH_MODE:
 807:  {
 808:  // This computes the day of month of the day of type
 809:  // "dayOfWeek" that lies in the same (sunday based) week as cal.
 810:  calDayOfMonth += (dayOfWeek - calDayOfWeek);
 811: 
 812:  // Now we convert it to 7 based number (to get a one based offset
 813:  // after dividing by 7). If we count from the end of the
 814:  // month, we get want a -7 based number counting the days from 
 815:  // the end:
 816:  if (day < 0)
 817:  calDayOfMonth -= getDaysInMonth(calMonth, calYear) + 7;
 818:  else
 819:  calDayOfMonth += 6;
 820: 
 821:  // day > 0 day < 0
 822:  // S M T W T F S S M T W T F S
 823:  // 7 8 9 10 11 12 -36-35-34-33-32-31
 824:  // 13 14 15 16 17 18 19 -30-29-28-27-26-25-24
 825:  // 20 21 22 23 24 25 26 -23-22-21-20-19-18-17
 826:  // 27 28 29 30 31 32 33 -16-15-14-13-12-11-10
 827:  // 34 35 36 -9 -8 -7
 828:  // Now we calculate the day of week in month:
 829:  int week = calDayOfMonth / 7;
 830: 
 831:  // day > 0 day < 0
 832:  // S M T W T F S S M T W T F S
 833:  // 1 1 1 1 1 1 -5 -5 -4 -4 -4 -4
 834:  // 1 2 2 2 2 2 2 -4 -4 -4 -3 -3 -3 -3
 835:  // 2 3 3 3 3 3 3 -3 -3 -3 -2 -2 -2 -2
 836:  // 3 4 4 4 4 4 4 -2 -2 -2 -1 -1 -1 -1
 837:  // 4 5 5 -1 -1 -1
 838:  if (week != day)
 839:  return week < day;
 840: 
 841:  if (calDayOfWeek != dayOfWeek)
 842:  return calDayOfWeek < dayOfWeek;
 843: 
 844:  // daylight savings starts/ends on the given day.
 845:  break;
 846:  }
 847:  case DOW_LE_DOM_MODE:
 848:  // The greatest sunday before or equal December, 12
 849:  // is the same as smallest sunday after or equal December, 6.
 850:  day = Math.abs(day) - 6;
 851:  case DOW_GE_DOM_MODE:
 852:  // Calculate the day of month of the day of type
 853:  // "dayOfWeek" that lies before (or on) the given date.
 854:  calDayOfMonth -= (calDayOfWeek < dayOfWeek ? 7 : 0) + calDayOfWeek
 855:  - dayOfWeek;
 856:  if (calDayOfMonth < day)
 857:  return true;
 858:  if (calDayOfWeek != dayOfWeek || calDayOfMonth >= day + 7)
 859:  return false;
 860: 
 861:  // now we have the same day
 862:  break;
 863:  }
 864: 
 865:  // the millis decides:
 866:  return (calMillis < millis);
 867:  }
 868: 
 869:  /**
 870:  * Determines if the given date is in daylight savings time.
 871:  * @return true, if it is in daylight savings time, false otherwise.
 872:  */
 873:  public boolean inDaylightTime(Date date)
 874:  {
 875:  Calendar cal = Calendar.getInstance(this);
 876:  cal.setTime(date);
 877:  return (cal.get(Calendar.DST_OFFSET) != 0);
 878:  }
 879: 
 880:  /**
 881:  * Generates the hashCode for the SimpleDateFormat object. It is
 882:  * the rawOffset, possibly, if useDaylightSavings is true, xored
 883:  * with startYear, startMonth, startDayOfWeekInMonth, ..., endTime.
 884:  */
 885:  public synchronized int hashCode()
 886:  {
 887:  return rawOffset
 888:  ^ (useDaylight
 889:  ? startMonth ^ startDay ^ startDayOfWeek ^ startTime ^ endMonth
 890:  ^ endDay ^ endDayOfWeek ^ endTime : 0);
 891:  }
 892: 
 893:  public synchronized boolean equals(Object o)
 894:  {
 895:  if (this == o)
 896:  return true;
 897:  if (! (o instanceof SimpleTimeZone))
 898:  return false;
 899:  SimpleTimeZone zone = (SimpleTimeZone) o;
 900:  if (zone.hashCode() != hashCode() || ! getID().equals(zone.getID())
 901:  || rawOffset != zone.rawOffset || useDaylight != zone.useDaylight)
 902:  return false;
 903:  if (! useDaylight)
 904:  return true;
 905:  return (startYear == zone.startYear && startMonth == zone.startMonth
 906:  && startDay == zone.startDay
 907:  && startDayOfWeek == zone.startDayOfWeek
 908:  && startTime == zone.startTime
 909:  && startTimeMode == zone.startTimeMode && endMonth == zone.endMonth
 910:  && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek
 911:  && endTime == zone.endTime && endTimeMode == zone.endTimeMode);
 912:  }
 913: 
 914:  /**
 915:  * Test if the other time zone uses the same rule and only
 916:  * possibly differs in ID. This implementation for this particular
 917:  * class will return true if the other object is a SimpleTimeZone,
 918:  * the raw offsets and useDaylight are identical and if useDaylight
 919:  * is true, also the start and end datas are identical.
 920:  * @return true if this zone uses the same rule.
 921:  */
 922:  public boolean hasSameRules(TimeZone other)
 923:  {
 924:  if (this == other)
 925:  return true;
 926:  if (! (other instanceof SimpleTimeZone))
 927:  return false;
 928:  SimpleTimeZone zone = (SimpleTimeZone) other;
 929:  if (zone.hashCode() != hashCode() || rawOffset != zone.rawOffset
 930:  || useDaylight != zone.useDaylight)
 931:  return false;
 932:  if (! useDaylight)
 933:  return true;
 934:  return (startYear == zone.startYear && startMonth == zone.startMonth
 935:  && startDay == zone.startDay
 936:  && startDayOfWeek == zone.startDayOfWeek
 937:  && startTime == zone.startTime
 938:  && startTimeMode == zone.startTimeMode && endMonth == zone.endMonth
 939:  && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek
 940:  && endTime == zone.endTime && endTimeMode == zone.endTimeMode);
 941:  }
 942: 
 943:  /**
 944:  * Returns a string representation of this SimpleTimeZone object.
 945:  * @return a string representation of this SimpleTimeZone object.
 946:  */
 947:  public String toString()
 948:  {
 949:  // the test for useDaylight is an incompatibility to jdk1.2, but
 950:  // I think this shouldn't hurt.
 951:  return getClass().getName() + "[" + "id=" + getID() + ",offset="
 952:  + rawOffset + ",dstSavings=" + dstSavings + ",useDaylight="
 953:  + useDaylight
 954:  + (useDaylight
 955:  ? ",startYear=" + startYear + ",startMode=" + startMode
 956:  + ",startMonth=" + startMonth + ",startDay=" + startDay
 957:  + ",startDayOfWeek=" + startDayOfWeek + ",startTime="
 958:  + startTime + ",startTimeMode=" + startTimeMode + ",endMode="
 959:  + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay
 960:  + ",endDayOfWeek=" + endDayOfWeek + ",endTime=" + endTime
 961:  + ",endTimeMode=" + endTimeMode : "") + "]";
 962:  }
 963: 
 964:  /**
 965:  * Reads a serialized simple time zone from stream.
 966:  * @see #writeObject
 967:  */
 968:  private void readObject(java.io.ObjectInputStream input)
 969:  throws java.io.IOException, ClassNotFoundException
 970:  {
 971:  input.defaultReadObject();
 972:  if (serialVersionOnStream == 0)
 973:  {
 974:  // initialize the new fields to default values.
 975:  dstSavings = 60 * 60 * 1000;
 976:  endMode = DOW_IN_MONTH_MODE;
 977:  startMode = DOW_IN_MONTH_MODE;
 978:  startTimeMode = WALL_TIME;
 979:  endTimeMode = WALL_TIME;
 980:  serialVersionOnStream = 2;
 981:  }
 982:  else
 983:  {
 984:  int length = input.readInt();
 985:  byte[] byteArray = new byte[length];
 986:  input.read(byteArray, 0, length);
 987:  if (length >= 4)
 988:  {
 989:  // Lets hope that Sun does extensions to the serialized
 990:  // form in a sane manner.
 991:  startDay = byteArray[0];
 992:  startDayOfWeek = byteArray[1];
 993:  endDay = byteArray[2];
 994:  endDayOfWeek = byteArray[3];
 995:  }
 996:  }
 997:  }
 998: 
 999:  /**
1000:  * Serializes this object to a stream. @serialdata The object is
1001:  * first written in the old JDK 1.1 format, so that it can be read
1002:  * by by the old classes. This means, that the
1003:  * <code>start/endDay(OfWeek)</code>-Fields are written in the
1004:  * DOW_IN_MONTH_MODE rule, since this was the only supported rule
1005:  * in 1.1.
1006:  *
1007:  * In the optional section, we write first the length of an byte
1008:  * array as int and afterwards the byte array itself. The byte
1009:  * array contains in this release four elements, namely the real
1010:  * startDay, startDayOfWeek endDay, endDayOfWeek in that Order.
1011:  * These fields are needed, because for compatibility reasons only
1012:  * approximative values are written to the required section, as
1013:  * described above.
1014:  */
1015:  private void writeObject(java.io.ObjectOutputStream output)
1016:  throws java.io.IOException
1017:  {
1018:  byte[] byteArray = new byte[]
1019:  {
1020:  (byte) startDay, (byte) startDayOfWeek, (byte) endDay,
1021:  (byte) endDayOfWeek
1022:  };
1023: 
1024:  /* calculate the approximation for JDK 1.1 */
1025:  switch (startMode)
1026:  {
1027:  case DOM_MODE:
1028:  startDayOfWeek = Calendar.SUNDAY; // random day of week
1029: 
1030:  // fall through
1031:  case DOW_GE_DOM_MODE:
1032:  case DOW_LE_DOM_MODE:
1033:  startDay = (startDay + 6) / 7;
1034:  }
1035:  switch (endMode)
1036:  {
1037:  case DOM_MODE:
1038:  endDayOfWeek = Calendar.SUNDAY;
1039: 
1040:  // fall through
1041:  case DOW_GE_DOM_MODE:
1042:  case DOW_LE_DOM_MODE:
1043:  endDay = (endDay + 6) / 7;
1044:  }
1045: 
1046:  // the required part:
1047:  output.defaultWriteObject();
1048:  // the optional part:
1049:  output.writeInt(byteArray.length);
1050:  output.write(byteArray, 0, byteArray.length);
1051:  }
1052: }
Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)

AltStyle によって変換されたページ (->オリジナル) /