KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > HsqlDateTime


1 /* Copyright (c) 2001-2005, The HSQL Development Group
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the HSQL Development Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31
32 package org.hsqldb;
33
34 import java.sql.Date JavaDoc;
35 import java.sql.Time JavaDoc;
36 import java.sql.Timestamp JavaDoc;
37 import java.text.SimpleDateFormat JavaDoc;
38 import java.util.Calendar JavaDoc;
39 import java.util.GregorianCalendar JavaDoc;
40 import java.util.TimeZone JavaDoc;
41
42 // fredt@users 20020130 - patch 1.7.0 by fredt - new class
43
// replaces patch by deforest@users
44
// fredt@users 20020414 - patch 517028 by peterhudson@users - use of calendar
45
// fredt@users 20020414 - patch 828957 by tjcrowder@users - JDK 1.3 compatibility
46
// fredt@users 20040105 - patch 870957 by Gerhard Hiller - JDK bug workaround
47

48 /**
49  * collection of static methods to convert Date, Time and Timestamp strings
50  * into corresponding Java objects. Also accepts SQL literals such as NOW,
51  * TODAY as valid strings and returns the current date / time / datetime.
52  * Compatible with jdk 1.1.x.<p>
53  *
54  * Was reviewed for 1.7.2 resulting in centralising all DATETIME related
55  * operstions.<p>
56  *
57  * HSQLDB uses the client and server's default timezone for all DATETIME
58  * operations. It stores the DATETIME values in .log and .script files using
59  * the default locale of the server. The same values are stored as binary
60  * UTC timestamps in .data files. If the database is trasported from one
61  * timezone to another, then the DATETIME values in cached tables will be
62  * handled as UTC but those in other tables will be treated as local. So
63  * a timestamp representing 12 noon stored in Tokyo timezone will be treated
64  * as 9 pm in London when stored in a cached table but the same value stored
65  * in a memory table will be treated as 12 noon.
66  *
67  * @author fredt@users
68  * @version 1.7.2
69  * @since 1.7.0
70  */

71 public class HsqlDateTime {
72
73     /**
74      * A reusable static value for today's date. Should only be accessed
75      * by getToday()
76      */

77     private static Calendar JavaDoc today = new GregorianCalendar JavaDoc();
78     private static Calendar JavaDoc tempCal = new GregorianCalendar JavaDoc();
79     private static Calendar JavaDoc tempCalDefault = new GregorianCalendar JavaDoc();
80     private static Calendar JavaDoc tempCalGMT =
81         new GregorianCalendar JavaDoc(TimeZone.getTimeZone("GMT"));
82     private static Date JavaDoc tempDate = new Date JavaDoc(0);
83     private static Date JavaDoc currentDate;
84
85     static {
86         resetToday(System.currentTimeMillis());
87     }
88
89     static final String JavaDoc zerodatetime = "1970-01-01 00:00:00.000000000";
90     static final String JavaDoc zeronanos = "000000000";
91
92     /**
93      * Converts a string in JDBC timestamp escape format to a
94      * <code>Timestamp</code> value.
95      *
96      * @param s timestamp in format <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>
97      * where end part can be omitted, or "NOW" (case insensitive)
98      * @return corresponding <code>Timestamp</code> value
99      * @exception java.lang.IllegalArgumentException if the given argument
100      * does not have the format <code>yyyy-mm-dd hh:mm:ss.fffffffff</code>
101      */

102     public static Timestamp JavaDoc timestampValue(String JavaDoc s) throws HsqlException {
103
104         if (s == null) {
105             throw Trace.error(Trace.HsqlDateTime_null_string);
106         }
107
108         if (s.length() > zerodatetime.length()) {
109             throw Trace.error(Trace.STRING_DATA_TRUNCATION);
110         }
111
112         s = s + zerodatetime.substring(s.length());
113
114         return Timestamp.valueOf(s);
115     }
116
117     /**
118      * For use with .script file, simpler than above
119      */

120     public static Timestamp JavaDoc simpleTimestampValue(String JavaDoc s) {
121         return Timestamp.valueOf(s);
122     }
123
124     /**
125      * @param time milliseconds
126      * @param nano nanoseconds
127      * @return Timestamp object
128      */

129     public static Timestamp JavaDoc timestampValue(long time, int nano) {
130
131         Timestamp JavaDoc ts = new Timestamp JavaDoc(time);
132
133         ts.setNanos(nano);
134
135         return ts;
136     }
137
138     /**
139      * Converts a string in JDBC date escape format to a <code>Date</code>
140      * value. Also accepts Timestamp values.
141      *
142      * @param s date in format <code>yyyy-mm-dd</code>,
143      * @return corresponding <code>Date</code> value
144      * @exception java.lang.IllegalArgumentException if the given argument
145      * does not have the format <code>yyyy-mm-dd</code>
146      */

147     public static Date JavaDoc dateValue(String JavaDoc s) throws HsqlException {
148
149         if (s == null) {
150             throw Trace.error(Trace.HsqlDateTime_null_string);
151         }
152
153         if (s.length() > sdfdPattern.length()) {
154             s = s.substring(0, sdfdPattern.length());
155         }
156
157         return Date.valueOf(s);
158     }
159
160     /**
161      * Converts a string in JDBC date escape format to a
162      * <code>Time</code> value.
163      *
164      * @param s date in format <code>hh:mm:ss</code>
165      * @return corresponding <code>Time</code> value
166      * @exception java.lang.IllegalArgumentException if the given argument
167      * does not have the format <code>hh:mm:ss</code>
168      */

169     public static Time JavaDoc timeValue(String JavaDoc s) {
170
171         if (s == null) {
172             throw new java.lang.IllegalArgumentException JavaDoc(
173                 Trace.getMessage(Trace.HsqlDateTime_null_string));
174         }
175
176         return Time.valueOf(s);
177     }
178
179     static int compare(Date JavaDoc a, Date JavaDoc b) {
180
181         long atime = a.getTime();
182         long btime = b.getTime();
183
184         if (atime == btime) {
185             return 0;
186         }
187
188         return atime > btime ? 1
189                              : -1;
190     }
191
192     static int compare(Time JavaDoc a, Time JavaDoc b) {
193
194         long atime = a.getTime();
195         long btime = b.getTime();
196
197         if (atime == btime) {
198             return 0;
199         }
200
201         return atime > btime ? 1
202                              : -1;
203     }
204
205     static int compare(Timestamp JavaDoc a, Timestamp JavaDoc b) {
206
207         long atime = a.getTime();
208         long btime = b.getTime();
209
210         if (atime == btime) {
211             if (a.getNanos() == b.getNanos()) {
212                 return 0;
213             }
214
215             return a.getNanos() > b.getNanos() ? 1
216                                                : -1;
217         }
218
219         return atime > btime ? 1
220                              : -1;
221     }
222
223     public static synchronized Date JavaDoc getCurrentDate(long millis) {
224
225         getToday(millis);
226
227         return currentDate;
228     }
229
230     public static Timestamp JavaDoc getTimestamp(long millis) {
231         return new Timestamp JavaDoc(millis);
232     }
233
234     private static final String JavaDoc sdftPattern = "HH:mm:ss";
235     private static final String JavaDoc sdfdPattern = "yyyy-MM-dd";
236     private static final String JavaDoc sdftsPattern = "yyyy-MM-dd HH:mm:ss.";
237     private static final String JavaDoc sdftsSysPattern = "yyyy-MM-dd HH:mm:ss.SSS";
238     static SimpleDateFormat JavaDoc sdfd = new SimpleDateFormat JavaDoc(sdfdPattern);
239     static SimpleDateFormat JavaDoc sdft = new SimpleDateFormat JavaDoc(sdftPattern);
240     static SimpleDateFormat JavaDoc sdfts = new SimpleDateFormat JavaDoc(sdftsPattern);
241     static SimpleDateFormat JavaDoc sdftsSys = new SimpleDateFormat JavaDoc(sdftsSysPattern);
242
243     /**
244      * Creates a valid timestamp string - jre 1.3 returns incorrect date part
245      * for Timestamp.toString();
246      */

247     public static String JavaDoc getTimestampString(Timestamp JavaDoc x) {
248
249         synchronized (sdfts) {
250             sdfts.setCalendar(tempCalDefault);
251
252             String JavaDoc n = String.valueOf(x.getNanos());
253
254             return sdfts.format(x) + zeronanos.substring(n.length()) + n;
255         }
256     }
257
258     /**
259      * Creates a full length timestamp string, with 9 digist for nanos
260      */

261     public static String JavaDoc getTimestampString(Timestamp JavaDoc x, Calendar JavaDoc cal) {
262
263         synchronized (sdfts) {
264             sdfts.setCalendar(cal == null ? tempCalDefault
265                                           : cal);
266
267             String JavaDoc n = String.valueOf(x.getNanos());
268
269             return sdfts.format(x) + zeronanos.substring(n.length()) + n;
270         }
271     }
272
273     private static java.util.Date JavaDoc sysDate = new java.util.Date JavaDoc();
274
275     public static String JavaDoc getSytemTimeString() {
276
277         synchronized (sdftsSys) {
278             sysDate.setTime(System.currentTimeMillis());
279
280             return sdftsSys.format(sysDate);
281         }
282     }
283
284     public static String JavaDoc getTimestampString(long timestamp) {
285
286         synchronized (sdftsSys) {
287             sysDate.setTime(timestamp);
288
289             return sdftsSys.format(sysDate);
290         }
291     }
292
293     public static String JavaDoc getTimeString(java.util.Date JavaDoc x, Calendar JavaDoc cal) {
294
295         synchronized (sdft) {
296             sdft.setCalendar(cal == null ? tempCalDefault
297                                          : cal);
298
299             return sdft.format(x);
300         }
301     }
302
303     public static String JavaDoc getDateString(java.util.Date JavaDoc x, Calendar JavaDoc cal) {
304
305         synchronized (sdfd) {
306             sdfd.setCalendar(cal == null ? tempCalDefault
307                                          : cal);
308
309             return sdfd.format(x);
310         }
311     }
312
313     /**
314      * Returns the same Date Object. This object should be treated as
315      * read-only.
316      */

317     static synchronized Calendar JavaDoc getToday(long millis) {
318
319         if (millis - getTimeInMillis(today) >= 24 * 3600 * 1000) {
320             resetToday(millis);
321         }
322
323         return today;
324     }
325
326     public static void resetToDate(Calendar JavaDoc cal) {
327
328         cal.set(Calendar.HOUR_OF_DAY, 0);
329         cal.set(Calendar.MINUTE, 0);
330         cal.set(Calendar.SECOND, 0);
331         cal.set(Calendar.MILLISECOND, 0);
332     }
333
334     public static void resetToTime(Calendar JavaDoc cal) {
335
336         cal.set(Calendar.YEAR, 1970);
337         cal.set(Calendar.MONTH, 0);
338         cal.set(Calendar.DATE, 1);
339         cal.set(Calendar.MILLISECOND, 0);
340     }
341
342     /**
343      * resets the static reusable value today
344      */

345     private static synchronized void resetToday(long millis) {
346
347 //#ifdef JDBC3
348
// Use method directly
349
today.setTimeInMillis(millis);
350
351 //#else
352
/*
353         // Have to go indirect
354         tempDate.setTime(millis);
355         today.setTime(tempDate);
356 */

357
358 //#endif JDBC3
359
resetToDate(today);
360
361         currentDate = new Date JavaDoc(getTimeInMillis(today));
362     }
363
364     /**
365      * Sets the time in the given Calendar using the given milliseconds value; wrapper method to
366      * allow use of more efficient JDK1.4 method on JDK1.4 (was protected in earlier versions).
367      *
368      * @param cal the Calendar
369      * @param millis the time value in milliseconds
370      */

371     private static void setTimeInMillis(Calendar JavaDoc cal, long millis) {
372
373 //#ifdef JDBC3
374
// Use method directly
375
cal.setTimeInMillis(millis);
376
377 //#else
378
/*
379         // Have to go indirect
380         synchronized (tempDate) {
381             tempDate.setTime(millis);
382             cal.setTime(tempDate);
383         }
384 */

385
386 //#endif JDBC3
387
}
388
389     public static long getTimeInMillis(java.util.Date JavaDoc dt, Calendar JavaDoc source,
390                                        Calendar JavaDoc target) {
391
392         if (source == null) {
393             source = tempCalDefault;
394         }
395
396         if (target == null) {
397             target = tempCalDefault;
398         }
399
400         synchronized (tempCal) {
401             tempCal.setTimeZone(source.getTimeZone());
402             tempCal.setTime(dt);
403             tempCal.setTimeZone(target.getTimeZone());
404
405             return getTimeInMillis(tempCal);
406         }
407     }
408
409     /**
410      * Gets the time from the given Calendar as a milliseconds value; wrapper method to
411      * allow use of more efficient JDK1.4 method on JDK1.4 (was protected in earlier versions).
412      *
413      * @param cal the Calendar
414      * @return the time value in milliseconds
415      */

416     public static long getTimeInMillis(Calendar JavaDoc cal) {
417
418 //#ifdef JDBC3
419
// Use method directly
420
return (cal.getTimeInMillis());
421
422 //#else
423
/*
424         // Have to go indirect
425         return (cal.getTime().getTime());
426 */

427
428 //#endif JDBC3
429
}
430
431     public static long getNormalisedTime(long t) {
432
433         synchronized (tempCalDefault) {
434             setTimeInMillis(tempCalDefault, t);
435             resetToTime(tempCalDefault);
436
437             return getTimeInMillis(tempCalDefault);
438         }
439     }
440
441     public static Time JavaDoc getNormalisedTime(Time JavaDoc t) {
442         return new Time JavaDoc(getNormalisedTime(t.getTime()));
443     }
444
445     public static Time JavaDoc getNormalisedTime(Timestamp JavaDoc ts) {
446         return new Time JavaDoc(getNormalisedTime(ts.getTime()));
447     }
448
449     public static long getNormalisedDate(long d) {
450
451         synchronized (tempCalDefault) {
452             setTimeInMillis(tempCalDefault, d);
453             resetToDate(tempCalDefault);
454
455             return getTimeInMillis(tempCalDefault);
456         }
457     }
458
459     public static Date JavaDoc getNormalisedDate(Timestamp JavaDoc ts) {
460
461         synchronized (tempCalDefault) {
462             setTimeInMillis(tempCalDefault, ts.getTime());
463             resetToDate(tempCalDefault);
464
465             long value = getTimeInMillis(tempCalDefault);
466
467             return new Date JavaDoc(value);
468         }
469     }
470
471     public static Date JavaDoc getNormalisedDate(Date JavaDoc d) {
472
473         synchronized (tempCalDefault) {
474             setTimeInMillis(tempCalDefault, d.getTime());
475             resetToDate(tempCalDefault);
476
477             long value = getTimeInMillis(tempCalDefault);
478
479             return new Date JavaDoc(value);
480         }
481     }
482
483     public static Timestamp JavaDoc getNormalisedTimestamp(Time JavaDoc t) {
484
485         synchronized (tempCalDefault) {
486             setTimeInMillis(tempCalDefault, System.currentTimeMillis());
487             resetToDate(tempCalDefault);
488
489             long value = getTimeInMillis(tempCalDefault) + t.getTime();
490
491             return new Timestamp JavaDoc(value);
492         }
493     }
494
495     public static Timestamp JavaDoc getNormalisedTimestamp(Date JavaDoc d) {
496
497         synchronized (tempCalDefault) {
498             setTimeInMillis(tempCalDefault, d.getTime());
499             resetToDate(tempCalDefault);
500
501             long value = getTimeInMillis(tempCalDefault);
502
503             return new Timestamp JavaDoc(value);
504         }
505     }
506
507     /**
508      * Returns the indicated part of the given <code>java.util.Date</code> object.
509      * @param d the <code>Date</code> object from which to extract the indicated part
510      * @param part an integer code corresponding to the desired date part
511      * @return the indicated part of the given <code>java.util.Date</code> object
512      */

513     static int getDateTimePart(java.util.Date JavaDoc d, int part) {
514
515         synchronized (tempCalDefault) {
516             tempCalDefault.setTime(d);
517
518             return tempCalDefault.get(part);
519         }
520     }
521
522     private static final char[][] dateTokens = {
523         {
524             'R', 'R', 'R', 'R'
525         }, {
526             'I', 'Y', 'Y', 'Y'
527         }, {
528             'Y', 'Y', 'Y', 'Y'
529         }, {
530             'I', 'Y'
531         }, {
532             'Y', 'Y'
533         }, {
534             'B', 'C'
535         }, {
536             'B', '.', 'C', '.'
537         }, {
538             'A', 'D'
539         }, {
540             'A', '.', 'D', '.'
541         }, {
542             'M', 'O', 'N'
543         }, {
544             'M', 'O', 'N', 'T', 'H'
545         }, { 'D' }, {
546             'I', 'W'
547         }, {
548             'D', 'D'
549         }, {
550             'D', 'D', 'D'
551         }, {
552             'H', 'H', '2', '4'
553         }, {
554             'H', 'H', '1', '2'
555         }, {
556             'H', 'H'
557         }, {
558             'M', 'I',
559         }, {
560             'S', 'S'
561         }, {
562             'A', 'M'
563         }, {
564             'P', 'M',
565         }, {
566             'A', '.', 'M', '.'
567         }, {
568             'P', '.', 'M', '.'
569         }
570     };
571     private static final String JavaDoc[] javaDateTokens = {
572         "yyyy", "yyyy", "yyyy", "yy", "yy", "G", "G", "G", "G", "MMM",
573         "MMMMM", "E", "w", "dd", "D", "k", "K", "K", "mm", "ss", "aaa", "aaa",
574         "aaa", "aaa"
575     };
576
577     /** Indicates end-of-input */
578     public static final char e = 0xffff;
579
580     /**
581      * Converts the given format into a pattern accepted by <code>java.text.SimpleDataFormat</code>
582      * @param format
583      * @return
584      */

585     public static String JavaDoc toJavaDatePattern(String JavaDoc format) {
586
587         int len = format.length();
588         char ch;
589         StringBuffer JavaDoc pattern = new StringBuffer JavaDoc(len);
590         Tokenizer tokenizer = new Tokenizer();
591
592         for (int i = 0; i <= len; i++) {
593             ch = (i == len) ? e
594                             : format.charAt(i);
595
596             if (!tokenizer.next(ch, dateTokens)) {
597                 int index = tokenizer.getLastMatch();
598
599                 if (index >= 0) {
600                     pattern.setLength(pattern.length() - tokenizer.length());
601                     pattern.append(javaDateTokens[index]);
602                 }
603
604                 tokenizer.reset();
605
606                 if (tokenizer.isConsumed()) {
607                     continue;
608                 }
609             }
610
611             pattern.append(ch);
612         }
613
614         pattern.setLength(pattern.length() - 1);
615
616         return pattern.toString();
617     }
618
619     /**
620      * This class can match 64 tokens at maximum.
621      */

622     static class Tokenizer {
623
624         private int last;
625         private int offset;
626         private long state;
627         private boolean consumed;
628
629         public Tokenizer() {
630             reset();
631         }
632
633         /**
634          * Resets for next reuse.
635          *
636          */

637         public void reset() {
638
639             last = -1;
640             offset = -1;
641             state = 0;
642         }
643
644         /**
645          * Returns a length of a token to match.
646          * @return
647          */

648         public int length() {
649             return offset;
650         }
651
652         /**
653          * Returns an index of the last matched token.
654          * @return
655          */

656         public int getLastMatch() {
657             return last;
658         }
659
660         /**
661          * Indicates whethe the last character has been consumed by the matcher.
662          * @return
663          */

664         public boolean isConsumed() {
665             return consumed;
666         }
667
668         /**
669          * Checks whether the specified bit is not set.
670          * @param bit
671          * @return
672          */

673         private boolean isZeroBit(int bit) {
674             return (state & (1L << bit)) == 0;
675         }
676
677         /**
678          * Sets the specified bit.
679          * @param bit
680          */

681         private void setBit(int bit) {
682             state |= (1L << bit);
683         }
684
685         /**
686          * Matches the specified character against tokens.
687          * @param ch
688          * @param tokens
689          * @return
690          */

691         public boolean next(char ch, char[][] tokens) {
692
693             // Use local variable for performance
694
int index = ++offset;
695             int len = offset + 1;
696             int left = 0;
697
698             consumed = false;
699
700             for (int i = tokens.length; --i >= 0; ) {
701                 if (isZeroBit(i)) {
702                     if (tokens[i][index] == ch) {
703                         consumed = true;
704
705                         if (tokens[i].length == len) {
706                             setBit(i);
707
708                             last = i;
709                         } else {
710                             ++left;
711                         }
712                     } else {
713                         setBit(i);
714                     }
715                 }
716             }
717
718             return left > 0;
719         }
720     }
721 }
722
Popular Tags