OSDN Git Service

Add license clarification.
[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 skipParens(String string, int offset)
308   {
309     int len = string.length();
310     int p = 0;
311     int i;
312
313     for (i = offset; i < len; ++i)
314       {
315         if (string.charAt(i) == '(')
316           ++p;
317         else if (string.charAt(i) == ')')
318           {
319             --p;
320             if (p == 0)
321               return i + 1;
322             // If we've encounted unbalanced parens, just return the
323             // leftover one as an ordinary character.  It will be
324             // caught later in parsing and cause an
325             // IllegalArgumentException.
326             if (p < 0)
327               return i;
328           }
329       }
330
331     // Not sure what to do if `p != 0' here.
332     return i;
333   }
334
335   private static int parseTz(String tok, char sign)
336     throws IllegalArgumentException
337   {
338     int num;
339
340     try
341       {
342         // parseInt doesn't handle '+' so strip off sign.
343         num = Integer.parseInt(tok.substring(1));
344       }
345     catch (NumberFormatException ex)
346       {
347         throw new IllegalArgumentException(tok);
348       }
349
350     // Convert hours to minutes.
351     if (num < 24)
352       num *= 60;
353     else
354       num = (num / 100) * 60 + num % 100;
355
356     return sign == '-' ? -num : num;
357   }
358
359   private static int parseMonth(String tok)
360   {
361     // Initialize strings for month names.
362     // We could possibly use the fields of DateFormatSymbols but that is
363     // localized and thus might not match the English words specified.
364     String months[] = { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY",
365                         "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER",
366                         "NOVEMBER", "DECEMBER" };
367
368     int i;
369     for (i = 0; i < 12; i++)
370       if (months[i].startsWith(tok))
371         return i;
372
373     // Return -1 if not found.
374     return -1;
375   }
376
377   private static boolean parseDayOfWeek(String tok)
378   {
379     // Initialize strings for days of the week names.
380     // We could possibly use the fields of DateFormatSymbols but that is
381     // localized and thus might not match the English words specified.
382     String daysOfWeek[] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY",
383                             "THURSDAY", "FRIDAY", "SATURDAY" };
384
385     int i;
386     for (i = 0; i < 7; i++)
387       if (daysOfWeek[i].startsWith(tok))
388         return true;
389
390     return false;
391   }
392
393   /** Parse a String and return the time it represents.
394    * @param s The String to parse.
395    * @deprecated Use DateFormat.parse(String)
396    */
397   public static long parse(String string)
398   {
399     // Initialize date/time fields before parsing begins.
400     int year = -1;
401     int month = -1;
402     int day = -1;
403     int hour = -1;
404     int minute = -1;
405     int second = -1;
406     int timezone = 0;
407     boolean localTimezone = true;
408
409     // Trim out any nested stuff in parentheses now to make parsing easier.
410     StringBuffer buf = new StringBuffer();
411     int off = 0;
412     int openParenOffset, tmpMonth;
413     while ((openParenOffset = string.indexOf('(', off)) >= 0)
414       {
415         // Copy part of string leading up to open paren.
416         buf.append(string.substring(off, openParenOffset));
417         off = skipParens(string, openParenOffset);
418       }
419     buf.append(string.substring(off));
420
421     // Make all chars upper case to simplify comparisons later.
422     // Also ignore commas; treat them as delimiters.
423     StringTokenizer strtok =
424       new StringTokenizer(buf.toString().toUpperCase(), " \t\n\r,");
425
426     while (strtok.hasMoreTokens())
427       {
428         String tok = strtok.nextToken();
429         char firstch = tok.charAt(0);
430         if ((firstch == '+' || firstch == '-') && year >= 0)
431           {
432             timezone = parseTz(tok, firstch);
433             localTimezone = false;
434           }
435         else if (firstch >= '0' && firstch <= '9')
436           {
437             while (tok != null && tok.length() > 0)
438               {
439                 // A colon or slash may be valid in the number.
440                 // Find the first of these before calling parseInt.
441                 int colon = tok.indexOf(':');
442                 int slash = tok.indexOf('/');
443                 int hyphen = tok.indexOf('-');
444                 // We choose tok.length initially because it makes
445                 // processing simpler.
446                 int punctOffset = tok.length();
447                 if (colon >= 0)
448                   punctOffset = Math.min(punctOffset, colon);
449                 if (slash >= 0)
450                   punctOffset = Math.min(punctOffset, slash);
451                 if (hyphen >= 0)
452                   punctOffset = Math.min(punctOffset, hyphen);
453                 // Following code relies on -1 being the exceptional
454                 // case.
455                 if (punctOffset == tok.length())
456                   punctOffset = -1;
457
458                 int num;
459                 try
460                   {
461                     num = Integer.parseInt(punctOffset < 0 ? tok :
462                                            tok.substring(0, punctOffset));
463                   }
464                 catch (NumberFormatException ex)
465                   {
466                     throw new IllegalArgumentException(tok);
467                   }
468
469                 // TBD: Spec says year can be followed by a slash.  That might
470                 // make sense if using YY/MM/DD formats, but it would fail in
471                 // that format for years <= 70.  Also, what about 1900?  That
472                 // is interpreted as the year 3800; seems that the comparison
473                 // should be num >= 1900 rather than just > 1900.
474                 // What about a year of 62 - 70?  (61 or less could be a (leap)
475                 // second).  70/MM/DD cause an exception but 71/MM/DD is ok
476                 // even though there's no ambiguity in either case.
477                 // For the parse method, the spec as written seems too loose.
478                 // Until shown otherwise, we'll follow the spec as written.
479                 if (num > 70 && (punctOffset < 0 || punctOffset == slash))
480                   year = num > 1900 ? num - 1900 : num;
481                 else if (punctOffset > 0 && punctOffset == colon)
482                   {
483                     if (hour < 0)
484                       hour = num;
485                     else
486                       minute = num;
487                   }
488                 else if (punctOffset > 0 && punctOffset == slash)
489                   {
490                     if (month < 0)
491                       month = num - 1;
492                     else
493                       day = num;
494                   }
495                 else if (hour >= 0 && minute < 0)
496                   minute = num;
497                 else if (minute >= 0 && second < 0)
498                   second = num;
499                 else if (day < 0)
500                   day = num;
501                 else
502                   throw new IllegalArgumentException(tok);
503
504                 // Advance string if there's more to process in this token.
505                 if (punctOffset < 0 || punctOffset + 1 >= tok.length())
506                   tok = null;
507                 else
508                   tok = tok.substring(punctOffset + 1);
509               }
510           }
511         else if (firstch >= 'A' && firstch <= 'Z')
512           {
513             if (tok.equals("AM"))
514               {
515                 if (hour < 1 || hour > 12)
516                   throw new IllegalArgumentException(tok);
517                 if (hour == 12)
518                   hour = 0;
519               }
520             else if (tok.equals("PM"))
521               {
522                 if (hour < 1 || hour > 12)
523                   throw new IllegalArgumentException(tok);
524                 if (hour < 12)
525                   hour += 12;
526               }
527             else if (parseDayOfWeek(tok))
528               ; // Ignore it; throw the token away.
529             else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT"))
530               localTimezone = false;
531             else if (tok.startsWith("UT") || tok.startsWith("GMT"))
532               {
533                 int signOffset = 3;
534                 if (tok.charAt(1) == 'T' && tok.charAt(2) != 'C')
535                   signOffset = 2;
536
537                 char sign = tok.charAt(signOffset);
538                 if (sign != '+' && sign != '-')
539                   throw new IllegalArgumentException(tok);
540
541                 timezone = parseTz(tok.substring(signOffset), sign);
542                 localTimezone = false;
543               }
544             else if ((tmpMonth = parseMonth(tok)) >= 0)
545               month = tmpMonth;
546             else if (tok.length() == 3 && tok.charAt(2) == 'T')
547               {
548                 // Convert timezone offset from hours to minutes.
549                 char ch = tok.charAt(0);
550                 if (ch == 'E')
551                   timezone = -5 * 60;
552                 else if (ch == 'C')
553                   timezone = -6 * 60;
554                 else if (ch == 'M')
555                   timezone = -7 * 60;
556                 else if (ch == 'P')
557                   timezone = -8 * 60;
558                 else
559                   throw new IllegalArgumentException(tok);
560
561                 // Shift 60 minutes for Daylight Savings Time.
562                 if (tok.charAt(1) == 'D')
563                   timezone += 60;
564                 else if (tok.charAt(1) != 'S')
565                   throw new IllegalArgumentException(tok);
566
567                 localTimezone = false;
568               }
569             else
570               throw new IllegalArgumentException(tok);
571           }
572         else
573           throw new IllegalArgumentException(tok);
574       }
575
576     // Unspecified minutes and seconds should default to 0.
577     if (minute < 0)
578       minute = 0;
579     if (second < 0)
580       second = 0;
581
582     // Throw exception if any other fields have not been recognized and set.
583     if (year < 0 || month < 0 || day < 0 || hour < 0)
584       throw new IllegalArgumentException("Missing field");
585
586     // Return the time in either local time or relative to GMT as parsed.
587     // If no time-zone was specified, get the local one (in minutes) and
588     // convert to milliseconds before adding to the UTC.
589     return UTC(year, month, day, hour, minute, second) + (localTimezone ?
590                 new Date(year, month, day).getTimezoneOffset() * 60 * 1000:
591                 -timezone * 60 * 1000);
592   }
593
594   /**
595    * @return the year minus 1900 represented by this date object.
596    * @deprecated Use Calendar instead of Date, and use get(Calendar.YEAR)
597    * instead.  Note about the 1900 difference in year.
598    */
599   public int getYear()
600   {
601     Calendar cal = Calendar.getInstance();
602     cal.setTimeInMillis(time);
603     return cal.get(Calendar.YEAR) - 1900;
604   }
605
606   /**
607    * Sets the year to year minus 1900, not changing the other fields.
608    * @param year the year minus 1900.
609    * @deprecated Use Calendar instead of Date, and use
610    * set(Calendar.YEAR, year) instead.  Note about the 1900
611    * difference in year.  
612    */
613   public void setYear(int year)
614   {
615     Calendar cal = Calendar.getInstance();
616     cal.setTimeInMillis(time);
617     cal.set(Calendar.YEAR, 1900 + year);
618     time = cal.getTimeInMillis();
619   }
620
621   /**
622    * @return the month represented by this date object (zero based).
623    * @deprecated Use Calendar instead of Date, and use get(Calendar.MONTH)
624    * instead.
625    */
626   public int getMonth()
627   {
628     Calendar cal = Calendar.getInstance();
629     cal.setTimeInMillis(time);
630     return cal.get(Calendar.MONTH);
631   }
632
633   /**
634    * Sets the month to the given value, not changing the other fields.
635    * @param month the month, zero based.
636    * @deprecated Use Calendar instead of Date, and use
637    * set(Calendar.MONTH, month) instead. 
638    */
639   public void setMonth(int month)
640   {
641     Calendar cal = Calendar.getInstance();
642     cal.setTimeInMillis(time);
643     cal.set(Calendar.MONTH, month);
644     time = cal.getTimeInMillis();
645   }
646
647   /**
648    * @return the day of month represented by this date object.
649    * @deprecated Use Calendar instead of Date, and use get(Calendar.DATE)
650    * instead.
651    */
652   public int getDate()
653   {
654     Calendar cal = Calendar.getInstance();
655     cal.setTimeInMillis(time);
656     return cal.get(Calendar.DATE);
657   }
658
659   /**
660    * Sets the date to the given value, not changing the other fields.
661    * @param date the date.
662    * @deprecated Use Calendar instead of Date, and use
663    * set(Calendar.DATE, date) instead. 
664    */
665   public void setDate(int date)
666   {
667     Calendar cal = Calendar.getInstance();
668     cal.setTimeInMillis(time);
669     cal.set(Calendar.DATE, date);
670     time = cal.getTimeInMillis();
671   }
672
673   /**
674    * @return the day represented by this date object.
675    * @deprecated Use Calendar instead of Date, and use get(Calendar.DAY_OF_WEEK)
676    * instead.
677    */
678   public int getDay()
679   {
680     Calendar cal = Calendar.getInstance();
681     cal.setTimeInMillis(time);
682     // For Calendar, Sunday is 1.  For Date, Sunday is 0.
683     return cal.get(Calendar.DAY_OF_WEEK) - 1;
684   }
685
686   /**
687    * @return the hours represented by this date object.
688    * @deprecated Use Calendar instead of Date, and use get(Calendar.HOUR_OF_DAY)
689    * instead.
690    */
691   public int getHours()
692   {
693     Calendar cal = Calendar.getInstance();
694     cal.setTimeInMillis(time);
695     return cal.get(Calendar.HOUR_OF_DAY);
696   }
697
698   /**
699    * Sets the hours to the given value, not changing the other fields.
700    * @param hours the hours.
701    * @deprecated Use Calendar instead of Date, and use
702    * set(Calendar.HOUR_OF_DAY, hours) instead. 
703    */
704   public void setHours(int hours)
705   {
706     Calendar cal = Calendar.getInstance();
707     cal.setTimeInMillis(time);
708     cal.set(Calendar.HOUR_OF_DAY, hours);
709     time = cal.getTimeInMillis();
710   }
711
712   /**
713    * @return the minutes represented by this date object.
714    * @deprecated Use Calendar instead of Date, and use get(Calendar.MINUTE)
715    * instead.
716    */
717   public int getMinutes()
718   {
719     Calendar cal = Calendar.getInstance();
720     cal.setTimeInMillis(time);
721     return cal.get(Calendar.MINUTE);
722   }
723
724   /**
725    * Sets the minutes to the given value, not changing the other fields.
726    * @param minutes the minutes.
727    * @deprecated Use Calendar instead of Date, and use
728    * set(Calendar.MINUTE, minutes) instead. 
729    */
730   public void setMinutes(int minutes)
731   {
732     Calendar cal = Calendar.getInstance();
733     cal.setTimeInMillis(time);
734     cal.set(Calendar.MINUTE, minutes);
735     time = cal.getTimeInMillis();
736   }
737
738   /**
739    * @return the seconds represented by this date object.
740    * @deprecated Use Calendar instead of Date, and use get(Calendar.SECOND)
741    * instead.
742    */
743   public int getSeconds()
744   {
745     Calendar cal = Calendar.getInstance();
746     cal.setTimeInMillis(time);
747     return cal.get(Calendar.SECOND);
748   }
749
750   /**
751    * Sets the seconds to the given value, not changing the other fields.
752    * @param seconds the seconds.
753    * @deprecated Use Calendar instead of Date, and use
754    * set(Calendar.SECOND, seconds) instead. 
755    */
756   public void setSeconds(int seconds)
757   {
758     Calendar cal = Calendar.getInstance();
759     cal.setTimeInMillis(time);
760     cal.set(Calendar.SECOND, seconds);
761     time = cal.getTimeInMillis();
762   }
763
764   /**
765    * Reads an Object from the stream.
766    */
767   private void readObject(java.io.ObjectInputStream input)
768     throws java.io.IOException, ClassNotFoundException
769   {
770     input.defaultReadObject();
771     time = input.readLong();
772   }
773
774   /**
775    * Writes an Object to the stream.
776    * @serialdata A long value representing the offset from the epoch
777    * in milliseconds.  This is the same value that is returned by the
778    * method getTime().
779    */
780   private void writeObject(java.io.ObjectOutputStream output)
781     throws java.io.IOException
782   {
783     output.defaultWriteObject();
784     output.writeLong(time);
785   }
786 }