KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > util > QDate


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.util;
31
32 import com.caucho.vfs.WriteStream;
33
34 import java.io.IOException JavaDoc;
35 import java.text.DateFormat JavaDoc;
36 import java.util.Date JavaDoc;
37 import java.util.GregorianCalendar JavaDoc;
38 import java.util.TimeZone JavaDoc;
39 import java.util.logging.Level JavaDoc;
40 import java.util.logging.Logger JavaDoc;
41
42 /**
43  * Resin Date object
44  */

45 public class QDate {
46   private static final Logger JavaDoc log
47     = Logger.getLogger(QDate.class.getName());
48   
49   static final public int YEAR = 0;
50   static final public int MONTH = YEAR + 1;
51   static final public int DAY_OF_MONTH = MONTH + 1;
52   static final public int DAY = DAY_OF_MONTH + 1;
53   static final public int DAY_OF_WEEK = DAY + 1;
54   static final public int HOUR = DAY_OF_WEEK + 1;
55   static final public int MINUTE = HOUR + 1;
56   static final public int SECOND = MINUTE + 1;
57   static final public int MILLISECOND = SECOND + 1;
58   static final public int TIME = MILLISECOND + 1;
59   static final public int TIME_ZONE = TIME + 1;
60
61   static final long MS_PER_DAY = 24 * 60 * 60 * 1000L;
62   static final long MS_PER_EON = MS_PER_DAY * (365 * 400 + 100 - 3);
63
64   static final int []DAYS_IN_MONTH = {
65     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
66   };
67
68   static final String JavaDoc []DAY_NAMES = {
69     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
70   };
71   static final String JavaDoc []MONTH_NAMES = {
72     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
73     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
74   };
75
76   private static final String JavaDoc []SHORT_WEEKDAY = {
77     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
78   };
79   private static final String JavaDoc []LONG_WEEKDAY = {
80     "Sunday", "Monday", "Tuesday", "Wednesday",
81     "Thursday", "Friday", "Saturday"
82   };
83   private static final String JavaDoc []SHORT_MONTH = {
84     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
85     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
86   };
87   private static final String JavaDoc []LONG_MONTH = {
88     "January", "February", "March", "April", "May", "June",
89     "July", "August", "September", "October", "November", "December",
90   };
91
92   private static TimeZone JavaDoc _localTimeZone = TimeZone.getDefault();
93   private static TimeZone JavaDoc _gmtTimeZone = TimeZone.getTimeZone("GMT");
94
95   private static String JavaDoc _localDstName =
96     _localTimeZone.getDisplayName(true, TimeZone.SHORT);
97   private static String JavaDoc _localStdName =
98     _localTimeZone.getDisplayName(false, TimeZone.SHORT);
99
100   private static String JavaDoc _gmtDstName =
101     _gmtTimeZone.getDisplayName(true, TimeZone.SHORT);
102   private static String JavaDoc _gmtStdName =
103     _gmtTimeZone.getDisplayName(false, TimeZone.SHORT);
104
105   // static dates for the static formatting
106
private static QDate _gmtDate = new QDate(false);
107   private static QDate _localDate = new QDate(true);
108
109   private TimeZone JavaDoc _timeZone;
110
111   private String JavaDoc _dstName;
112   private String JavaDoc _stdName;
113
114   private DateFormat JavaDoc _dateFormat;
115   private Date JavaDoc _date = new Date JavaDoc();
116
117   // All times are local
118
private long _localTimeOfEpoch;
119
120   private long _dayOfEpoch;
121   private long _year;
122   private int _dayOfYear;
123   private long _month;
124   private long _dayOfMonth;
125   private long _hour;
126   private long _minute;
127   private long _second;
128   private long _ms;
129   private boolean _isLeapYear;
130   private long _timeOfDay;
131
132   private boolean _isDaylightTime;
133   private long _zoneOffset;
134   private String JavaDoc _zoneName;
135
136   private long _lastTime;
137   private String JavaDoc _lastDate;
138
139   /**
140    * Creates the date for GMT.
141    */

142   public QDate()
143   {
144     this(_gmtTimeZone);
145   }
146
147   /**
148    * Creates the date form local or GMT.
149    */

150   public QDate(boolean isLocal)
151   {
152     this(isLocal ? _localTimeZone : _gmtTimeZone);
153   }
154
155   /**
156    * Creates the date from local or GMT.
157    */

158   public QDate(TimeZone JavaDoc zone)
159   {
160     _timeZone = zone;
161
162     if (zone == _gmtTimeZone) {
163       _stdName = _gmtStdName;
164       _dstName = _gmtDstName;
165     }
166     else if (zone == _localTimeZone) {
167       _stdName = _localStdName;
168       _dstName = _localDstName;
169     }
170     else {
171       _stdName = _timeZone.getDisplayName(false, TimeZone.SHORT);
172       _dstName = _timeZone.getDisplayName(true, TimeZone.SHORT);
173     }
174
175     setLocalTime(Alarm.getCurrentTime());
176   }
177
178   /**
179    * Creates the date for the local time zone.
180    *
181    * @see #setDate(long, long, long)
182    */

183   public QDate(long year, long month, long dayOfMonth)
184   {
185     this(_localTimeZone);
186     setDate(year, month, dayOfMonth);
187   }
188
189   /**
190    * Creates a local calendar.
191    */

192   public static QDate createLocal()
193   {
194     return new QDate(true);
195   }
196
197   /**
198    * Sets the time in milliseconds since the epoch and calculate
199    * the internal variables.
200    */

201   public void setLocalTime(long time)
202   {
203     // If this is a local time zone date, just set the time
204
if (_timeZone != _gmtTimeZone) {
205       calculateSplit(time);
206     }
207     // If this is a GMT date, convert from local to GMT
208
else {
209       calculateSplit(time - _localTimeZone.getRawOffset());
210
211       try {
212     long offset = _localTimeZone.getOffset(GregorianCalendar.AD,
213                            (int) _year,
214                            (int) _month,
215                            (int) _dayOfMonth + 1,
216                            getDayOfWeek(),
217                            (int) _timeOfDay);
218
219     calculateSplit(time - offset);
220       } catch (Throwable JavaDoc e) {
221     log.log(Level.FINE, e.toString(), e);
222       }
223     }
224   }
225
226   /**
227    * Returns the time in milliseconds since the epoch.
228    */

229   public long getLocalTime()
230   {
231     // If this is a local time zone date, just set the time
232
if (_timeZone != _gmtTimeZone) {
233       return _localTimeOfEpoch;
234     }
235     // If this is a GMT date, convert from local to GMT
236
else {
237       long offset = _localTimeZone.getOffset(GregorianCalendar.AD,
238                                              (int) _year,
239                                              (int) _month,
240                                              (int) _dayOfMonth + 1,
241                                              getDayOfWeek(),
242                                              (int) _timeOfDay);
243
244       return _localTimeOfEpoch + offset;
245     }
246   }
247
248   /**
249    * Sets the time in milliseconds since the epoch and calculate
250    * the internal variables.
251    */

252   public void setGMTTime(long time)
253   {
254     calculateSplit(time + _timeZone.getRawOffset());
255
256     // need to recalculate for daylight time
257
if (_isDaylightTime)
258       calculateSplit(time + _zoneOffset);
259   }
260
261   /**
262    * Returns the time in milliseconds since the epoch.
263    */

264   public long getGMTTime()
265   {
266     return _localTimeOfEpoch - _zoneOffset;
267   }
268
269   /**
270    * Returns the milliseconds since the beginning of the day.
271    */

272   public long getTimeOfDay()
273   {
274     return _timeOfDay;
275   }
276
277   /**
278    * Returns the year.
279    */

280   public int getYear()
281   {
282     return (int) _year;
283   }
284
285   /**
286    * Sets the year, recalculating the time since epoch.
287    */

288   public void setYear(int year)
289   {
290     _year = year;
291
292     calculateJoin();
293     calculateSplit(_localTimeOfEpoch);
294   }
295
296   /**
297    * Returns the month in the year.
298    */

299   public int getMonth()
300   {
301     return (int) _month;
302   }
303
304   /**
305    * Sets the month in the year.
306    */

307   public void setMonth(int month)
308   {
309     _month = month;
310     calculateJoin();
311     calculateSplit(_localTimeOfEpoch);
312   }
313
314   /**
315    * Returns the day of the month, based on 1 for the first of the month.
316    */

317   public int getDayOfMonth()
318   {
319     return (int) _dayOfMonth + 1;
320   }
321
322   /**
323    * sets the day of the month based on 1 for the first of the month.
324    */

325   public void setDayOfMonth(int day)
326   {
327     _dayOfMonth = day - 1;
328     calculateJoin();
329     calculateSplit(_localTimeOfEpoch);
330   }
331
332   /**
333    * Returns the day of the month, based on 1 for the first of the month.
334    */

335   public int getDaysInMonth()
336   {
337     if (_month == 1)
338       return _isLeapYear ? 29 : 28;
339     else
340       return DAYS_IN_MONTH[(int) _month];
341   }
342
343   /**
344    * Returns the day of the week.
345    */

346   public int getDayOfWeek()
347   {
348     return (int) ((_dayOfEpoch % 7) + 11) % 7 + 1;
349   }
350
351   /**
352    * Returns the day of the year, based on 0 for January 1.
353    */

354   public int getDayOfYear()
355   {
356     return (int) _dayOfYear;
357   }
358
359   /**
360    * Returns the hour.
361    */

362   public int getHour()
363   {
364     return (int) _hour;
365   }
366
367   /**
368    * Sets the hour, recalculating the localTimeOfEpoch.
369    */

370   public void setHour(int hour)
371   {
372     _hour = hour;
373
374     calculateJoin();
375     calculateSplit(_localTimeOfEpoch);
376   }
377
378   /**
379    * Returns the minute.
380    */

381   public int getMinute()
382   {
383     return (int) _minute;
384   }
385
386   /**
387    * Sets the minute, recalculating the localTimeOfEpoch.
388    */

389   public void setMinute(int minute)
390   {
391     _minute = minute;
392
393     calculateJoin();
394     calculateSplit(_localTimeOfEpoch);
395   }
396
397   /**
398    * Returns the second.
399    */

400   public int getSecond()
401   {
402     return (int) _second;
403   }
404
405   /**
406    * Sets the second, recalculating the localTimeOfEpoch.
407    */

408   public void setSecond(int second)
409   {
410     _second = second;
411
412     calculateJoin();
413     calculateSplit(_localTimeOfEpoch);
414   }
415
416   /**
417    * Returns the millisecond.
418    */

419   public long getMillisecond()
420   {
421     return _ms;
422   }
423
424   /**
425    * Sets the millisecond, recalculating the localTimeOfEpoch.
426    */

427   public void setMillisecond(long millisecond)
428   {
429     _ms = millisecond;
430
431     calculateJoin();
432     calculateSplit(_localTimeOfEpoch);
433   }
434
435   /**
436    * Returns the time zone offset for that particular day.
437    */

438   public long getZoneOffset()
439   {
440     return _zoneOffset;
441   }
442
443   /**
444    * Returns true for DST
445    */

446   public boolean isDST()
447   {
448     return _isDaylightTime;
449   }
450
451   /**
452    * Returns the current time zone.
453    */

454   public TimeZone JavaDoc getLocalTimeZone()
455   {
456     return _localTimeZone;
457   }
458
459   /**
460    * Returns the week in the year.
461    */

462   public int getWeek()
463   {
464     int newYears = (int) ((_dayOfEpoch - _dayOfYear) % 7 + 11) % 7;
465     int normDay = (_dayOfYear - (7 - newYears) % 7);
466     int week = normDay < 0 ? -1 : normDay / 7;
467     if (newYears <= 3)
468       week++;
469
470     return week;
471   }
472
473   /**
474    * Gets values based on a field.
475    */

476   public long get(int field)
477   {
478     switch (field) {
479     case TIME:
480       return getLocalTime();
481
482     case YEAR:
483       return getYear();
484
485     case MONTH:
486       return getMonth();
487
488     case DAY_OF_MONTH:
489       return getDayOfMonth();
490
491     case DAY:
492       return getDayOfWeek();
493
494     case DAY_OF_WEEK:
495       return getDayOfWeek();
496
497     case HOUR:
498       return getHour();
499
500     case MINUTE:
501       return getMinute();
502
503     case SECOND:
504       return getSecond();
505
506     case MILLISECOND:
507       return getMillisecond();
508
509     case TIME_ZONE:
510       return getZoneOffset() / 1000;
511
512     default:
513       return Long.MAX_VALUE;
514     }
515   }
516
517   /**
518    * Sets values based on a field.
519    */

520   public long set(int field, long value)
521   {
522     switch (field) {
523     case YEAR:
524       setYear((int) value);
525       break;
526
527     case MONTH:
528       setMonth((int) value);
529       break;
530
531     case DAY_OF_MONTH:
532       setDayOfMonth((int) value);
533       break;
534
535     case HOUR:
536       setHour((int) value);
537       break;
538
539     case MINUTE:
540       setMinute((int) value);
541       break;
542
543     case SECOND:
544       setSecond((int) value);
545       break;
546
547     case MILLISECOND:
548       setMillisecond(value);
549       break;
550
551     default:
552       throw new RuntimeException JavaDoc();
553     }
554
555     return _localTimeOfEpoch;
556   }
557
558   /*
559    * Mon, 17 Jan 1994 11:14:55 -0500 (EST)
560    */

561   public String JavaDoc printDate()
562   {
563     if (_lastDate != null && _lastTime == _localTimeOfEpoch)
564       return _lastDate;
565
566     CharBuffer cb = new CharBuffer();
567
568     printDate(cb);
569
570     _lastDate = cb.toString();
571     _lastTime = _localTimeOfEpoch;
572
573     return _lastDate;
574   }
575
576   /*
577    * Mon, 17 Jan 1994 11:14:55 -0500 (EST)
578    */

579   public void printDate(CharBuffer cb)
580   {
581     cb.append(DAY_NAMES[(int) (_dayOfEpoch % 7 + 11) % 7]);
582     cb.append(", ");
583     cb.append((_dayOfMonth + 1) / 10);
584     cb.append((_dayOfMonth + 1) % 10);
585     cb.append(" ");
586     cb.append(MONTH_NAMES[(int) _month]);
587     cb.append(" ");
588     cb.append(_year);
589     cb.append(" ");
590     cb.append((_timeOfDay / 36000000L) % 10);
591     cb.append((_timeOfDay / 3600000L) % 10);
592     cb.append(":");
593     cb.append((_timeOfDay / 600000L) % 6);
594     cb.append((_timeOfDay / 60000L) % 10);
595     cb.append(":");
596     cb.append((_timeOfDay / 10000L) % 6);
597     cb.append((_timeOfDay / 1000L) % 10);
598
599     if (_zoneName == null || _zoneName.equals("GMT")) {
600       cb.append(" GMT");
601       return;
602     }
603
604     long offset = _zoneOffset;
605
606     if (offset < 0) {
607       cb.append(" -");
608       offset = - offset;
609     } else
610       cb.append(" +");
611
612     cb.append((offset / 36000000) % 10);
613     cb.append((offset / 3600000) % 10);
614     cb.append((offset / 600000) % 6);
615     cb.append((offset / 60000) % 10);
616
617     cb.append(" (");
618     cb.append(_zoneName);
619     cb.append(")");
620   }
621
622   /**
623    * Prints the date to a stream.
624    */

625   public void printDate(WriteStream os)
626     throws IOException JavaDoc
627   {
628     os.print(DAY_NAMES[(int) (_dayOfEpoch % 7 + 11) % 7]);
629     os.write(',');
630     os.write(' ');
631     os.print((_dayOfMonth + 1) / 10);
632     os.print((_dayOfMonth + 1) % 10);
633     os.write(' ');
634     os.print(MONTH_NAMES[(int) _month]);
635     os.write(' ');
636     os.print(_year);
637     os.write(' ');
638     os.print((_timeOfDay / 36000000) % 10);
639     os.print((_timeOfDay / 3600000) % 10);
640     os.write(':');
641     os.print((_timeOfDay / 600000) % 6);
642     os.print((_timeOfDay / 60000) % 10);
643     os.write(':');
644     os.print((_timeOfDay / 10000) % 6);
645     os.print((_timeOfDay / 1000) % 10);
646
647     if (_zoneName == null) {
648       os.print(" GMT");
649       return;
650     }
651
652     long offset = _zoneOffset;
653
654     if (offset < 0) {
655       os.write(' ');
656       os.write('-');
657       offset = - offset;
658     } else {
659       os.write(' ');
660       os.write('+');
661     }
662
663     os.print((offset / 36000000) % 10);
664     os.print((offset / 3600000) % 10);
665     os.print((offset / 600000) % 6);
666     os.print((offset / 60000) % 10);
667
668     os.write(' ');
669     os.write('(');
670     os.print(_zoneName);
671     os.write(')');
672   }
673
674   /**
675    * Prints the time in ISO 8601
676    */

677   public String JavaDoc printISO8601()
678   {
679     CharBuffer cb = new CharBuffer();
680
681     if (_year > 0) {
682       cb.append((_year / 1000) % 10);
683       cb.append((_year / 100) % 10);
684       cb.append((_year / 10) % 10);
685       cb.append(_year % 10);
686       cb.append(((_month + 1) / 10) % 10);
687       cb.append((_month + 1) % 10);
688       cb.append(((_dayOfMonth + 1) / 10) % 10);
689       cb.append((_dayOfMonth + 1) % 10);
690     }
691
692     if (_timeOfDay != 0 || _year <= 0) {
693       long time = _timeOfDay / 1000;
694       long ms = _timeOfDay % 1000;
695
696       cb.append("T");
697       cb.append((time / 36000) % 10);
698       cb.append((time / 3600) % 10);
699       if (time % 3600 != 0) {
700     cb.append((time / 600) % 6);
701     cb.append((time / 60) % 10);
702     if (time % 60 != 0) {
703       cb.append((time / 10) % 6);
704       cb.append((time / 1) % 10);
705     }
706       }
707
708       if (ms != 0) {
709     cb.append('.');
710     cb.append((ms / 100) % 10);
711     cb.append((ms / 10) % 10);
712     cb.append(ms % 10);
713       }
714     }
715
716     if (_zoneName == null) {
717       cb.append("Z");
718       return cb.toString();
719     }
720
721     /*
722     long offset = zoneOffset;
723
724     if (offset < 0) {
725       cb.append("-");
726       offset = - offset;
727     } else
728       cb.append("+");
729
730     cb.append((offset / 36000000) % 10);
731     cb.append((offset / 3600000) % 10);
732     cb.append((offset / 600000) % 6);
733     cb.append((offset / 60000) % 10);
734     */

735
736     return cb.toString();
737   }
738
739   /**
740    * Prints just the date component of ISO 8601
741    */

742   public String JavaDoc printISO8601Date()
743   {
744     CharBuffer cb = new CharBuffer();
745
746     if (_year > 0) {
747       cb.append((_year / 1000) % 10);
748       cb.append((_year / 100) % 10);
749       cb.append((_year / 10) % 10);
750       cb.append(_year % 10);
751       cb.append('-');
752       cb.append(((_month + 1) / 10) % 10);
753       cb.append((_month + 1) % 10);
754       cb.append('-');
755       cb.append(((_dayOfMonth + 1) / 10) % 10);
756       cb.append((_dayOfMonth + 1) % 10);
757     }
758
759     return cb.toString();
760   }
761
762   /**
763    * Formats a date.
764    *
765    * @param time the time to format
766    * @param format the format string
767    */

768   public synchronized static String JavaDoc formatGMT(long gmtTime, String JavaDoc format)
769   {
770     _gmtDate.setGMTTime(gmtTime);
771
772     return _gmtDate.format(new CharBuffer(), format).toString();
773   }
774
775   /**
776    * Formats a date, using the default time format.
777    *
778    * @param time the time to format
779    */

780   public synchronized static String JavaDoc formatGMT(long gmtTime)
781   {
782     _gmtDate.setGMTTime(gmtTime);
783
784     return _gmtDate.printDate();
785   }
786
787   /**
788    * Formats a time in the local time zone.
789    *
790    * @param time in milliseconds, GMT, from the epoch.
791    * @param format formatting string.
792    */

793   public synchronized static String JavaDoc formatLocal(long gmtTime, String JavaDoc format)
794   {
795     _localDate.setGMTTime(gmtTime);
796
797     return _localDate.format(new CharBuffer(), format).toString();
798   }
799
800   /**
801    * Formats a time in the local time zone, using the default format.
802    *
803    * @param time in milliseconds, GMT, from the epoch.
804    */

805   public synchronized static String JavaDoc formatLocal(long gmtTime)
806   {
807     _localDate.setGMTTime(gmtTime);
808
809     return _localDate.printDate();
810   }
811
812   /**
813    * Formats a time in the local time zone.
814    *
815    * @param time in milliseconds, GMT, from the epoch.
816    * @param format formatting string.
817    */

818   public synchronized static CharBuffer formatLocal(CharBuffer cb,
819                                                     long gmtTime,
820                                                     String JavaDoc format)
821   {
822     _localDate.setGMTTime(gmtTime);
823
824     return _localDate.format(cb, format);
825   }
826
827   public synchronized static String JavaDoc formatISO8601(long gmtTime)
828   {
829     if (_gmtDate == null)
830       _gmtDate = new QDate();
831
832     _gmtDate.setGMTTime(gmtTime);
833
834     return _gmtDate.printISO8601();
835   }
836
837   /**
838    * Global date must be synchronized before you can do anything on it.
839    */

840   public static QDate getGlobalDate()
841   {
842     return _localDate;
843   }
844
845   /**
846    * Formats the current date.
847    */

848   public String JavaDoc format(String JavaDoc format)
849   {
850     CharBuffer cb = new CharBuffer();
851
852     return format(cb, format).close();
853   }
854
855   /**
856    * Format the date using % escapes:
857    *
858    * <table>
859    * <tr><td>%a<td>day of week (short)
860    * <tr><td>%A<td>day of week (verbose)
861    * <tr><td>%b<td>day of month (short)
862    * <tr><td>%B<td>day of month (verbose)
863    * <tr><td>%c<td>Java locale date
864    * <tr><td>%d<td>day of month (two-digit)
865    * <tr><td>%H<td>24-hour (two-digit)
866    * <tr><td>%I<td>12-hour (two-digit)
867    * <tr><td>%j<td>day of year (three-digit)
868    * <tr><td>%m<td>month (two-digit)
869    * <tr><td>%M<td>minutes
870    * <tr><td>%p<td>am/pm
871    * <tr><td>%S<td>seconds
872    * <tr><td>%s<td>milliseconds
873    * <tr><td>%W<td>week in year (three-digit)
874    * <tr><td>%w<td>day of week (one-digit)
875    * <tr><td>%y<td>year (two-digit)
876    * <tr><td>%Y<td>year (four-digit)
877    * <tr><td>%Z<td>time zone (name)
878    * <tr><td>%z<td>time zone (+/-0800)
879    * </table>
880    */

881   public CharBuffer format(CharBuffer cb, String JavaDoc format)
882   {
883     int length = format.length();
884     for (int i = 0; i < length; i++) {
885       char ch = format.charAt(i);
886       if (ch != '%') {
887     cb.append(ch);
888     continue;
889       }
890
891       switch (format.charAt(++i)) {
892       case 'a':
893     cb.append(SHORT_WEEKDAY[getDayOfWeek() - 1]);
894     break;
895
896       case 'A':
897     cb.append(LONG_WEEKDAY[getDayOfWeek() - 1]);
898     break;
899
900       case 'b':
901     cb.append(SHORT_MONTH[(int) _month]);
902     break;
903
904       case 'B':
905     cb.append(LONG_MONTH[(int) _month]);
906     break;
907
908       case 'c':
909     cb.append(printLocaleDate());
910     break;
911
912       case 'd':
913     cb.append((_dayOfMonth + 1) / 10);
914     cb.append((_dayOfMonth + 1) % 10);
915     break;
916
917       case 'H':
918     int hour = (int) (_timeOfDay / 3600000) % 24;
919     cb.append(hour / 10);
920     cb.append(hour % 10);
921     break;
922
923       case 'I':
924     hour = (int) (_timeOfDay / 3600000) % 12;
925     if (hour == 0)
926       hour = 12;
927     cb.append(hour / 10);
928     cb.append(hour % 10);
929     break;
930
931       case 'j':
932     cb.append((_dayOfYear + 1) / 100);
933     cb.append((_dayOfYear + 1) / 10 % 10);
934     cb.append((_dayOfYear + 1) % 10);
935     break;
936
937       case 'm':
938     cb.append((_month + 1) / 10);
939     cb.append((_month + 1) % 10);
940     break;
941
942       case 'M':
943     cb.append((_timeOfDay / 600000) % 6);
944     cb.append((_timeOfDay / 60000) % 10);
945     break;
946
947       case 'p':
948     hour = (int) (_timeOfDay / 3600000) % 24;
949     if (hour < 12)
950       cb.append("am");
951     else
952       cb.append("pm");
953     break;
954
955       case 'S':
956     cb.append((_timeOfDay / 10000) % 6);
957     cb.append((_timeOfDay / 1000) % 10);
958     break;
959
960       case 's':
961     cb.append((_timeOfDay / 100) % 10);
962     cb.append((_timeOfDay / 10) % 10);
963     cb.append(_timeOfDay % 10);
964     break;
965
966       case 'W':
967     int week = getWeek();
968     cb.append((week + 1) / 10);
969     cb.append((week + 1) % 10);
970     break;
971
972       case 'w':
973     cb.append(getDayOfWeek() - 1);
974     break;
975
976       case 'y':
977     cb.append(_year / 10 % 10);
978     cb.append(_year % 10);
979     break;
980
981       case 'Y':
982     cb.append(_year / 1000 % 10);
983     cb.append(_year / 100 % 10);
984     cb.append(_year / 10 % 10);
985     cb.append(_year % 10);
986     break;
987
988       case 'Z':
989         if (_zoneName == null)
990           cb.append("GMT");
991         else
992           cb.append(_zoneName);
993     break;
994
995       case 'z':
996         long offset = _zoneOffset;
997
998         if (offset < 0) {
999           cb.append("-");
1000          offset = - offset;
1001        }
1002        else
1003          cb.append("+");
1004
1005        cb.append((offset / 36000000) % 10);
1006        cb.append((offset / 3600000) % 10);
1007        cb.append((offset / 600000) % 6);
1008        cb.append((offset / 60000) % 10);
1009    break;
1010
1011      default:
1012    cb.append(format.charAt(i));
1013      }
1014    }
1015
1016    return cb;
1017  }
1018
1019  /*
1020   * XXX: buggy (Because cal is buggy), may have to implement the sdf
1021   */

1022  public String JavaDoc printLocaleDate()
1023  {
1024    _date.setTime(_localTimeOfEpoch);
1025
1026    // SimpleDateFormat sdf = new SimpleDateFormat();
1027
// System.out.println("" + sdf.toPattern());
1028

1029    if (_dateFormat == null)
1030      _dateFormat = DateFormat.getInstance();
1031
1032    return _dateFormat.format(_date);
1033  }
1034
1035  /*
1036   * XXX: okay, this is vile.
1037   * Mon, 17 Jan 1994 11:14:55 -0500 (EST)
1038   *
1039   * In local time
1040   */

1041  public long parseLocalDate(String JavaDoc string) throws Exception JavaDoc
1042  {
1043    long time = parseDate(string);
1044
1045    synchronized (this) {
1046      setLocalTime(time);
1047      return getGMTTime();
1048    }
1049  }
1050
1051  /*
1052   * XXX: okay, this is vile.
1053   * Mon, 17 Jan 1994 11:14:55 -0500 (EST)
1054   *
1055   * In GMT time
1056   */

1057  public long parseDate(String JavaDoc string) throws Exception JavaDoc
1058  {
1059    try {
1060      int i = skipWhitespace(string, 0);
1061
1062      int ch = string.charAt(i);
1063      if (ch >= '0' && ch <= '9' ||
1064      ch == 'T' &&
1065      string.charAt(i + 1) >= '0' && string.charAt(i + 1) <= '9')
1066    return parseISO8601Date(string, i);
1067
1068      CharBuffer cb = new CharBuffer();
1069
1070      i = scan(string, 0, cb, true);
1071      if (cb.length() == 0 || ! Character.isDigit(cb.charAt(0)))
1072    i = scan(string, i, cb, true);
1073
1074      int dayOfMonth = parseInt(cb);
1075      i = scan(string, i, cb, true);
1076      String JavaDoc smonth = cb.toString();
1077      int month;
1078      for (month = 0; month < 12; month++) {
1079    if (MONTH_NAMES[(int) month].equalsIgnoreCase(smonth))
1080      break;
1081      }
1082      if (month == 12) throw new Exception JavaDoc();
1083
1084      i = scan(string, i, cb, true);
1085
1086      int year = parseInt(cb);
1087      if (cb.length() < 3 && year < 50)
1088    year += 2000;
1089      else if (cb.length() < 3 && year < 100)
1090    year += 1900;
1091
1092      i = scan(string, i, cb, false);
1093      long timeOfDay = parseInt(cb) * 3600000;
1094
1095      i = scan(string, i, cb, false);
1096      timeOfDay += parseInt(cb) * 60000;
1097
1098      i = scan(string, i, cb, false);
1099      timeOfDay += parseInt(cb) * 1000;
1100
1101      // XXX: gross hack
1102
if (year <= 1600)
1103    dayOfMonth--;
1104
1105      long time = (MS_PER_DAY * (yearToDayOfEpoch(year) +
1106                 monthToDayOfYear(month, isLeapYear(year)) +
1107                 dayOfMonth - 1) +
1108           timeOfDay);
1109
1110      try {
1111    i = scan(string, i, cb, false);
1112    for (int j = 0; j < cb.length(); j++) {
1113      if ((ch = cb.charAt(j)) == ';' || ch == ' ')
1114        cb.setLength(j);
1115    }
1116
1117    ch = cb.charAt(0);
1118    if (ch == '-' || ch == '+' || ch >= '0' && ch <= '9') {
1119          long zoneOffset;
1120      zoneOffset = parseInt(cb);
1121      zoneOffset = 60000 * (60 * (zoneOffset / 100) + zoneOffset % 100);
1122
1123      time -= zoneOffset;
1124
1125          setGMTTime(time);
1126    } else if (cb.equalsIgnoreCase("gmt") ||
1127           cb.equalsIgnoreCase("utc")) {
1128          setGMTTime(time);
1129    } else {
1130          setLocalTime(time);
1131    }
1132      } catch (Exception JavaDoc e) {
1133      }
1134
1135      return _localTimeOfEpoch - _zoneOffset;
1136    } catch (Exception JavaDoc e) {
1137      return Long.MAX_VALUE;
1138    }
1139  }
1140
1141  private long parseISO8601Date(String JavaDoc string, int pos)
1142    throws Exception JavaDoc
1143  {
1144    int length = string.length();
1145    int year = 0;
1146    int i;
1147
1148    char ch = string.charAt(pos);
1149
1150    if ('0' <= ch && ch <= '9') {
1151      year = scanISOInt(string, pos, length, 4);
1152      pos += 4;
1153    }
1154
1155    if (pos < length && string.charAt(pos) == '-')
1156      pos++;
1157
1158    int month = 0;
1159    if (pos < length && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
1160      month = scanISOInt(string, pos, length, 2);
1161      month--;
1162      pos += 2;
1163    } else if (ch == 'W')
1164      return Long.MAX_VALUE;
1165
1166    if (pos < length && string.charAt(pos) == '-')
1167      pos++;
1168
1169    int day = 0;
1170    if (pos < length && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
1171      day = scanISOInt(string, pos, length, 2);
1172      day--;
1173      pos += 2;
1174    }
1175
1176    int hour = 0;
1177    int minute = 0;
1178    int second = 0;
1179    if (pos < length && string.charAt(pos) == 'T') {
1180      pos++;
1181
1182      if (pos < length && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
1183    hour = scanISOInt(string, pos, length, 2);
1184    pos += 2;
1185      }
1186
1187      if (pos < length && string.charAt(pos) == ':')
1188    pos++;
1189
1190      if (pos < length && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
1191    minute = scanISOInt(string, pos, length, 2);
1192    pos += 2;
1193      }
1194
1195      if (pos < length && string.charAt(pos) == ':')
1196    pos++;
1197
1198      if (pos < length && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
1199    second = scanISOInt(string, pos, length, 2);
1200    pos += 2;
1201      }
1202    }
1203
1204    long timeOfDay = 1000 * (second + 60 * (minute + 60 * hour));
1205
1206    // XXX: gross hack
1207
if (year <= 1600)
1208      day--;
1209
1210    long time = (MS_PER_DAY * (yearToDayOfEpoch(year) +
1211                   monthToDayOfYear(month, isLeapYear(year)) +
1212                   day) +
1213         timeOfDay);
1214
1215    if (pos >= length) {
1216      setLocalTime(time);
1217      return _localTimeOfEpoch;
1218    }
1219
1220    if (string.charAt(pos) == 'Z') {
1221      pos++;
1222    }
1223
1224    else if (string.charAt(pos) == '-' || string.charAt(pos) == '+') {
1225      int sign = 1;
1226      if (string.charAt(pos) == '-')
1227    sign = -1;
1228
1229      pos++;
1230      int tzHour = scanISOInt(string, pos, length, 2);
1231      pos += 2;
1232      int tzMinute = 0;
1233
1234      if (pos < length && string.charAt(pos) == ':')
1235    pos++;
1236      if (pos < length && '0' <= (ch = string.charAt(pos)) && ch <= '9') {
1237    tzMinute = scanISOInt(string, pos, length, 2);
1238    pos += 2;
1239      }
1240
1241      time += sign * 1000 * (60 * (tzMinute + 60 * tzHour));
1242    }
1243
1244    else {
1245      setLocalTime(time);
1246      return _localTimeOfEpoch;
1247    }
1248
1249    pos = skipWhitespace(string, pos);
1250    if (pos < length)
1251      throw new Exception JavaDoc("extra junk at end of ISO date");
1252
1253    setGMTTime(time);
1254
1255    return _localTimeOfEpoch;
1256  }
1257
1258  /**
1259   * Based on the year, return the number of days since the epoch.
1260   */

1261  private long yearToDayOfEpoch(long year)
1262  {
1263    if (year > 0) {
1264      year -= 1601;
1265      return (365 * year + year / 4 - year / 100 + year / 400 -
1266          ((1970 - 1601) * 365 + (1970 - 1601) / 4 - 3));
1267    } else {
1268      year = 2000 - year;
1269
1270      return ((2000 - 1970) * 365 + (2000 - 1970) / 4 -
1271          (365 * year + year / 4 - year / 100 + year / 400));
1272    }
1273  }
1274
1275  /**
1276   * Calculates the day of the year for the beginning of the month.
1277   */

1278  private long monthToDayOfYear(long month, boolean isLeapYear)
1279  {
1280    long day = 0;
1281
1282    for (int i = 0; i < month && i < 12; i++) {
1283      day += DAYS_IN_MONTH[i];
1284      if (i == 1 && isLeapYear)
1285    day++;
1286    }
1287
1288    return day;
1289  }
1290
1291  /**
1292   * Returns true if the given year is a leap year.
1293   */

1294  private boolean isLeapYear(long year)
1295  {
1296    return ! ((_year % 4) != 0 || (_year % 100) == 0 && (_year % 400) != 0);
1297  }
1298
1299  private int scanISOInt(String JavaDoc string, int pos, int length, int digits)
1300    throws Exception JavaDoc
1301  {
1302    int value = 0;
1303    for (int i = 0; i < digits; i++) {
1304      if (pos >= length)
1305    throw new Exception JavaDoc("expected ISO8601 digit");
1306      char ch = string.charAt(pos++);
1307      if ('0' <= ch && ch <= '9')
1308    value = 10 * value + ch - '0';
1309      else
1310    throw new Exception JavaDoc("expected ISO8601 digit");
1311    }
1312
1313    return value;
1314  }
1315
1316  private int skipWhitespace(String JavaDoc string, int i)
1317  {
1318    char ch;
1319    for (; i < string.length() &&
1320       ((ch = string.charAt(i)) == ' ' || ch == '\t' ||
1321        ch == '\n' || ch == '\r');
1322     i++) {
1323    }
1324
1325    return i;
1326  }
1327
1328  /*
1329   * Scan to whitespace or ':'
1330   */

1331  private int scan(String JavaDoc string, int i, CharBuffer cb, boolean dash)
1332    throws Exception JavaDoc
1333  {
1334    char ch;
1335
1336    cb.setLength(0);
1337
1338    for (; i < string.length(); i++) {
1339      if (! Character.isWhitespace(ch = string.charAt(i)) &&
1340      (ch != ':' && (! dash || ch != '-')))
1341    break;
1342    }
1343
1344    for (; i < string.length(); i++) {
1345      if (! Character.isWhitespace(ch = string.charAt(i)) &&
1346      (ch != ':' && (! dash || ch != '-')))
1347    cb.append((char) ch);
1348      else
1349    break;
1350    }
1351
1352    if (cb.length() == 0)
1353      throw new Exception JavaDoc();
1354
1355    return i;
1356  }
1357
1358  private int parseInt(CharBuffer cb) throws Exception JavaDoc
1359  {
1360    int value = 0;
1361    int sign = 1;
1362
1363    for (int i = 0; i < cb.length(); i++) {
1364      int ch = cb.charAt(i);
1365      if (i == 0 && ch == '-')
1366    sign = -1;
1367      else if (i == 0 && ch == '+') {
1368      }
1369      else if (ch >= '0' && ch <= '9')
1370    value = 10 * value + ch - '0';
1371      else
1372    throw new Exception JavaDoc();
1373    }
1374
1375    return sign * value;
1376  }
1377
1378  /**
1379   * Sets date in the local time.
1380   *
1381   * @param year
1382   * @param month where January = 0
1383   * @param day day of month where the 1st = 1
1384   */

1385  public long setDate(long year, long month, long day)
1386  {
1387    year += (long) Math.floor(month / 12.0);
1388    month -= (long) 12 * Math.floor(month / 12.0);
1389
1390    _year = year;
1391    _month = month;
1392    _dayOfMonth = day - 1;
1393
1394    calculateJoin();
1395    calculateSplit(_localTimeOfEpoch);
1396
1397    return _localTimeOfEpoch;
1398  }
1399
1400  public long setTime(long hour, long minute, long second, long ms)
1401  {
1402    _hour = hour;
1403    _minute = minute;
1404    _second = second;
1405    _ms = ms;
1406
1407    calculateJoin();
1408    calculateSplit(_localTimeOfEpoch);
1409
1410    return _localTimeOfEpoch;
1411  }
1412
1413  /**
1414   * Calculate and set the calendar components based on the given time.
1415   *
1416   * @param localTime local time in milliseconds since the epoch
1417   */

1418  private void calculateSplit(long localTime)
1419  {
1420    _localTimeOfEpoch = localTime;
1421    _dayOfEpoch = divFloor(_localTimeOfEpoch, MS_PER_DAY);
1422    _timeOfDay = _localTimeOfEpoch - MS_PER_DAY * _dayOfEpoch;
1423
1424    calculateYear();
1425    calculateMonth();
1426
1427    _hour = _timeOfDay / 3600000;
1428    _minute = _timeOfDay / 60000 % 60;
1429    _second = _timeOfDay / 1000 % 60;
1430    _ms = _timeOfDay % 1000;
1431
1432    if (_timeZone == _gmtTimeZone) {
1433      _isDaylightTime = false;
1434      _zoneName = _stdName;
1435    }
1436    else {
1437      _zoneOffset = _timeZone.getOffset(GregorianCalendar.AD,
1438                    (int) _year,
1439                    (int) _month,
1440                    (int) _dayOfMonth + 1,
1441                    getDayOfWeek(),
1442                    (int) _timeOfDay);
1443
1444      if (_zoneOffset == _timeZone.getRawOffset()) {
1445    _isDaylightTime = false;
1446    _zoneName = _stdName;
1447      }
1448      else {
1449    _isDaylightTime = true;
1450    _zoneName = _dstName;
1451      }
1452    }
1453  }
1454
1455  /**
1456   * Calculates the year, the dayOfYear and whether this is a leap year
1457   * from the current days since the epoch.
1458   */

1459  private void calculateYear()
1460  {
1461    long days = _dayOfEpoch;
1462
1463    // shift to using 1601 as a base
1464
days += (1970 - 1601) * 365 + (1970 - 1601) / 4 - 3;
1465
1466    long n400 = divFloor(days, 400 * 365 + 100 - 3);
1467    days -= n400 * (400 * 365 + 100 - 3);
1468
1469    long n100 = divFloor(days, 100 * 365 + 25 - 1);
1470    if (n100 == 4)
1471      n100 = 3;
1472    days -= n100 * (100 * 365 + 25 - 1);
1473
1474    long n4 = divFloor(days, 4 * 365 + 1);
1475    if (n4 == 25)
1476      n4 = 24;
1477    days -= n4 * (4 * 365 + 1);
1478
1479    long n1 = divFloor(days, 365);
1480    if (n1 == 4)
1481      n1 = 3;
1482
1483    _year = 400 * n400 + 100 * n100 + 4 * n4 + n1 + 1601;
1484    _dayOfYear = (int) (days - 365 * n1);
1485
1486    _isLeapYear = isLeapYear(_year);
1487  }
1488
1489  public boolean isLeapYear()
1490  {
1491    return _isLeapYear;
1492  }
1493
1494  /**
1495   * Calculates the month based on the day of the year.
1496   */

1497  private void calculateMonth()
1498  {
1499    _dayOfMonth = _dayOfYear;
1500
1501    for (_month = 0; _month < 12; _month++) {
1502      if (_month == 1 && _isLeapYear) {
1503    if (_dayOfMonth < 29)
1504      return;
1505    else
1506      _dayOfMonth -= 29;
1507      }
1508      else if (_dayOfMonth < DAYS_IN_MONTH[(int) _month])
1509    return;
1510      else
1511    _dayOfMonth -= DAYS_IN_MONTH[(int) _month];
1512    }
1513  }
1514
1515  /**
1516   * Based on the current data, calculate the time since the epoch.
1517   *
1518   * @return time since the epoch, given the calendar components
1519   */

1520  private long calculateJoin()
1521  {
1522    _year += divFloor(_month, 12);
1523    _month -= 12 * divFloor(_month, 12);
1524
1525    _localTimeOfEpoch = MS_PER_DAY * (yearToDayOfEpoch(_year) +
1526                                    monthToDayOfYear(_month, isLeapYear(_year)) +
1527                                    _dayOfMonth);
1528
1529    _localTimeOfEpoch += _ms + 1000 * (_second + 60 * (_minute + 60 * _hour));
1530
1531    return _localTimeOfEpoch;
1532  }
1533
1534  private long divFloor(long n, long d)
1535  {
1536    if (n > 0)
1537      return n / d;
1538    else
1539      return (n - d + 1) / d;
1540  }
1541
1542  public Object JavaDoc clone()
1543  {
1544    QDate newObj = new QDate(_timeZone);
1545
1546    newObj.calculateSplit(_localTimeOfEpoch);
1547
1548    return newObj;
1549  }
1550
1551  public String JavaDoc toString()
1552  {
1553    return "QDate[" + printDate() + "]";
1554  }
1555}
1556
Popular Tags