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