Frames | No Frames |
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: }