Source for java.util.Date

   1: /* java.util.Date
   2:    Copyright (C) 1998, 1999, 2000, 2001, 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: package java.util;
  39: 
  40: import gnu.java.lang.CPStringBuilder;
  41: 
  42: import java.io.IOException;
  43: import java.io.ObjectInputStream;
  44: import java.io.ObjectOutputStream;
  45: import java.io.Serializable;
  46: import java.text.DateFormat;
  47: import java.text.SimpleDateFormat;
  48: 
  49: /**
  50:  * <p>
  51:  * This class represents a specific time in milliseconds since the epoch.
  52:  * The epoch is 1970, January 1 00:00:00.0000 UTC.
  53:  * </p>
  54:  * <p>
  55:  * <code>Date</code> is intended to reflect universal time coordinate (UTC),
  56:  * but this depends on the underlying host environment.  Most operating systems
  57:  * don't handle the leap second, which occurs about once every year or
  58:  * so.  The leap second is added to the last minute of the day on either
  59:  * the 30th of June or the 31st of December, creating a minute 61 seconds
  60:  * in length.
  61:  * </p>
  62:  * <p>
  63:  * The representations of the date fields are as follows:
  64:  * <ul>
  65:  * <li>
  66:  * Years are specified as the difference between the year
  67:  * and 1900.  Thus, the final year used is equal to
  68:  * 1900 + y, where y is the input value.
  69:  * </li>
  70:  * <li>
  71:  * Months are represented using zero-based indexing,
  72:  * making 0 January and 11 December.
  73:  * </li>
  74:  * <li>
  75:  * Dates are represented with the usual values of
  76:  * 1 through to 31.
  77:  * </li>
  78:  * <li>
  79:  * Hours are represented in the twenty-four hour clock,
  80:  * with integer values from 0 to 23.  12am is 0, and
  81:  * 12pm is 12.
  82:  * </li>
  83:  * <li>
  84:  * Minutes are again as usual, with values from 0 to 59.
  85:  * </li>
  86:  * <li>
  87:  * Seconds are represented with the values 0 through to 61,
  88:  * with 60 and 61 being leap seconds (as per the ISO C standard).
  89:  * </li>
  90:  * </ul>
  91:  * </p>
  92:  * <p>
  93:  * Prior to JDK 1.1, this class was the sole class handling date and time
  94:  * related functionality.  However, this particular solution was not
  95:  * amenable to internationalization.  The new <code>Calendar</code>
  96:  * class should now be used to handle dates and times, with <code>Date</code>
  97:  * being used only for values in milliseconds since the epoch.  The
  98:  * <code>Calendar</code> class, and its concrete implementations, handle
  99:  * the interpretation of these values into minutes, hours, days, months
 100:  * and years.  The formatting and parsing of dates is left to the
 101:  * <code>DateFormat</code> class, which is able to handle the different
 102:  * types of date format which occur in different locales.
 103:  * </p>
 104:  *
 105:  * @see Calendar
 106:  * @see GregorianCalendar
 107:  * @see java.text.DateFormat
 108:  * @author Jochen Hoenicke
 109:  * @author Per Bothner (bothner@cygnus.com)
 110:  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
 111:  */
 112: public class Date
 113:     implements Cloneable, Comparable<Date>, Serializable
 114: {
 115:   /**
 116:    * This is the serialization UID for this class
 117:    * for compatability with Sun's JDK.
 118:    */
 119:   private static final long serialVersionUID = 7523967970034938905L;
 120: 
 121:   /**
 122:    * The time in milliseconds since the epoch.
 123:    */
 124:   private transient long time;
 125: 
 126:   /**
 127:    * An array of week names used to map names to integer values.
 128:    */
 129:   private static final String[] weekNames = { "Sun", "Mon", "Tue", "Wed",
 130:                                               "Thu", "Fri", "Sat" };
 131:   /**
 132:    * An array of month names used to map names to integer values.
 133:    */
 134:   private static final String[] monthNames = { "Jan", "Feb", "Mar", "Apr",
 135:                                                "May", "Jun", "Jul", "Aug",
 136:                                                "Sep", "Oct", "Nov", "Dec" };
 137:   /**
 138:    * Creates a new Date Object representing the current time.
 139:    */
 140:   public Date()
 141:   {
 142:     time = System.currentTimeMillis();
 143:   }
 144: 
 145:   /**
 146:    * Creates a new Date Object representing the given time.
 147:    *
 148:    * @param time the time in milliseconds since the epoch.
 149:    */
 150:   public Date(long time)
 151:   {
 152:     this.time = time;
 153:   }
 154: 
 155:   /**
 156:    * Creates a new Date Object representing the given time.
 157:    *
 158:    * @deprecated use <code>new GregorianCalendar(year+1900, month,
 159:    * day)</code> instead.
 160:    * @param year the difference between the required year and 1900.
 161:    * @param month the month as a value between 0 and 11.
 162:    * @param day the day as a value between 0 and 31.
 163:    */
 164:   public Date(int year, int month, int day)
 165:   {
 166:     this(year, month, day, 0, 0, 0);
 167:   }
 168: 
 169:   /**
 170:    * Creates a new Date Object representing the given time.
 171:    *
 172:    * @deprecated use <code>new GregorianCalendar(year+1900, month,
 173:    * day, hour, min)</code> instead.
 174:    * @param year the difference between the required year and 1900.
 175:    * @param month the month as a value between 0 and 11.
 176:    * @param day the day as a value between 0 and 31.
 177:    * @param hour the hour as a value between 0 and 23, in 24-hour
 178:    *        clock notation.
 179:    * @param min the minute as a value between 0 and 59.
 180:    */
 181:   public Date(int year, int month, int day, int hour, int min)
 182:   {
 183:     this(year, month, day, hour, min, 0);
 184:   }
 185: 
 186:   /**
 187:    * Creates a new Date Object representing the given time.
 188:    *
 189:    * @deprecated use <code>new GregorianCalendar(year+1900, month,
 190:    * day, hour, min, sec)</code> instead.
 191:    * @param year the difference between the required year and 1900.
 192:    * @param month the month as a value between 0 and 11.
 193:    * @param day the day as a value between 0 and 31.
 194:    * @param hour the hour as a value between 0 and 23, in 24-hour
 195:    *        clock notation.
 196:    * @param min the minute as a value between 0 and 59.
 197:    * @param sec the second as a value between 0 and 61 (with 60
 198:    *        and 61 being leap seconds).
 199:    */
 200:   public Date(int year, int month, int day, int hour, int min, int sec)
 201:   {
 202:     GregorianCalendar cal =
 203:         new GregorianCalendar(year + 1900, month, day, hour, min, sec);
 204:     time = cal.getTimeInMillis();
 205:   }
 206: 
 207:   /**
 208:    * Creates a new Date from the given string representation.  This
 209:    * does the same as <code>new Date(Date.parse(s))</code>
 210:    * @see #parse
 211:    * @deprecated use <code>java.text.DateFormat.parse(s)</code> instead.
 212:    */
 213:   public Date(String s)
 214:   {
 215:     time = parse(s);
 216:   }
 217: 
 218:   /**
 219:    * Returns a copy of this <code>Date</code> object.
 220:    *
 221:    * @return a copy, or null if the object couldn't be
 222:    *         cloned.
 223:    * @see Object#clone()
 224:    */
 225:   public Object clone()
 226:   {
 227:     try
 228:       {
 229:         return super.clone();
 230:       }
 231:     catch (CloneNotSupportedException ex)
 232:       {
 233:         return null;
 234:       }
 235:   }
 236: 
 237:   /**
 238:    * Returns the number of milliseconds since the epoch
 239:    * specified by the given arguments.  The arguments are
 240:    * interpreted relative to UTC rather than the local
 241:    * time zone.
 242:    *
 243:    * @deprecated Use <code>Calendar</code> with a UTC
 244:    *             <code>TimeZone</code> instead.
 245:    * @param year the difference between the required year and 1900.
 246:    * @param month the month as a value between 0 and 11.
 247:    * @param date the day as a value between 0 and 31.
 248:    * @param hrs the hour as a value between 0 and 23, in 24-hour
 249:    *        clock notation.
 250:    * @param min the minute as a value between 0 and 59.
 251:    * @param sec the second as a value between 0 and 61 (with 60
 252:    *        and 61 being leap seconds).
 253:    * @return the time in milliseconds since the epoch.
 254:    */
 255:   public static long UTC(int year, int month, int date,
 256:                          int hrs, int min, int sec)
 257:   {
 258:     GregorianCalendar cal =
 259:       new GregorianCalendar(year + 1900, month, date, hrs, min, sec);
 260:     cal.set(Calendar.ZONE_OFFSET, 0);
 261:     cal.set(Calendar.DST_OFFSET, 0);
 262:     return cal.getTimeInMillis();
 263:   }
 264: 
 265:   /**
 266:    * Gets the time represented by this object.
 267:    *
 268:    * @return the time in milliseconds since the epoch.
 269:    */
 270:   public long getTime()
 271:   {
 272:     return time;
 273:   }
 274: 
 275:   /**
 276:    * Returns the number of minutes offset used with UTC to give the time
 277:    * represented by this object in the current time zone.  The date information
 278:    * from this object is also used to determine whether or not daylight savings
 279:    * time is in effect.  For example, the offset for the UK would be 0 if the
 280:    * month of the date object was January, and 1 if the month was August.
 281:    *
 282:    * @deprecated use
 283:    * <code>Calendar.get(Calendar.ZONE_OFFSET)+Calendar.get(Calendar.DST_OFFSET)</code>
 284:    * instead.
 285:    * @return The time zone offset in minutes of the local time zone
 286:    * relative to UTC.  The time represented by this object is used to
 287:    * determine if we should use daylight savings.
 288:    */
 289:   public int getTimezoneOffset()
 290:   {
 291:     Calendar cal = Calendar.getInstance();
 292:     cal.setTimeInMillis(time);
 293:     return - (cal.get(Calendar.ZONE_OFFSET)
 294:             + cal.get(Calendar.DST_OFFSET)) / (60 * 1000);
 295:   }
 296: 
 297:   /**
 298:    * Sets the time which this object should represent.
 299:    *
 300:    * @param time the time in milliseconds since the epoch.
 301:    */
 302:   public void setTime(long time)
 303:   {
 304:     this.time = time;
 305:   }
 306: 
 307:   /**
 308:    * Tests if this date is after the specified date.
 309:    *
 310:    * @param when the other date
 311:    * @return true, if the date represented by this object is
 312:    * strictly later than the time represented by when.
 313:    */
 314:   public boolean after(Date when)
 315:   {
 316:     return time > when.time;
 317:   }
 318: 
 319:   /**
 320:    * Tests if this date is before the specified date.
 321:    *
 322:    * @param when the other date
 323:    * @return true, if the date represented by when is strictly later
 324:    * than the time represented by this object.
 325:    */
 326:   public boolean before(Date when)
 327:   {
 328:     return time < when.time;
 329:   }
 330: 
 331:   /**
 332:    * Compares two dates for equality.
 333:    *
 334:    * @param obj the object to compare.
 335:    * @return true, if obj is a Date object and the time represented
 336:    * by obj is exactly the same as the time represented by this
 337:    * object.
 338:    */
 339:   public boolean equals(Object obj)
 340:   {
 341:     return (obj instanceof Date && time == ((Date) obj).time);
 342:   }
 343: 
 344:   /**
 345:    * Compares two dates.
 346:    *
 347:    * @param when the other date.
 348:    * @return 0, if the date represented
 349:    * by obj is exactly the same as the time represented by this
 350:    * object, a negative if this Date is before the other Date, and
 351:    * a positive value otherwise.
 352:    */
 353:   public int compareTo(Date when)
 354:   {
 355:     return (time < when.time) ? -1 : (time == when.time) ? 0 : 1;
 356:   }
 357: 
 358:   /**
 359:    * Computes the hash code of this <code>Date</code> as the
 360:    * XOR of the most significant and the least significant
 361:    * 32 bits of the 64 bit milliseconds value.
 362:    *
 363:    * @return the hash code.
 364:    */
 365:   public int hashCode()
 366:   {
 367:     return (int) time ^ (int) (time >>> 32);
 368:   }
 369: 
 370:   /**
 371:    * <p>
 372:    * Returns a string representation of this date using
 373:    * the following date format:
 374:    * </p>
 375:    * <p>
 376:    * <code>day mon dd hh:mm:ss zz yyyy</code>
 377:    * </p>
 378:    * <p>where the fields used here are:
 379:    * <ul>
 380:    * <li>
 381:    * <code>day</code> -- the day of the week
 382:    * (Sunday through to Saturday).
 383:    * </li>
 384:    * <li>
 385:    * <code>mon</code> -- the month (Jan to Dec).
 386:    * </li>
 387:    * <li>
 388:    * <code>dd</code> -- the day of the month
 389:    * as two decimal digits (01 to 31).
 390:    * </li>
 391:    * <li>
 392:    * <code>hh</code> -- the hour of the day
 393:    * as two decimal digits in 24-hour clock notation
 394:    * (01 to 23).
 395:    * </li>
 396:    * <li>
 397:    * <code>mm</code> -- the minute of the day
 398:    * as two decimal digits (01 to 59).
 399:    * </li>
 400:    * <li>
 401:    * <code>ss</code> -- the second of the day
 402:    * as two decimal digits (01 to 61).
 403:    * </li>
 404:    * <li>
 405:    * <code>zz</code> -- the time zone information if available.
 406:    * The possible time zones used include the abbreviations
 407:    * recognised by <code>parse()</code> (e.g. GMT, CET, etc.)
 408:    * and may reflect the fact that daylight savings time is in
 409:    * effect.  The empty string is used if there is no time zone
 410:    * information.
 411:    * </li>
 412:    * <li>
 413:    * <code>yyyy</code> -- the year as four decimal digits.
 414:    * </li>
 415:    * </ul>
 416:    * <p>
 417:    * The <code>DateFormat</code> class should now be
 418:    * preferred over using this method.
 419:    * </p>
 420:    *
 421:    * @return A string of the form 'day mon dd hh:mm:ss zz yyyy'
 422:    * @see #parse(String)
 423:    * @see DateFormat
 424:    */
 425:   public String toString()
 426:   {
 427:     Calendar cal = Calendar.getInstance();
 428:     cal.setTimeInMillis(time);
 429:     String day = "0" + cal.get(Calendar.DATE);
 430:     String hour = "0" + cal.get(Calendar.HOUR_OF_DAY);
 431:     String min = "0" + cal.get(Calendar.MINUTE);
 432:     String sec = "0" + cal.get(Calendar.SECOND);
 433:     String year = "000" + cal.get(Calendar.YEAR);
 434:     return weekNames[cal.get(Calendar.DAY_OF_WEEK) - 1] + " "
 435:       + monthNames[cal.get(Calendar.MONTH)] + " "
 436:       + day.substring(day.length() - 2) + " "
 437:       + hour.substring(hour.length() - 2) + ":"
 438:       + min.substring(min.length() - 2) + ":"
 439:       + sec.substring(sec.length() - 2) + " "
 440:       +
 441:       cal.getTimeZone().getDisplayName(cal.getTimeZone().inDaylightTime(this),
 442:                                        TimeZone.SHORT) + " " +
 443:       year.substring(year.length() - 4);
 444:   }
 445: 
 446:   /**
 447:    * Returns a locale-dependent string representation of this
 448:    * <code>Date</code> object.
 449:    *
 450:    * @deprecated Use DateFormat.format(Date)
 451:    * @return A locale-dependent string representation.
 452:    * @see #parse(String)
 453:    * @see DateFormat
 454:    */
 455:   public String toLocaleString()
 456:   {
 457:     return java.text.DateFormat.getInstance().format(this);
 458:   }
 459: 
 460:   /**
 461:    * <p>
 462:    * Returns a string representation of this <code>Date</code>
 463:    * object using GMT rather than the local timezone.
 464:    * The following date format is used:
 465:    * </p>
 466:    * <p>
 467:    * <code>d mon yyyy hh:mm:ss GMT</code>
 468:    * </p>
 469:    * <p>where the fields used here are:
 470:    * <ul>
 471:    * <li>
 472:    * <code>d</code> -- the day of the month
 473:    * as one or two decimal digits (1 to 31).
 474:    * </li>
 475:    * <li>
 476:    * <code>mon</code> -- the month (Jan to Dec).
 477:    * </li>
 478:    * <li>
 479:    * <code>yyyy</code> -- the year as four decimal digits.
 480:    * </li>
 481:    * <li>
 482:    * <code>hh</code> -- the hour of the day
 483:    * as two decimal digits in 24-hour clock notation
 484:    * (01 to 23).
 485:    * </li>
 486:    * <li>
 487:    * <code>mm</code> -- the minute of the day
 488:    * as two decimal digits (01 to 59).
 489:    * </li>
 490:    * <li>
 491:    * <code>ss</code> -- the second of the day
 492:    * as two decimal digits (01 to 61).
 493:    * </li>
 494:    * <li>
 495:    * <code>GMT</code> -- the literal string "GMT"
 496:    * indicating Greenwich Mean Time as opposed to
 497:    * the local timezone.
 498:    * </li>
 499:    * </ul>
 500:    *
 501:    * @deprecated Use DateFormat.format(Date) with a GMT TimeZone.
 502:    * @return A string of the form 'd mon yyyy hh:mm:ss GMT' using
 503:    *         GMT as opposed to the local timezone.
 504:    * @see #parse(String)
 505:    * @see DateFormat
 506:    */
 507:   public String toGMTString()
 508:   {
 509:     java.text.DateFormat format = java.text.DateFormat.getInstance();
 510:     format.setTimeZone(TimeZone.getTimeZone("GMT"));
 511:     return format.format(this);
 512:   }
 513: 
 514:   /**
 515:    * Parses the time zone string.
 516:    *
 517:    * @param tok The token containing the time zone.
 518:    * @param sign The sign (+ or -) used by the time zone.
 519:    * @return An integer representing the number of minutes offset
 520:    *         from GMT for the time zone.
 521:    */
 522:   private static int parseTz(String tok, char sign)
 523:     throws IllegalArgumentException
 524:   {
 525:     int num;
 526: 
 527:     try
 528:       {
 529:         // parseInt doesn't handle '+' so strip off sign.
 530:         num = Integer.parseInt(tok.substring(1));
 531:       }
 532:     catch (NumberFormatException ex)
 533:       {
 534:         throw new IllegalArgumentException(tok);
 535:       }
 536: 
 537:     // Convert hours to minutes.
 538:     if (num < 24)
 539:       num *= 60;
 540:     else
 541:       num = (num / 100) * 60 + num % 100;
 542: 
 543:     return sign == '-' ? -num : num;
 544:   }
 545: 
 546:   /**
 547:    * Parses the month string.
 548:    *
 549:    * @param tok the token containing the month.
 550:    * @return An integer between 0 and 11, representing
 551:    *         a month from January (0) to December (11),
 552:    *         or -1 if parsing failed.
 553:    */
 554:   private static int parseMonth(String tok)
 555:   {
 556:     // Initialize strings for month names.
 557:     // We could possibly use the fields of DateFormatSymbols but that is
 558:     // localized and thus might not match the English words specified.
 559:     String months[] = { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY",
 560:                         "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER",
 561:                         "NOVEMBER", "DECEMBER" };
 562: 
 563:     int i;
 564:     for (i = 0; i < 12; i++)
 565:       if (months[i].startsWith(tok))
 566:         return i;
 567: 
 568:     // Return -1 if not found.
 569:     return -1;
 570:   }
 571: 
 572:   /**
 573:    * Parses the day of the week string.
 574:    *
 575:    * @param tok the token containing the day of the week.
 576:    * @return true if the token was parsed successfully.
 577:    */
 578:   private static boolean parseDayOfWeek(String tok)
 579:   {
 580:     // Initialize strings for days of the week names.
 581:     // We could possibly use the fields of DateFormatSymbols but that is
 582:     // localized and thus might not match the English words specified.
 583:     String daysOfWeek[] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
 584:                             "THURSDAY", "FRIDAY", "SATURDAY" };
 585: 
 586:     int i;
 587:     for (i = 0; i < 7; i++)
 588:       if (daysOfWeek[i].startsWith(tok))
 589:         return true;
 590: 
 591:     return false;
 592:   }
 593: 
 594:   /**
 595:    * <p>
 596:    * Parses a String and returns the time, in milliseconds since the
 597:    * epoch, it represents.  Most syntaxes are handled, including
 598:    * the IETF date standard "day, dd mon yyyy hh:mm:ss zz" (see
 599:    * <code>toString()</code> for definitions of these fields).
 600:    * Standard U.S. time zone abbreviations are recognised, in
 601:    * addition to time zone offsets in positive or negative minutes.
 602:    * If a time zone is specified, the specified time is assumed to
 603:    * be in UTC and the appropriate conversion is applied, following
 604:    * parsing, to convert this to the local time zone.  If no zone
 605:    * is specified, the time is assumed to already be in the local
 606:    * time zone.
 607:    * </p>
 608:    * <p>
 609:    * The method parses the string progressively from left to right.
 610:    * At the end of the parsing process, either a time is returned
 611:    * or an <code>IllegalArgumentException</code> is thrown to signify
 612:    * failure.  The ASCII characters A-Z, a-z, 0-9, and ',', '+', '-',
 613:    * ':' and '/' are the only characters permitted within the string,
 614:    * besides whitespace and characters enclosed within parantheses
 615:    * '(' and ')'.
 616:    * </p>
 617:    * <p>
 618:    * A sequence of consecutive digits are recognised as a number,
 619:    * and interpreted as follows:
 620:    * <ul>
 621:    * <li>
 622:    * A number preceded by a sign (+ or -) is taken to be a time zone
 623:    * offset.  The time zone offset can be specified in either hours
 624:    * or minutes.  The former is assumed if the number is less than 24.
 625:    * Otherwise, the offset is assumed to be in minutes.  A - indicates
 626:    * a time zone west of GMT, while a + represents a time zone to the
 627:    * east of GMT.  The time zones are always assumed to be relative
 628:    * to GMT, and a (redundant) specification of this can be included
 629:    * with the time zone.  For example, '-9', 'utc-9' and 'GMT-9' all
 630:    * represent a time zone nine hours west of GMT.  Similarly,
 631:    * '+4', 'ut+4' and 'UTC+4' all give 4 hours east of GMT.
 632:    * </li>
 633:    * <li>
 634:    * A number equal to or greater than 70 is regarded as a year specification.
 635:    * Values lower than 70 are only assumed to indicate a year if both the
 636:    * day of the month and the month itself have already been recognised.
 637:    * Year values less than 100 are interpreted as being relative to the current
 638:    * century when the <code>Date</code> class is initialised..  Given a century,
 639:    * x, the year is assumed to be within the range x - 80 to x + 19.  The value
 640:    * itself is then used as a match against the two last digits of one of these
 641:    * years.  For example, take x to be 2004.  A two-digit year is assumed to fall
 642:    * within the range x - 80 (1924) and x + 19 (2023).  Thus, any intepreted value
 643:    * between 0 and 23 is assumed to be 2000 to 2023 and values between 24 and 99
 644:    * are taken as being 1924 to 1999.  This only applies for the case of 2004.
 645:    * With a different year, the values will be interpreted differently. 2005
 646:    * will used 0 to 24 as 2000 to 2024 and 25 to 99 as 1925 to 1999, for example.
 647:    * This behaviour differs from that of <code>SimpleDateFormat</code> and is
 648:    * time-dependent (a two-digit year will be interpreted differently depending
 649:    * on the time the code is run).
 650:    * </li>
 651:    * <li>
 652:    * Numbers followed by a colon are interpreted by first an hour, and then
 653:    * as a minute, once an hour has been found.
 654:    * </li>
 655:    * <li>
 656:    * <li>
 657:    * Numbers followed by a slash are regarded first as a month, and then as
 658:    * a day of the month once the month has been found.  This follows the
 659:    * U.S. date format of mm/dd, rather than the European dd/mm.  Months
 660:    * are converted to the recognised value - 1 before storage, in order
 661:    * to put the number within the range 0 to 11.
 662:    * </li>
 663:    * <li>
 664:    * Numbers followed by commas, whitespace, hyphens or the end of the string
 665:    * are interpreted in the following order: hour, minute, second, day of month.
 666:    * The first type not already recognised in the current string being parsed is
 667:    * assumed.
 668:    * </li>
 669:    * </ul>
 670:    * </p>
 671:    * <p>
 672:    * A sequence of consecutive alphabetic characters is recognised as a word,
 673:    * and interpreted as follows, in a case-insentive fashion:
 674:    * <ul>
 675:    * <li>
 676:    * The characters 'AM' or 'PM' restrict the hour value to a value between 0
 677:    * and 12.  In the latter case, 12 is added to the hour value before storage.
 678:    * </li>
 679:    * <li>
 680:    * Any words which match any prefix of one of the days of the week ('Monday',
 681:    * 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' and 'Sunday'),
 682:    * are simply ignored.
 683:    * </li>
 684:    * <li>
 685:    * Any words which match any prefix of one of the months of the year ('January',
 686:    * 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September',
 687:    * 'October', 'November', 'December') are recognised and interpreted as the
 688:    * appropriate value between 0 and 11.  The first match made against a
 689:    * month is the one used, in the order specified here.  For example, 'Ma' is
 690:    * intepreted as 'March' (2) and not as 'May' (4).  Similarly, 'Ju' is 'June',
 691:    * and not 'July'.
 692:    * </li>
 693:    * <li>
 694:    * The words 'GMT', 'UT' and 'UTC' are interpreted as specifying UTC as the
 695:    * time zone in use for this date.
 696:    * </li>
 697:    * <li>
 698:    * The word pairs 'EST'/'EDT', 'CST'/'CDT', 'MST'/'MDT' and 'PST'/'PDT' are
 699:    * interpreted as the appropriate U.S. time zone abbreviation.  Each pair
 700:    * is the standard and daylight savings time zone specification, respectively,
 701:    * for each zone within the U.S, these being Eastern Standard/Daylight Time
 702:    * (-5), Central Standard/Daylight Time (-6), Mountain Standard/Daylight Time
 703:    * (-7) and Pacific Standard/Daylight Time (-8).
 704:    * </li>
 705:    * </ul>
 706:    *
 707:    * @param string The String to parse.
 708:    * @return The time in milliseconds since the epoch.
 709:    * @throws IllegalArgumentException if the string fails to parse.
 710:    * @deprecated Use DateFormat.parse(String)
 711:    * @see #toString()
 712:    * @see SimpleDateFormat
 713:    */
 714:   public static long parse(String string)
 715:   {
 716:     // Initialize date/time fields before parsing begins.
 717:     int year = -1;
 718:     int month = -1;
 719:     int day = -1;
 720:     int hour = -1;
 721:     int minute = -1;
 722:     int second = -1;
 723:     int timezone = 0;
 724:     boolean localTimezone = true;
 725: 
 726:     // Trim out any nested stuff in parentheses now to make parsing easier.
 727:     CPStringBuilder buf = new CPStringBuilder();
 728:     int parenNesting = 0;
 729:     int len = string.length();
 730:     for (int i = 0;  i < len;  i++)
 731:       {
 732:         char ch = string.charAt(i);
 733:         if (ch >= 'a' && ch <= 'z')
 734:           ch -= 'a' - 'A';
 735:         if (ch == '(')
 736:           parenNesting++;
 737:         else if (parenNesting == 0)
 738:           buf.append(ch);
 739:         else if (ch == ')')
 740:           parenNesting--;
 741:       }
 742:     int tmpMonth;
 743: 
 744:     // Make all chars upper case to simplify comparisons later.
 745:     // Also ignore commas; treat them as delimiters.
 746:     StringTokenizer strtok = new StringTokenizer(buf.toString(), " \t\n\r,");
 747: 
 748:     while (strtok.hasMoreTokens())
 749:       {
 750:         String tok = strtok.nextToken();
 751:         char firstch = tok.charAt(0);
 752:         if ((firstch == '+' || firstch == '-') && year >= 0)
 753:           {
 754:             timezone = parseTz(tok, firstch);
 755:             localTimezone = false;
 756:           }
 757:         else if (firstch >= '0' && firstch <= '9')
 758:           {
 759:             int lastPunct = -1;
 760:             while (tok != null && tok.length() > 0)
 761:               {
 762:                 int punctOffset = tok.length();
 763:                 int num = 0;
 764:                 int punct;
 765:                 for (int i = 0;  ;  i++)
 766:                   {
 767:                     if (i >= punctOffset)
 768:                       {
 769:                         punct = -1;
 770:                         break;
 771:                       }
 772:                     else
 773:                       {
 774:                         punct = tok.charAt(i);
 775:                         if (punct >= '0' && punct <= '9')
 776:                           {
 777:                             if (num > 999999999) // in case of overflow
 778:                               throw new IllegalArgumentException(tok);
 779:                             num = 10 * num + (punct - '0');
 780:                           }
 781:                         else
 782:                           {
 783:                             punctOffset = i;
 784:                             break;
 785:                           }
 786:                       }
 787: 
 788:                   }
 789: 
 790:                 if (punct == ':')
 791:                   {
 792:                     if (hour < 0)
 793:                       hour = num;
 794:                     else
 795:                       minute = num;
 796:                   }
 797:                 else if (lastPunct == ':' && hour >= 0 && (minute < 0 || second < 0))
 798:                   {
 799:                     if (minute < 0)
 800:                       minute = num;
 801:                     else
 802:                       second = num;
 803:                   }
 804:                 else if ((num >= 70
 805:                           && (punct == ' ' || punct == ','
 806:                               || punct == '/' || punct < 0))
 807:                          || (num < 70 && day >= 0 && month >= 0 && year < 0))
 808:                   {
 809:                     if (num >= 100)
 810:                       year = num;
 811:                     else
 812:                       {
 813:                         int curYear = 1900 + new Date().getYear();
 814:                         int firstYear = curYear - 80;
 815:                         year = firstYear / 100 * 100 + num;
 816:                         if (year < firstYear)
 817:                           year += 100;
 818:                       }
 819:                   }
 820:                 else if (punct == '/')
 821:                   {
 822:                     if (month < 0)
 823:                       month = num - 1;
 824:                     else
 825:                       day = num;
 826:                   }
 827:                 else if (hour >= 0 && minute < 0)
 828:                   minute = num;
 829:                 else if (minute >= 0 && second < 0)
 830:                   second = num;
 831:                 else if (day < 0)
 832:                   day = num;
 833:                 else
 834:                   throw new IllegalArgumentException(tok);
 835: 
 836:                 // Advance string if there's more to process in this token.
 837:                 if (punct < 0 || punctOffset + 1 >= tok.length())
 838:                   tok = null;
 839:                 else
 840:                   tok = tok.substring(punctOffset + 1);
 841:                 lastPunct = punct;
 842:               }
 843:           }
 844:         else if (firstch >= 'A' && firstch <= 'Z')
 845:           {
 846:             if (tok.equals("AM"))
 847:               {
 848:                 if (hour < 1 || hour > 12)
 849:                   throw new IllegalArgumentException(tok);
 850:                 if (hour == 12)
 851:                   hour = 0;
 852:               }
 853:             else if (tok.equals("PM"))
 854:               {
 855:                 if (hour < 1 || hour > 12)
 856:                   throw new IllegalArgumentException(tok);
 857:                 if (hour < 12)
 858:                   hour += 12;
 859:               }
 860:             else if (parseDayOfWeek(tok))
 861:               { /* Ignore it; throw the token away. */ }
 862:             else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT"))
 863:               localTimezone = false;
 864:             else if (tok.startsWith("UT") || tok.startsWith("GMT"))
 865:               {
 866:                 int signOffset = 3;
 867:                 if (tok.charAt(1) == 'T' && tok.charAt(2) != 'C')
 868:                   signOffset = 2;
 869: 
 870:                 char sign = tok.charAt(signOffset);
 871:                 if (sign != '+' && sign != '-')
 872:                   throw new IllegalArgumentException(tok);
 873: 
 874:                 timezone = parseTz(tok.substring(signOffset), sign);
 875:                 localTimezone = false;
 876:               }
 877:             else if ((tmpMonth = parseMonth(tok)) >= 0)
 878:               month = tmpMonth;
 879:             else if (tok.length() == 3 && tok.charAt(2) == 'T')
 880:               {
 881:                 // Convert timezone offset from hours to minutes.
 882:                 char ch = tok.charAt(0);
 883:                 if (ch == 'E')
 884:                   timezone = -5 * 60;
 885:                 else if (ch == 'C')
 886:                   timezone = -6 * 60;
 887:                 else if (ch == 'M')
 888:                   timezone = -7 * 60;
 889:                 else if (ch == 'P')
 890:                   timezone = -8 * 60;
 891:                 else
 892:                   throw new IllegalArgumentException(tok);
 893: 
 894:                 // Shift 60 minutes for Daylight Savings Time.
 895:                 if (tok.charAt(1) == 'D')
 896:                   timezone += 60;
 897:                 else if (tok.charAt(1) != 'S')
 898:                   throw new IllegalArgumentException(tok);
 899: 
 900:                 localTimezone = false;
 901:               }
 902:             else
 903:               throw new IllegalArgumentException(tok);
 904:           }
 905:         else
 906:           throw new IllegalArgumentException(tok);
 907:       }
 908: 
 909:     // Unspecified hours, minutes, or seconds should default to 0.
 910:     if (hour < 0)
 911:       hour = 0;
 912:     if (minute < 0)
 913:       minute = 0;
 914:     if (second < 0)
 915:       second = 0;
 916: 
 917:     // Throw exception if any other fields have not been recognized and set.
 918:     if (year < 0 || month < 0 || day < 0)
 919:       throw new IllegalArgumentException("Missing field");
 920: 
 921:     // Return the time in either local time or relative to GMT as parsed.
 922:     // If no time-zone was specified, get the local one (in minutes) and
 923:     // convert to milliseconds before adding to the UTC.
 924:     GregorianCalendar cal
 925:       = new GregorianCalendar(year, month, day, hour, minute, second);
 926:     if (!localTimezone)
 927:       {
 928:         cal.set(Calendar.ZONE_OFFSET, timezone * 60 * 1000);
 929:         cal.set(Calendar.DST_OFFSET, 0);
 930:       }
 931:     return cal.getTimeInMillis();
 932:   }
 933: 
 934:   /**
 935:    * Returns the difference between the year represented by this
 936:    * <code>Date</code> object and 1900.
 937:    *
 938:    * @return the year minus 1900 represented by this date object.
 939:    * @deprecated Use Calendar instead of Date, and use get(Calendar.YEAR)
 940:    * instead.  Note the 1900 difference in the year.
 941:    * @see Calendar
 942:    * @see #setYear(int)
 943:    */
 944:   public int getYear()
 945:   {
 946:     Calendar cal = Calendar.getInstance();
 947:     cal.setTimeInMillis(time);
 948:     return cal.get(Calendar.YEAR) - 1900;
 949:   }
 950: 
 951:   /**
 952:    * Sets the year to the specified year, plus 1900.  The other
 953:    * fields are only altered as required to match the same date
 954:    * and time in the new year.  Usually, this will mean that
 955:    * the fields are not changed at all, but in the case of
 956:    * a leap day or leap second, the fields will change in
 957:    * relation to the existence of such an event in the new year.
 958:    * For example, if the date specifies February the 29th, 2000,
 959:    * then this will become March the 1st if the year is changed
 960:    * to 2001, as 2001 is not a leap year.  Similarly, a seconds
 961:    * value of 60 or 61 may result in the seconds becoming 0 and
 962:    * the minute increasing by 1, if the new time does not include
 963:    * a leap second.
 964:    *
 965:    * @param year the year minus 1900.
 966:    * @deprecated Use Calendar instead of Date, and use
 967:    * set(Calendar.YEAR, year) instead.  Note about the 1900
 968:    * difference in year.
 969:    * @see #getYear()
 970:    * @see Calendar
 971:    */
 972:   public void setYear(int year)
 973:   {
 974:     Calendar cal = Calendar.getInstance();
 975:     cal.setTimeInMillis(time);
 976:     cal.set(Calendar.YEAR, 1900 + year);
 977:     time = cal.getTimeInMillis();
 978:   }
 979: 
 980:   /**
 981:    * Returns the month represented by this <code>Date</code> object,
 982:    * as a value between 0 (January) and 11 (December).
 983:    *
 984:    * @return the month represented by this date object (zero based).
 985:    * @deprecated Use Calendar instead of Date, and use get(Calendar.MONTH)
 986:    * instead.
 987:    * @see #setMonth(int)
 988:    * @see Calendar
 989:    */
 990:   public int getMonth()
 991:   {
 992:     Calendar cal = Calendar.getInstance();
 993:     cal.setTimeInMillis(time);
 994:     return cal.get(Calendar.MONTH);
 995:   }
 996: 
 997:   /**
 998:    * Sets the month to the given value.  The other
 999:    * fields are only altered as necessary to match
1000:    * the same date and time in the new month.  In most
1001:    * cases, the other fields won't change at all.  However,
1002:    * in the case of a shorter month or a leap second, values
1003:    * may be adjusted.  For example, if the day of the month
1004:    * is currently 31, and the month value is changed from
1005:    * January (0) to September (8), the date will become
1006:    * October the 1st, as September only has 30 days.  Similarly,
1007:    * a seconds value of 60 or 61 (a leap second) may result
1008:    * in the seconds value being reset to 0 and the minutes
1009:    * value being incremented by 1, if the new time does
1010:    * not include a leap second.
1011:    *
1012:    * @param month the month, with a zero-based index
1013:    *        from January.
1014:    * @deprecated Use Calendar instead of Date, and use
1015:    * set(Calendar.MONTH, month) instead.
1016:    * @see #getMonth()
1017:    * @see Calendar
1018:    */
1019:   public void setMonth(int month)
1020:   {
1021:     Calendar cal = Calendar.getInstance();
1022:     cal.setTimeInMillis(time);
1023:     cal.set(Calendar.MONTH, month);
1024:     time = cal.getTimeInMillis();
1025:   }
1026: 
1027:   /**
1028:    * Returns the day of the month of this <code>Date</code>
1029:    * object, as a value between 0 and 31.
1030:    *
1031:    * @return the day of month represented by this date object.
1032:    * @deprecated Use Calendar instead of Date, and use get(Calendar.DATE)
1033:    * instead.
1034:    * @see Calendar
1035:    * @see #setDate(int)
1036:    */
1037:   public int getDate()
1038:   {
1039:     Calendar cal = Calendar.getInstance();
1040:     cal.setTimeInMillis(time);
1041:     return cal.get(Calendar.DATE);
1042:   }
1043: 
1044:   /**
1045:    * Sets the date to the given value. The other
1046:    * fields are only altered as necessary to match
1047:    * the same date and time on the new day of the month.  In most
1048:    * cases, the other fields won't change at all.  However,
1049:    * in the case of a leap second or the day being out of
1050:    * the range of the current month, values
1051:    * may be adjusted.  For example, if the day of the month
1052:    * is currently 30 and the month is June, a new day of the
1053:    * month value of 31 will cause the month to change to July,
1054:    * as June only has 30 days .  Similarly,
1055:    * a seconds value of 60 or 61 (a leap second) may result
1056:    * in the seconds value being reset to 0 and the minutes
1057:    * value being incremented by 1, if the new time does
1058:    * not include a leap second.
1059:    *
1060:    * @param date the date.
1061:    * @deprecated Use Calendar instead of Date, and use
1062:    * set(Calendar.DATE, date) instead.
1063:    * @see Calendar
1064:    * @see #getDate()
1065:    */
1066:   public void setDate(int date)
1067:   {
1068:     Calendar cal = Calendar.getInstance();
1069:     cal.setTimeInMillis(time);
1070:     cal.set(Calendar.DATE, date);
1071:     time = cal.getTimeInMillis();
1072:   }
1073: 
1074:   /**
1075:    * Returns the day represented by this <code>Date</code>
1076:    * object as an integer between 0 (Sunday) and 6 (Saturday).
1077:    *
1078:    * @return the day represented by this date object.
1079:    * @deprecated Use Calendar instead of Date, and use get(Calendar.DAY_OF_WEEK)
1080:    * instead.
1081:    * @see Calendar
1082:    */
1083:   public int getDay()
1084:   {
1085:     Calendar cal = Calendar.getInstance();
1086:     cal.setTimeInMillis(time);
1087:     // For Calendar, Sunday is 1.  For Date, Sunday is 0.
1088:     return cal.get(Calendar.DAY_OF_WEEK) - 1;
1089:   }
1090: 
1091:   /**
1092:    * Returns the hours represented by this <code>Date</code>
1093:    * object as an integer between 0 and 23.
1094:    *
1095:    * @return the hours represented by this date object.
1096:    * @deprecated Use Calendar instead of Date, and use get(Calendar.HOUR_OF_DAY)
1097:    * instead.
1098:    * @see Calendar
1099:    * @see #setHours(int)
1100:    */
1101:   public int getHours()
1102:   {
1103:     Calendar cal = Calendar.getInstance();
1104:     cal.setTimeInMillis(time);
1105:     return cal.get(Calendar.HOUR_OF_DAY);
1106:   }
1107: 
1108:   /**
1109:    * Sets the hours to the given value.  The other
1110:    * fields are only altered as necessary to match
1111:    * the same date and time in the new hour.  In most
1112:    * cases, the other fields won't change at all.  However,
1113:    * in the case of a leap second, values
1114:    * may be adjusted.  For example,
1115:    * a seconds value of 60 or 61 (a leap second) may result
1116:    * in the seconds value being reset to 0 and the minutes
1117:    * value being incremented by 1 if the new hour does
1118:    * not contain a leap second.
1119:    *
1120:    * @param hours the hours.
1121:    * @deprecated Use Calendar instead of Date, and use
1122:    * set(Calendar.HOUR_OF_DAY, hours) instead.
1123:    * @see Calendar
1124:    * @see #getHours()
1125:    */
1126:   public void setHours(int hours)
1127:   {
1128:     Calendar cal = Calendar.getInstance();
1129:     cal.setTimeInMillis(time);
1130:     cal.set(Calendar.HOUR_OF_DAY, hours);
1131:     time = cal.getTimeInMillis();
1132:   }
1133: 
1134:   /**
1135:    * Returns the number of minutes represented by the <code>Date</code>
1136:    * object, as an integer between 0 and 59.
1137:    *
1138:    * @return the minutes represented by this date object.
1139:    * @deprecated Use Calendar instead of Date, and use get(Calendar.MINUTE)
1140:    * instead.
1141:    * @see Calendar
1142:    * @see #setMinutes(int)
1143:    */
1144:   public int getMinutes()
1145:   {
1146:     Calendar cal = Calendar.getInstance();
1147:     cal.setTimeInMillis(time);
1148:     return cal.get(Calendar.MINUTE);
1149:   }
1150: 
1151:   /**
1152:    * Sets the minutes to the given value.  The other
1153:    * fields are only altered as necessary to match
1154:    * the same date and time in the new minute.  In most
1155:    * cases, the other fields won't change at all.  However,
1156:    * in the case of a leap second, values
1157:    * may be adjusted.  For example,
1158:    * a seconds value of 60 or 61 (a leap second) may result
1159:    * in the seconds value being reset to 0 and the minutes
1160:    * value being incremented by 1 if the new minute does
1161:    * not contain a leap second.
1162:    *
1163:    * @param minutes the minutes.
1164:    * @deprecated Use Calendar instead of Date, and use
1165:    * set(Calendar.MINUTE, minutes) instead.
1166:    * @see Calendar
1167:    * @see #getMinutes()
1168:    */
1169:   public void setMinutes(int minutes)
1170:   {
1171:     Calendar cal = Calendar.getInstance();
1172:     cal.setTimeInMillis(time);
1173:     cal.set(Calendar.MINUTE, minutes);
1174:     time = cal.getTimeInMillis();
1175:   }
1176: 
1177:   /**
1178:    * Returns the number of seconds represented by the <code>Date</code>
1179:    * object, as an integer between 0 and 61 (60 and 61 being leap seconds).
1180:    *
1181:    * @return the seconds represented by this date object.
1182:    * @deprecated Use Calendar instead of Date, and use get(Calendar.SECOND)
1183:    * instead.
1184:    * @see Calendar
1185:    * @see #setSeconds(int)
1186:    */
1187:   public int getSeconds()
1188:   {
1189:     Calendar cal = Calendar.getInstance();
1190:     cal.setTimeInMillis(time);
1191:     return cal.get(Calendar.SECOND);
1192:   }
1193: 
1194:   /**
1195:    * Sets the seconds to the given value.  The other
1196:    * fields are only altered as necessary to match
1197:    * the same date and time in the new minute.  In most
1198:    * cases, the other fields won't change at all.  However,
1199:    * in the case of a leap second, values
1200:    * may be adjusted.  For example, setting the
1201:    * seconds value to 60 or 61 (a leap second) may result
1202:    * in the seconds value being reset to 0 and the minutes
1203:    * value being incremented by 1, if the current time does
1204:    * not contain a leap second.
1205:    *
1206:    * @param seconds the seconds.
1207:    * @deprecated Use Calendar instead of Date, and use
1208:    * set(Calendar.SECOND, seconds) instead.
1209:    * @see Calendar
1210:    * @see #getSeconds()
1211:    */
1212:   public void setSeconds(int seconds)
1213:   {
1214:     Calendar cal = Calendar.getInstance();
1215:     cal.setTimeInMillis(time);
1216:     cal.set(Calendar.SECOND, seconds);
1217:     time = cal.getTimeInMillis();
1218:   }
1219: 
1220:   /**
1221:    * Deserializes a <code>Date</code> object from an
1222:    * input stream, setting the time (in milliseconds
1223:    * since the epoch) to the long value read from the
1224:    * stream.
1225:    *
1226:    * @param input the input stream.
1227:    * @throws IOException if an I/O error occurs in the stream.
1228:    * @throws ClassNotFoundException if the class of the
1229:    *         serialized object could not be found.
1230:    */
1231:   private void readObject(ObjectInputStream input)
1232:     throws IOException, ClassNotFoundException
1233:   {
1234:     input.defaultReadObject();
1235:     time = input.readLong();
1236:   }
1237: 
1238:   /**
1239:    * Serializes a <code>Date</code> object to an output stream,
1240:    * storing the time (in milliseconds since the epoch) as a long
1241:    * value in the stream.
1242:    *
1243:    * @serialdata A long value representing the offset from the epoch
1244:    * in milliseconds.  This is the same value that is returned by the
1245:    * method getTime().
1246:    * @param output the output stream.
1247:    * @throws IOException if an I/O error occurs in the stream.
1248:    */
1249:   private void writeObject(ObjectOutputStream output)
1250:     throws IOException
1251:   {
1252:     output.defaultWriteObject();
1253:     output.writeLong(time);
1254:   }
1255: 
1256: }