OSDN Git Service

2004-05-05 Tom Tromey <tromey@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / util / Date.java
1 /* java.util.Date
2    Copyright (C) 1998, 1999, 2000, 2001 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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package java.util;
40
41 /**
42  * This class represents a specific time in milliseconds since the epoch.
43  * The epoch is 1970, January 1 00:00:00.0000 UTC.  
44  *
45  * Date is intended to reflect universal time coordinate (UTC), but doesn't
46  * handle the leap seconds.
47  *
48  * Prior to jdk 1.1 this class was the sole Time class and had also 
49  * calendar functionality.  But this can't be localized, so a new Calendar
50  * class was created, that you should use instead.  The functions which
51  * get or return a year, month, day etc. are all deprecated and shouldn't be
52  * used.  Use Calendar instead.
53  * 
54  * @see Calendar
55  * @see GregorianCalendar
56  * @see java.text.DateFormat
57  * @author Jochen Hoenicke
58  * @author Per Bothner <bothner@cygnus.com>
59  */
60 public class Date implements Cloneable, Comparable, java.io.Serializable
61 {
62   /**
63    * This is the serialization UID for this class
64    */
65   private static final long serialVersionUID = 7523967970034938905L;
66
67   /**
68    * The time in milliseconds since the epoch.
69    */
70   private transient long time;
71
72   /**
73    * Creates a new Date Object representing the current time.
74    */
75   public Date()
76   {
77     time = System.currentTimeMillis();
78   }
79
80   /**
81    * Creates a new Date Object representing the given time.
82    * @param time the time in milliseconds since the epoch.
83    */
84   public Date(long time)
85   {
86     this.time = time;
87   }
88
89   /**
90    * Creates a new Date Object representing the given time.
91    * @deprecated use <code>new GregorianCalendar(year+1900, month,
92    * day)</code> instead.  
93    */
94   public Date(int year, int month, int day)
95   {
96     time = new GregorianCalendar(year + 1900, month, day).getTimeInMillis();
97   }
98
99   /**
100    * Creates a new Date Object representing the given time.
101    * @deprecated use <code>new GregorianCalendar(year+1900, month,
102    * day, hour, min)</code> instead.  
103    */
104   public Date(int year, int month, int day, int hour, int min)
105   {
106     time =
107       new GregorianCalendar(year + 1900, month, day, hour,
108                             min).getTimeInMillis();
109   }
110
111   /**
112    * Creates a new Date Object representing the given time.
113    * @deprecated use <code>new GregorianCalendar(year+1900, month,
114    * day)</code> instead.  
115    */
116   public Date(int year, int month, int day, int hour, int min, int sec)
117   {
118     time =
119       new GregorianCalendar(year + 1900, month, day, hour, min,
120                             sec).getTimeInMillis();
121   }
122
123   /**
124    * Creates a new Date from the given string representation.  This
125    * does the same as <code>new Date(Date.parse(s))</code>
126    * @see #parse
127    * @deprecated use <code>java.text.DateFormat.parse(s)</code> instead.  
128    */
129   public Date(String s)
130   {
131     time = parse(s);
132   }
133
134   public Object clone()
135   {
136     try
137       {
138         return super.clone();
139       }
140     catch (CloneNotSupportedException ex)
141       {
142         return null;
143       }
144   }
145
146   /**
147    * @deprecated Use Calendar with a UTC TimeZone instead.
148    * @return the time in millis since the epoch.
149    */
150   public static long UTC(int year, int month, int date,
151                          int hrs, int min, int sec)
152   {
153     GregorianCalendar cal =
154       new GregorianCalendar(year + 1900, month, date, hrs, min, sec);
155     cal.set(Calendar.ZONE_OFFSET, 0);
156     cal.set(Calendar.DST_OFFSET, 0);
157     return cal.getTimeInMillis();
158   }
159
160   /**
161    * Gets the time represented by this Object
162    * @return the time in milliseconds since the epoch.
163    */
164   public long getTime()
165   {
166     return time;
167   }
168
169   /**
170    * @deprecated use
171    * Calendar.get(Calendar.ZONE_OFFSET)+Calendar.get(Calendar.DST_OFFSET)
172    * instead.
173    * @return The time zone offset in minutes of the local time zone
174    * relative to UTC.  The time represented by this object is used to
175    * determine if we should use daylight savings.
176    */
177   public int getTimezoneOffset()
178   {
179     Calendar cal = Calendar.getInstance();
180     cal.setTimeInMillis(time);
181     return (cal.get(Calendar.ZONE_OFFSET)
182             + cal.get(Calendar.DST_OFFSET)) / (60 * 1000);
183   }
184
185   /**
186    * Sets the time which this Object should represented.
187    * @param time the time in milliseconds since the epoch.  */
188   public void setTime(long time)
189   {
190     this.time = time;
191   }
192
193   /**
194    * Tests if this date is after the specified date.
195    * @param when the other date
196    * @return true, if the date represented by this Object is
197    * strictly later than the time represented by when.  
198    */
199   public boolean after(Date when)
200   {
201     return time > when.time;
202   }
203
204   /**
205    * Tests if this date is before the specified date.
206    * @param when the other date
207    * @return true, if the date represented by when is strictly later
208    * than the time represented by this object.
209    */
210   public boolean before(Date when)
211   {
212     return time < when.time;
213   }
214
215   /**
216    * Compares two dates for equality.
217    * @param obj the object to compare.
218    * @return true, if obj is a Date object and the date represented
219    * by obj is exactly the same as the time represented by this
220    * object.  
221    */
222   public boolean equals(Object obj)
223   {
224     return (obj instanceof Date && time == ((Date) obj).time);
225   }
226
227   /**
228    * Compares two dates.
229    * @param when the other date.
230    * @return 0, if the date represented
231    * by obj is exactly the same as the time represented by this
232    * object, a negative if this Date is before the other Date, and
233    * a positive value otherwise.  
234    */
235   public int compareTo(Date when)
236   {
237     return (time < when.time) ? -1 : (time == when.time) ? 0 : 1;
238   }
239
240   /**
241    * Compares this Date to another.  This behaves like
242    * <code>compareTo(Date)</code>, but it may throw a
243    * <code>ClassCastException</code>
244    * @param obj the other date.
245    * @return 0, if the date represented
246    * by obj is exactly the same as the time represented by this
247    * object, a negative if this Date is before the other Date, and
248    * a positive value otherwise.  
249    * @exception ClassCastException if obj is not of type Date.
250    */
251   public int compareTo(Object obj)
252   {
253     return compareTo((Date) obj);
254   }
255
256   public int hashCode()
257   {
258     return (int) time ^ (int) (time >>> 32);
259   }
260
261   private static final String[] weekNames = { "Sun", "Mon", "Tue", "Wed",
262                                               "Thu", "Fri", "Sat" };
263
264   private static final String[] monthNames = { "Jan", "Feb", "Mar", "Apr",
265                                                "May", "Jun", "Jul", "Aug",
266                                                "Sep", "Oct", "Nov", "Dec" };
267
268   public String toString()
269   {
270     Calendar cal = Calendar.getInstance();
271     cal.setTimeInMillis(time);
272     String day = "0" + cal.get(Calendar.DATE);
273     String hour = "0" + cal.get(Calendar.HOUR_OF_DAY);
274     String min = "0" + cal.get(Calendar.MINUTE);
275     String sec = "0" + cal.get(Calendar.SECOND);
276     String year = "000" + cal.get(Calendar.YEAR);
277     return weekNames[cal.get(Calendar.DAY_OF_WEEK) - 1] + " "
278       + monthNames[cal.get(Calendar.MONTH)] + " "
279       + day.substring(day.length() - 2) + " "
280       + hour.substring(hour.length() - 2) + ":"
281       + min.substring(min.length() - 2) + ":"
282       + sec.substring(sec.length() - 2) + " "
283       +
284       cal.getTimeZone().getDisplayName(cal.getTimeZone().inDaylightTime(this),
285                                        TimeZone.SHORT) + " " +
286       year.substring(year.length() - 4);
287   }
288
289   /** Format this object in a locale-specific way.
290    * @deprecated Use DateFormat.format(Date)
291    */
292   public String toLocaleString()
293   {
294     return java.text.DateFormat.getInstance().format(this);
295   }
296
297   /** Format this object in a standard format in the GMT timezone.
298    * @deprecated Use DateFormat.format(Date) with a GMT TimeZone.
299    */
300   public String toGMTString()
301   {
302     java.text.DateFormat format = java.text.DateFormat.getInstance();
303     format.setTimeZone(TimeZone.getTimeZone("GMT"));
304     return format.format(this);
305   }
306
307   private static int parseTz(String tok, char sign)
308     throws IllegalArgumentException
309   {
310     int num;
311
312     try
313       {
314         // parseInt doesn't handle '+' so strip off sign.
315         num = Integer.parseInt(tok.substring(1));
316       }
317     catch (NumberFormatException ex)
318       {
319         throw new IllegalArgumentException(tok);
320       }
321
322     // Convert hours to minutes.
323     if (num < 24)
324       num *= 60;
325     else
326       num = (num / 100) * 60 + num % 100;
327
328     return sign == '-' ? -num : num;
329   }
330
331   private static int parseMonth(String tok)
332   {
333     // Initialize strings for month names.
334     // We could possibly use the fields of DateFormatSymbols but that is
335     // localized and thus might not match the English words specified.
336     String months[] = { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY",
337                         "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER",
338                         "NOVEMBER", "DECEMBER" };
339
340     int i;
341     for (i = 0; i < 12; i++)
342       if (months[i].startsWith(tok))
343         return i;
344
345     // Return -1 if not found.
346     return -1;
347   }
348
349   private static boolean parseDayOfWeek(String tok)
350   {
351     // Initialize strings for days of the week names.
352     // We could possibly use the fields of DateFormatSymbols but that is
353     // localized and thus might not match the English words specified.
354     String daysOfWeek[] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
355                             "THURSDAY", "FRIDAY", "SATURDAY" };
356
357     int i;
358     for (i = 0; i < 7; i++)
359       if (daysOfWeek[i].startsWith(tok))
360         return true;
361
362     return false;
363   }
364
365   /** Parse a String and return the time it represents.
366    * @param s The String to parse.
367    * @deprecated Use DateFormat.parse(String)
368    */
369   public static long parse(String string)
370   {
371     // Initialize date/time fields before parsing begins.
372     int year = -1;
373     int month = -1;
374     int day = -1;
375     int hour = -1;
376     int minute = -1;
377     int second = -1;
378     int timezone = 0;
379     boolean localTimezone = true;
380
381     // Trim out any nested stuff in parentheses now to make parsing easier.
382     StringBuffer buf = new StringBuffer();
383     int parenNesting = 0;
384     int len = string.length();
385     for (int i = 0;  i < len;  i++)
386       {
387         char ch = string.charAt(i);
388         if (ch >= 'a' && ch <= 'z')
389           ch -= 'a' - 'A';
390         if (ch == '(')
391           parenNesting++;
392         else if (parenNesting == 0)
393           buf.append(ch);
394         else if (ch == ')')
395           parenNesting--;
396       }
397     int tmpMonth;
398
399     // Make all chars upper case to simplify comparisons later.
400     // Also ignore commas; treat them as delimiters.
401     StringTokenizer strtok = new StringTokenizer(buf.toString(), " \t\n\r,");
402
403     while (strtok.hasMoreTokens())
404       {
405         String tok = strtok.nextToken();
406         char firstch = tok.charAt(0);
407         if ((firstch == '+' || firstch == '-') && year >= 0)
408           {
409             timezone = parseTz(tok, firstch);
410             localTimezone = false;
411           }
412         else if (firstch >= '0' && firstch <= '9')
413           {
414             while (tok != null && tok.length() > 0)
415               {
416                 int punctOffset = tok.length();
417                 int num = 0;
418                 int punct;
419                 for (int i = 0;  ;  i++)
420                   {
421                     if (i >= punctOffset)
422                       {
423                         punct = -1;
424                         break;
425                       }
426                     else
427                       {
428                         punct = tok.charAt(i);
429                         if (punct >= '0' && punct <= '9')
430                           {
431                             if (num > 999999999) // in case of overflow
432                               throw new IllegalArgumentException(tok);
433                             num = 10 * num + (punct - '0');
434                           }
435                         else
436                           {
437                             punctOffset = i;
438                             break;
439                           }
440                       }
441                       
442                   }
443
444                 if (punct == ':')
445                   {
446                     if (hour < 0)
447                       hour = num;
448                     else
449                       minute = num;
450                   }
451                 else if ((num >= 70
452                           && (punct == ' ' || punct == ','
453                               || punct == '/' || punct < 0))
454                          || (num < 70 && day >= 0 && month >= 0 && year < 0))
455                   {
456                     if (num >= 100)
457                       year = num;
458                     else
459                       {
460                         int curYear = 1900 + new Date().getYear();
461                         int firstYear = curYear - 80;
462                         year = firstYear / 100 * 100 + num;
463                         if (year < firstYear)
464                           year += 100;
465                       }
466                   }
467                 else if (punct == '/')
468                   {
469                     if (month < 0)
470                       month = num - 1;
471                     else
472                       day = num;
473                   }
474                 else if (hour >= 0 && minute < 0)
475                   minute = num;
476                 else if (minute >= 0 && second < 0)
477                   second = num;
478                 else if (day < 0)
479                   day = num;
480                 else
481                   throw new IllegalArgumentException(tok);
482
483                 // Advance string if there's more to process in this token.
484                 if (punct < 0 || punctOffset + 1 >= tok.length())
485                   tok = null;
486                 else
487                   tok = tok.substring(punctOffset + 1);
488               }
489           }
490         else if (firstch >= 'A' && firstch <= 'Z')
491           {
492             if (tok.equals("AM"))
493               {
494                 if (hour < 1 || hour > 12)
495                   throw new IllegalArgumentException(tok);
496                 if (hour == 12)
497                   hour = 0;
498               }
499             else if (tok.equals("PM"))
500               {
501                 if (hour < 1 || hour > 12)
502                   throw new IllegalArgumentException(tok);
503                 if (hour < 12)
504                   hour += 12;
505               }
506             else if (parseDayOfWeek(tok))
507               ; // Ignore it; throw the token away.
508             else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT"))
509               localTimezone = false;
510             else if (tok.startsWith("UT") || tok.startsWith("GMT"))
511               {
512                 int signOffset = 3;
513                 if (tok.charAt(1) == 'T' && tok.charAt(2) != 'C')
514                   signOffset = 2;
515
516                 char sign = tok.charAt(signOffset);
517                 if (sign != '+' && sign != '-')
518                   throw new IllegalArgumentException(tok);
519
520                 timezone = parseTz(tok.substring(signOffset), sign);
521                 localTimezone = false;
522               }
523             else if ((tmpMonth = parseMonth(tok)) >= 0)
524               month = tmpMonth;
525             else if (tok.length() == 3 && tok.charAt(2) == 'T')
526               {
527                 // Convert timezone offset from hours to minutes.
528                 char ch = tok.charAt(0);
529                 if (ch == 'E')
530                   timezone = -5 * 60;
531                 else if (ch == 'C')
532                   timezone = -6 * 60;
533                 else if (ch == 'M')
534                   timezone = -7 * 60;
535                 else if (ch == 'P')
536                   timezone = -8 * 60;
537                 else
538                   throw new IllegalArgumentException(tok);
539
540                 // Shift 60 minutes for Daylight Savings Time.
541                 if (tok.charAt(1) == 'D')
542                   timezone += 60;
543                 else if (tok.charAt(1) != 'S')
544                   throw new IllegalArgumentException(tok);
545
546                 localTimezone = false;
547               }
548             else
549               throw new IllegalArgumentException(tok);
550           }
551         else
552           throw new IllegalArgumentException(tok);
553       }
554
555     // Unspecified hours, minutes, or seconds should default to 0.
556     if (hour < 0)
557       hour = 0;
558     if (minute < 0)
559       minute = 0;
560     if (second < 0)
561       second = 0;
562
563     // Throw exception if any other fields have not been recognized and set.
564     if (year < 0 || month < 0 || day < 0)
565       throw new IllegalArgumentException("Missing field");
566
567     // Return the time in either local time or relative to GMT as parsed.
568     // If no time-zone was specified, get the local one (in minutes) and
569     // convert to milliseconds before adding to the UTC.
570     GregorianCalendar cal
571       = new GregorianCalendar(year, month, day, hour, minute, second);
572     if (!localTimezone)
573       {
574         cal.set(Calendar.ZONE_OFFSET, timezone * 60 * 1000);
575         cal.set(Calendar.DST_OFFSET, 0);
576       }
577     return cal.getTimeInMillis();
578   }
579
580   /**
581    * @return the year minus 1900 represented by this date object.
582    * @deprecated Use Calendar instead of Date, and use get(Calendar.YEAR)
583    * instead.  Note about the 1900 difference in year.
584    */
585   public int getYear()
586   {
587     Calendar cal = Calendar.getInstance();
588     cal.setTimeInMillis(time);
589     return cal.get(Calendar.YEAR) - 1900;
590   }
591
592   /**
593    * Sets the year to year minus 1900, not changing the other fields.
594    * @param year the year minus 1900.
595    * @deprecated Use Calendar instead of Date, and use
596    * set(Calendar.YEAR, year) instead.  Note about the 1900
597    * difference in year.  
598    */
599   public void setYear(int year)
600   {
601     Calendar cal = Calendar.getInstance();
602     cal.setTimeInMillis(time);
603     cal.set(Calendar.YEAR, 1900 + year);
604     time = cal.getTimeInMillis();
605   }
606
607   /**
608    * @return the month represented by this date object (zero based).
609    * @deprecated Use Calendar instead of Date, and use get(Calendar.MONTH)
610    * instead.
611    */
612   public int getMonth()
613   {
614     Calendar cal = Calendar.getInstance();
615     cal.setTimeInMillis(time);
616     return cal.get(Calendar.MONTH);
617   }
618
619   /**
620    * Sets the month to the given value, not changing the other fields.
621    * @param month the month, zero based.
622    * @deprecated Use Calendar instead of Date, and use
623    * set(Calendar.MONTH, month) instead. 
624    */
625   public void setMonth(int month)
626   {
627     Calendar cal = Calendar.getInstance();
628     cal.setTimeInMillis(time);
629     cal.set(Calendar.MONTH, month);
630     time = cal.getTimeInMillis();
631   }
632
633   /**
634    * @return the day of month represented by this date object.
635    * @deprecated Use Calendar instead of Date, and use get(Calendar.DATE)
636    * instead.
637    */
638   public int getDate()
639   {
640     Calendar cal = Calendar.getInstance();
641     cal.setTimeInMillis(time);
642     return cal.get(Calendar.DATE);
643   }
644
645   /**
646    * Sets the date to the given value, not changing the other fields.
647    * @param date the date.
648    * @deprecated Use Calendar instead of Date, and use
649    * set(Calendar.DATE, date) instead. 
650    */
651   public void setDate(int date)
652   {
653     Calendar cal = Calendar.getInstance();
654     cal.setTimeInMillis(time);
655     cal.set(Calendar.DATE, date);
656     time = cal.getTimeInMillis();
657   }
658
659   /**
660    * @return the day represented by this date object.
661    * @deprecated Use Calendar instead of Date, and use get(Calendar.DAY_OF_WEEK)
662    * instead.
663    */
664   public int getDay()
665   {
666     Calendar cal = Calendar.getInstance();
667     cal.setTimeInMillis(time);
668     // For Calendar, Sunday is 1.  For Date, Sunday is 0.
669     return cal.get(Calendar.DAY_OF_WEEK) - 1;
670   }
671
672   /**
673    * @return the hours represented by this date object.
674    * @deprecated Use Calendar instead of Date, and use get(Calendar.HOUR_OF_DAY)
675    * instead.
676    */
677   public int getHours()
678   {
679     Calendar cal = Calendar.getInstance();
680     cal.setTimeInMillis(time);
681     return cal.get(Calendar.HOUR_OF_DAY);
682   }
683
684   /**
685    * Sets the hours to the given value, not changing the other fields.
686    * @param hours the hours.
687    * @deprecated Use Calendar instead of Date, and use
688    * set(Calendar.HOUR_OF_DAY, hours) instead. 
689    */
690   public void setHours(int hours)
691   {
692     Calendar cal = Calendar.getInstance();
693     cal.setTimeInMillis(time);
694     cal.set(Calendar.HOUR_OF_DAY, hours);
695     time = cal.getTimeInMillis();
696   }
697
698   /**
699    * @return the minutes represented by this date object.
700    * @deprecated Use Calendar instead of Date, and use get(Calendar.MINUTE)
701    * instead.
702    */
703   public int getMinutes()
704   {
705     Calendar cal = Calendar.getInstance();
706     cal.setTimeInMillis(time);
707     return cal.get(Calendar.MINUTE);
708   }
709
710   /**
711    * Sets the minutes to the given value, not changing the other fields.
712    * @param minutes the minutes.
713    * @deprecated Use Calendar instead of Date, and use
714    * set(Calendar.MINUTE, minutes) instead. 
715    */
716   public void setMinutes(int minutes)
717   {
718     Calendar cal = Calendar.getInstance();
719     cal.setTimeInMillis(time);
720     cal.set(Calendar.MINUTE, minutes);
721     time = cal.getTimeInMillis();
722   }
723
724   /**
725    * @return the seconds represented by this date object.
726    * @deprecated Use Calendar instead of Date, and use get(Calendar.SECOND)
727    * instead.
728    */
729   public int getSeconds()
730   {
731     Calendar cal = Calendar.getInstance();
732     cal.setTimeInMillis(time);
733     return cal.get(Calendar.SECOND);
734   }
735
736   /**
737    * Sets the seconds to the given value, not changing the other fields.
738    * @param seconds the seconds.
739    * @deprecated Use Calendar instead of Date, and use
740    * set(Calendar.SECOND, seconds) instead. 
741    */
742   public void setSeconds(int seconds)
743   {
744     Calendar cal = Calendar.getInstance();
745     cal.setTimeInMillis(time);
746     cal.set(Calendar.SECOND, seconds);
747     time = cal.getTimeInMillis();
748   }
749
750   /**
751    * Reads an Object from the stream.
752    */
753   private void readObject(java.io.ObjectInputStream input)
754     throws java.io.IOException, ClassNotFoundException
755   {
756     input.defaultReadObject();
757     time = input.readLong();
758   }
759
760   /**
761    * Writes an Object to the stream.
762    * @serialdata A long value representing the offset from the epoch
763    * in milliseconds.  This is the same value that is returned by the
764    * method getTime().
765    */
766   private void writeObject(java.io.ObjectOutputStream output)
767     throws java.io.IOException
768   {
769     output.defaultWriteObject();
770     output.writeLong(time);
771   }
772 }