OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [libjava/] [classpath/] [java/] [util/] [SimpleTimeZone.java] - Blame information for rev 14

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.