OSDN Git Service

c25b503dcde3ae3388c463ac791413eddf15ad12
[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                         int yx = year;
464                         if (year < firstYear)
465                           year += 100;
466                       }
467                   }
468                 else if (punct == '/')
469                   {
470                     if (month < 0)
471                       month = num - 1;
472                     else
473                       day = num;
474                   }
475                 else if (hour >= 0 && minute < 0)
476                   minute = num;
477                 else if (minute >= 0 && second < 0)
478                   second = num;
479                 else if (day < 0)
480                   day = num;
481                 else
482                   throw new IllegalArgumentException(tok);
483
484                 // Advance string if there's more to process in this token.
485                 if (punct < 0 || punctOffset + 1 >= tok.length())
486                   tok = null;
487                 else
488                   tok = tok.substring(punctOffset + 1);
489               }
490           }
491         else if (firstch >= 'A' && firstch <= 'Z')
492           {
493             if (tok.equals("AM"))
494               {
495                 if (hour < 1 || hour > 12)
496                   throw new IllegalArgumentException(tok);
497                 if (hour == 12)
498                   hour = 0;
499               }
500             else if (tok.equals("PM"))
501               {
502                 if (hour < 1 || hour > 12)
503                   throw new IllegalArgumentException(tok);
504                 if (hour < 12)
505                   hour += 12;
506               }
507             else if (parseDayOfWeek(tok))
508               ; // Ignore it; throw the token away.
509             else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT"))
510               localTimezone = false;
511             else if (tok.startsWith("UT") || tok.startsWith("GMT"))
512               {
513                 int signOffset = 3;
514                 if (tok.charAt(1) == 'T' && tok.charAt(2) != 'C')
515                   signOffset = 2;
516
517                 char sign = tok.charAt(signOffset);
518                 if (sign != '+' && sign != '-')
519                   throw new IllegalArgumentException(tok);
520
521                 timezone = parseTz(tok.substring(signOffset), sign);
522                 localTimezone = false;
523               }
524             else if ((tmpMonth = parseMonth(tok)) >= 0)
525               month = tmpMonth;
526             else if (tok.length() == 3 && tok.charAt(2) == 'T')
527               {
528                 // Convert timezone offset from hours to minutes.
529                 char ch = tok.charAt(0);
530                 if (ch == 'E')
531                   timezone = -5 * 60;
532                 else if (ch == 'C')
533                   timezone = -6 * 60;
534                 else if (ch == 'M')
535                   timezone = -7 * 60;
536                 else if (ch == 'P')
537                   timezone = -8 * 60;
538                 else
539                   throw new IllegalArgumentException(tok);
540
541                 // Shift 60 minutes for Daylight Savings Time.
542                 if (tok.charAt(1) == 'D')
543                   timezone += 60;
544                 else if (tok.charAt(1) != 'S')
545                   throw new IllegalArgumentException(tok);
546
547                 localTimezone = false;
548               }
549             else
550               throw new IllegalArgumentException(tok);
551           }
552         else
553           throw new IllegalArgumentException(tok);
554       }
555
556     // Unspecified hours, minutes, or seconds should default to 0.
557     if (hour < 0)
558       hour = 0;
559     if (minute < 0)
560       minute = 0;
561     if (second < 0)
562       second = 0;
563
564     // Throw exception if any other fields have not been recognized and set.
565     if (year < 0 || month < 0 || day < 0)
566       throw new IllegalArgumentException("Missing field");
567
568     // Return the time in either local time or relative to GMT as parsed.
569     // If no time-zone was specified, get the local one (in minutes) and
570     // convert to milliseconds before adding to the UTC.
571     GregorianCalendar cal
572       = new GregorianCalendar(year, month, day, hour, minute, second);
573     if (!localTimezone)
574       {
575         cal.set(Calendar.ZONE_OFFSET, timezone * 60 * 1000);
576         cal.set(Calendar.DST_OFFSET, 0);
577       }
578     return cal.getTimeInMillis();
579   }
580
581   /**
582    * @return the year minus 1900 represented by this date object.
583    * @deprecated Use Calendar instead of Date, and use get(Calendar.YEAR)
584    * instead.  Note about the 1900 difference in year.
585    */
586   public int getYear()
587   {
588     Calendar cal = Calendar.getInstance();
589     cal.setTimeInMillis(time);
590     return cal.get(Calendar.YEAR) - 1900;
591   }
592
593   /**
594    * Sets the year to year minus 1900, not changing the other fields.
595    * @param year the year minus 1900.
596    * @deprecated Use Calendar instead of Date, and use
597    * set(Calendar.YEAR, year) instead.  Note about the 1900
598    * difference in year.  
599    */
600   public void setYear(int year)
601   {
602     Calendar cal = Calendar.getInstance();
603     cal.setTimeInMillis(time);
604     cal.set(Calendar.YEAR, 1900 + year);
605     time = cal.getTimeInMillis();
606   }
607
608   /**
609    * @return the month represented by this date object (zero based).
610    * @deprecated Use Calendar instead of Date, and use get(Calendar.MONTH)
611    * instead.
612    */
613   public int getMonth()
614   {
615     Calendar cal = Calendar.getInstance();
616     cal.setTimeInMillis(time);
617     return cal.get(Calendar.MONTH);
618   }
619
620   /**
621    * Sets the month to the given value, not changing the other fields.
622    * @param month the month, zero based.
623    * @deprecated Use Calendar instead of Date, and use
624    * set(Calendar.MONTH, month) instead. 
625    */
626   public void setMonth(int month)
627   {
628     Calendar cal = Calendar.getInstance();
629     cal.setTimeInMillis(time);
630     cal.set(Calendar.MONTH, month);
631     time = cal.getTimeInMillis();
632   }
633
634   /**
635    * @return the day of month represented by this date object.
636    * @deprecated Use Calendar instead of Date, and use get(Calendar.DATE)
637    * instead.
638    */
639   public int getDate()
640   {
641     Calendar cal = Calendar.getInstance();
642     cal.setTimeInMillis(time);
643     return cal.get(Calendar.DATE);
644   }
645
646   /**
647    * Sets the date to the given value, not changing the other fields.
648    * @param date the date.
649    * @deprecated Use Calendar instead of Date, and use
650    * set(Calendar.DATE, date) instead. 
651    */
652   public void setDate(int date)
653   {
654     Calendar cal = Calendar.getInstance();
655     cal.setTimeInMillis(time);
656     cal.set(Calendar.DATE, date);
657     time = cal.getTimeInMillis();
658   }
659
660   /**
661    * @return the day represented by this date object.
662    * @deprecated Use Calendar instead of Date, and use get(Calendar.DAY_OF_WEEK)
663    * instead.
664    */
665   public int getDay()
666   {
667     Calendar cal = Calendar.getInstance();
668     cal.setTimeInMillis(time);
669     // For Calendar, Sunday is 1.  For Date, Sunday is 0.
670     return cal.get(Calendar.DAY_OF_WEEK) - 1;
671   }
672
673   /**
674    * @return the hours represented by this date object.
675    * @deprecated Use Calendar instead of Date, and use get(Calendar.HOUR_OF_DAY)
676    * instead.
677    */
678   public int getHours()
679   {
680     Calendar cal = Calendar.getInstance();
681     cal.setTimeInMillis(time);
682     return cal.get(Calendar.HOUR_OF_DAY);
683   }
684
685   /**
686    * Sets the hours to the given value, not changing the other fields.
687    * @param hours the hours.
688    * @deprecated Use Calendar instead of Date, and use
689    * set(Calendar.HOUR_OF_DAY, hours) instead. 
690    */
691   public void setHours(int hours)
692   {
693     Calendar cal = Calendar.getInstance();
694     cal.setTimeInMillis(time);
695     cal.set(Calendar.HOUR_OF_DAY, hours);
696     time = cal.getTimeInMillis();
697   }
698
699   /**
700    * @return the minutes represented by this date object.
701    * @deprecated Use Calendar instead of Date, and use get(Calendar.MINUTE)
702    * instead.
703    */
704   public int getMinutes()
705   {
706     Calendar cal = Calendar.getInstance();
707     cal.setTimeInMillis(time);
708     return cal.get(Calendar.MINUTE);
709   }
710
711   /**
712    * Sets the minutes to the given value, not changing the other fields.
713    * @param minutes the minutes.
714    * @deprecated Use Calendar instead of Date, and use
715    * set(Calendar.MINUTE, minutes) instead. 
716    */
717   public void setMinutes(int minutes)
718   {
719     Calendar cal = Calendar.getInstance();
720     cal.setTimeInMillis(time);
721     cal.set(Calendar.MINUTE, minutes);
722     time = cal.getTimeInMillis();
723   }
724
725   /**
726    * @return the seconds represented by this date object.
727    * @deprecated Use Calendar instead of Date, and use get(Calendar.SECOND)
728    * instead.
729    */
730   public int getSeconds()
731   {
732     Calendar cal = Calendar.getInstance();
733     cal.setTimeInMillis(time);
734     return cal.get(Calendar.SECOND);
735   }
736
737   /**
738    * Sets the seconds to the given value, not changing the other fields.
739    * @param seconds the seconds.
740    * @deprecated Use Calendar instead of Date, and use
741    * set(Calendar.SECOND, seconds) instead. 
742    */
743   public void setSeconds(int seconds)
744   {
745     Calendar cal = Calendar.getInstance();
746     cal.setTimeInMillis(time);
747     cal.set(Calendar.SECOND, seconds);
748     time = cal.getTimeInMillis();
749   }
750
751   /**
752    * Reads an Object from the stream.
753    */
754   private void readObject(java.io.ObjectInputStream input)
755     throws java.io.IOException, ClassNotFoundException
756   {
757     input.defaultReadObject();
758     time = input.readLong();
759   }
760
761   /**
762    * Writes an Object to the stream.
763    * @serialdata A long value representing the offset from the epoch
764    * in milliseconds.  This is the same value that is returned by the
765    * method getTime().
766    */
767   private void writeObject(java.io.ObjectOutputStream output)
768     throws java.io.IOException
769   {
770     output.defaultWriteObject();
771     output.writeLong(time);
772   }
773 }