1 | /* ============================================================= |
2 | * SmallSQL : a free Java DBMS library for the Java(tm) platform |
3 | * ============================================================= |
4 | * |
5 | * (C) Copyright 2004-2006, by Volker Berlin. |
6 | * |
7 | * Project Info: http://www.smallsql.de/ |
8 | * |
9 | * This library is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU Lesser General Public License as published by |
11 | * the Free Software Foundation; either version 2.1 of the License, or |
12 | * (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, but |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
16 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
17 | * License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Lesser General Public |
20 | * License along with this library; if not, write to the Free Software |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, |
22 | * USA. |
23 | * |
24 | * [Java is a trademark or registered trademark of Sun Microsystems, Inc. |
25 | * in the United States and other countries.] |
26 | * |
27 | * --------------- |
28 | * DateTime.java |
29 | * --------------- |
30 | * Author: Volker Berlin |
31 | * |
32 | * Created on 07.05.2004 |
33 | */ |
34 | package smallsql.database; |
35 | |
36 | import java.sql.*; |
37 | import java.text.DateFormatSymbols; |
38 | import java.util.Calendar; |
39 | import java.util.TimeZone; |
40 | |
41 | |
42 | public final class DateTime implements Mutable{ |
43 | |
44 | long time; |
45 | private int dataType = SQLTokenizer.TIMESTAMP; |
46 | |
47 | static final int[] MONTH_DAYS = {0,31,59,90,120,151,181,212,243,273,304,334}; |
48 | |
49 | private static final String[] SHORT_MONTHS = new DateFormatSymbols().getShortMonths(); |
50 | |
51 | DateTime(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millis){ |
52 | time = calcMillis( year, month, day, hour, minute, second, millis); |
53 | } |
54 | |
55 | |
56 | DateTime(long time, int dataType) throws SQLException{ |
57 | switch(dataType){ |
58 | case SQLTokenizer.SMALLDATETIME: |
59 | dataType = SQLTokenizer.SMALLDATETIME; |
60 | break; |
61 | case SQLTokenizer.TIME: |
62 | time %= 86400000; |
63 | break; |
64 | case SQLTokenizer.DATE: |
65 | int millis = (int)(time % 86400000); |
66 | if(millis < 0) |
67 | millis += 86400000; |
68 | time -= millis; |
69 | break; |
70 | } |
71 | this.time = time; |
72 | this.dataType = dataType; |
73 | } |
74 | |
75 | |
76 | static long calcMillis(Details details){ |
77 | return calcMillis(details.year, details.month, details.day, details.hour, details.minute, details.second, details.millis); |
78 | } |
79 | |
80 | static long calcMillis(int year, int month, final int day, final int hour, final int minute, final int second, final int millis){ |
81 | long result = millis; |
82 | result += second * 1000; |
83 | result += minute * 60000; |
84 | result += hour * 3600000; |
85 | result += (day-1) * 86400000L; |
86 | if(month > 11){ |
87 | year += month / 12; |
88 | month %= 12; |
89 | } |
90 | result += MONTH_DAYS[month] * 86400000L; |
91 | result += (year - 1970) * 31536000000L; // millis 365 days |
92 | result += ((year/4) - (year/100) + (year/400) - 477) * 86400000L; |
93 | if(month<2 && year % 4 == 0 && (year%100 != 0 || year%400 == 0)) |
94 | result -= 86400000L; |
95 | return result; |
96 | } |
97 | |
98 | |
99 | static long now(){ |
100 | return removeDateTimeOffset( System.currentTimeMillis() ); |
101 | } |
102 | |
103 | |
104 | /** |
105 | * Return the day of week.<p> |
106 | * 0 - Monday<p> |
107 | * 1 - Tuesday<p> |
108 | * 2 - Wednsday<p> |
109 | * 3 - Thursday<p> |
110 | * 4 - Friday<p> |
111 | * 5 - Saturday<p> |
112 | * 6 - Sunday<p> |
113 | */ |
114 | static int dayOfWeek(long time){ |
115 | // the 1. Jan 1970 is a Thursday --> 3 |
116 | return (int)((time / 86400000 + 3) % 7); |
117 | } |
118 | |
119 | static long parse(java.util.Date date) throws SQLException{ |
120 | long t = date.getTime(); |
121 | return removeDateTimeOffset(t); |
122 | } |
123 | |
124 | static DateTime valueOf(java.util.Date date) throws SQLException{ |
125 | if(date == null) return null; |
126 | int type; |
127 | if(date instanceof java.sql.Date) |
128 | type = SQLTokenizer.DATE; |
129 | else |
130 | if(date instanceof java.sql.Time) |
131 | type = SQLTokenizer.TIME; |
132 | else |
133 | type = SQLTokenizer.TIMESTAMP; |
134 | return new DateTime( parse(date), type); |
135 | } |
136 | |
137 | |
138 | static DateTime valueOf(java.sql.Date date) throws SQLException{ |
139 | if(date == null) return null; |
140 | return new DateTime( parse(date), SQLTokenizer.DATE); |
141 | } |
142 | |
143 | |
144 | static DateTime valueOf(java.sql.Time date) throws SQLException{ |
145 | if(date == null) return null; |
146 | return new DateTime( parse(date), SQLTokenizer.TIME); |
147 | } |
148 | |
149 | |
150 | static DateTime valueOf(java.sql.Timestamp date) throws SQLException{ |
151 | if(date == null) return null; |
152 | return new DateTime( parse(date), SQLTokenizer.TIMESTAMP); |
153 | } |
154 | |
155 | |
156 | /** |
157 | * @param dataType is used for the toString() method |
158 | */ |
159 | static DateTime valueOf(String date, int dataType) throws SQLException{ |
160 | if(date == null) return null; |
161 | return new DateTime( parse(date), dataType); |
162 | } |
163 | |
164 | |
165 | static long parse(final String datetime) throws SQLException{ |
166 | try{ |
167 | final int length = datetime.length(); |
168 | |
169 | final int year; |
170 | final int month; |
171 | final int day; |
172 | final int hour; |
173 | final int minute; |
174 | final int second; |
175 | final int millis; |
176 | |
177 | |
178 | int idx1 = 0; |
179 | int idx2 = datetime.indexOf('-'); |
180 | if(idx2 > 0){ |
181 | year = Integer.parseInt(datetime.substring(idx1, idx2).trim()); |
182 | |
183 | idx1 = idx2+1; |
184 | idx2 = datetime.indexOf('-', idx1); |
185 | month = Integer.parseInt(datetime.substring(idx1, idx2).trim())-1; |
186 | |
187 | idx1 = idx2+1; |
188 | idx2 = datetime.indexOf(' ', idx1); |
189 | if(idx2 < 0) idx2 = datetime.length(); |
190 | day = Integer.parseInt(datetime.substring(idx1, idx2).trim()); |
191 | }else{ |
192 | year = 1970; |
193 | month = 0; |
194 | day = 1; |
195 | } |
196 | |
197 | idx1 = idx2+1; |
198 | idx2 = datetime.indexOf(':', idx1); |
199 | if(idx2>0){ |
200 | hour = Integer.parseInt(datetime.substring(idx1, idx2).trim()); |
201 | |
202 | idx1 = idx2+1; |
203 | idx2 = datetime.indexOf(':', idx1); |
204 | minute = Integer.parseInt(datetime.substring(idx1, idx2).trim()); |
205 | |
206 | idx1 = idx2+1; |
207 | idx2 = datetime.indexOf('.', idx1); |
208 | if(idx2 < 0) idx2 = datetime.length(); |
209 | second = Integer.parseInt(datetime.substring(idx1, idx2).trim()); |
210 | |
211 | idx1 = idx2+1; |
212 | if(idx1 < length){ |
213 | String strMillis = datetime.substring(idx1).trim(); |
214 | switch(strMillis.length()){ |
215 | case 1: |
216 | millis = Integer.parseInt(strMillis) * 100; |
217 | break; |
218 | case 2: |
219 | millis = Integer.parseInt(strMillis) * 10; |
220 | break; |
221 | case 3: |
222 | millis = Integer.parseInt(strMillis); |
223 | break; |
224 | default: |
225 | millis = Integer.parseInt(strMillis.substring(0,3)); |
226 | } |
227 | }else |
228 | millis = 0; |
229 | }else{ |
230 | hour = 0; |
231 | minute = 0; |
232 | second = 0; |
233 | millis = 0; |
234 | } |
235 | return calcMillis(year, month, day, hour, minute, second, millis); |
236 | }catch(Throwable e){ |
237 | e.printStackTrace(); |
238 | throw Utils.createSQLException('\'' +datetime+ "' is an invalid DATE, TIME or TIMESTAMP" ); |
239 | } |
240 | } |
241 | |
242 | |
243 | long getTimeMillis(){ |
244 | return time; |
245 | } |
246 | |
247 | |
248 | int getDataType(){ |
249 | return dataType; |
250 | } |
251 | |
252 | |
253 | /** |
254 | * Convert the this value in a String depending of the type the format is a subset of |
255 | * yyyy-mm-dd hh:mm:ss.nnn |
256 | */ |
257 | public String toString(){ |
258 | Details details = new Details(time); |
259 | StringBuffer buf = new StringBuffer(); |
260 | if(dataType != SQLTokenizer.TIME){ |
261 | formatNumber( details.year, 4, buf ); |
262 | buf.append('-'); |
263 | formatNumber( details.month + 1, 2, buf ); |
264 | buf.append('-'); |
265 | formatNumber( details.day, 2, buf ); |
266 | } |
267 | if(dataType != SQLTokenizer.DATE){ |
268 | if(buf.length() > 0) buf.append(' '); |
269 | formatNumber( details.hour, 2, buf ); |
270 | buf.append(':'); |
271 | formatNumber( details.minute, 2, buf ); |
272 | buf.append(':'); |
273 | formatNumber( details.second, 2, buf ); |
274 | } |
275 | if(dataType == SQLTokenizer.TIMESTAMP){ |
276 | buf.append('.'); |
277 | formatMillis( details.millis, buf ); |
278 | } |
279 | return buf.toString(); |
280 | } |
281 | |
282 | |
283 | public boolean equals(Object obj){ |
284 | if(!(obj instanceof DateTime)) return false; |
285 | DateTime value = (DateTime)obj; |
286 | return value.time == time && value.dataType == dataType; |
287 | } |
288 | |
289 | |
290 | /** |
291 | * @param style a value like the syle of CONVERT function from MS SQL Server. |
292 | */ |
293 | String toString(int style){ |
294 | if(style < 0) |
295 | return toString(); |
296 | Details details = new Details(time); |
297 | StringBuffer buf = new StringBuffer(); |
298 | switch(style){ |
299 | case 0: |
300 | case 100: // mon dd yyyy hh:miAM (oder PM) |
301 | buf.append( SHORT_MONTHS[ details.month ]); |
302 | buf.append(' '); |
303 | formatNumber( details.day, 2, buf); |
304 | buf.append(' '); |
305 | formatNumber( details.year, 4, buf); |
306 | buf.append(' '); |
307 | formatHour12( details.hour, buf ); |
308 | buf.append(':'); |
309 | formatNumber( details.minute, 2, buf); |
310 | buf.append( details.hour < 12 ? "AM" : "PM" ); |
311 | return buf.toString(); |
312 | case 1: // USA mm/dd/yy |
313 | formatNumber( details.month+1, 2, buf); |
314 | buf.append('/'); |
315 | formatNumber( details.day, 2, buf); |
316 | buf.append('/'); |
317 | formatNumber( details.year % 100, 2, buf); |
318 | return buf.toString(); |
319 | case 101: // USA mm/dd/yyyy |
320 | formatNumber( details.month+1, 2, buf); |
321 | buf.append('/'); |
322 | formatNumber( details.day, 2, buf); |
323 | buf.append('/'); |
324 | formatNumber( details.year, 4, buf); |
325 | return buf.toString(); |
326 | case 2: // ANSI yy.mm.dd |
327 | formatNumber( details.year % 100, 2, buf); |
328 | buf.append('.'); |
329 | formatNumber( details.month+1, 2, buf); |
330 | buf.append('.'); |
331 | formatNumber( details.day, 2, buf); |
332 | return buf.toString(); |
333 | case 102: // ANSI yyyy.mm.dd |
334 | formatNumber( details.year, 4, buf); |
335 | buf.append('.'); |
336 | formatNumber( details.month+1, 2, buf); |
337 | buf.append('.'); |
338 | formatNumber( details.day, 2, buf); |
339 | return buf.toString(); |
340 | case 3: // britsh dd/mm/yy |
341 | formatNumber( details.day, 2, buf); |
342 | buf.append('/'); |
343 | formatNumber( details.month+1, 2, buf); |
344 | buf.append('/'); |
345 | formatNumber( details.year % 100, 2, buf); |
346 | return buf.toString(); |
347 | case 103: // britsh dd/mm/yyyy |
348 | formatNumber( details.day, 2, buf); |
349 | buf.append('/'); |
350 | formatNumber( details.month+1, 2, buf); |
351 | buf.append('/'); |
352 | formatNumber( details.year, 4, buf); |
353 | return buf.toString(); |
354 | case 4: // german dd.mm.yy |
355 | formatNumber( details.day, 2, buf); |
356 | buf.append('.'); |
357 | formatNumber( details.month+1, 2, buf); |
358 | buf.append('.'); |
359 | formatNumber( details.year % 100, 2, buf); |
360 | return buf.toString(); |
361 | case 104: // german dd.mm.yyyy |
362 | formatNumber( details.day, 2, buf); |
363 | buf.append('.'); |
364 | formatNumber( details.month+1, 2, buf); |
365 | buf.append('.'); |
366 | formatNumber( details.year, 4, buf); |
367 | return buf.toString(); |
368 | case 5: // italiano dd-mm-yy |
369 | formatNumber( details.day, 2, buf); |
370 | buf.append('-'); |
371 | formatNumber( details.month+1, 2, buf); |
372 | buf.append('-'); |
373 | formatNumber( details.year % 100, 2, buf); |
374 | return buf.toString(); |
375 | case 105: // italiano dd-mm-yyyy |
376 | formatNumber( details.day, 2, buf); |
377 | buf.append('-'); |
378 | formatNumber( details.month+1, 2, buf); |
379 | buf.append('-'); |
380 | formatNumber( details.year, 4, buf); |
381 | return buf.toString(); |
382 | case 6: // dd mon yy |
383 | formatNumber( details.day, 2, buf); |
384 | buf.append(' '); |
385 | buf.append( SHORT_MONTHS[ details.month ]); |
386 | buf.append(' '); |
387 | formatNumber( details.year % 100, 2, buf); |
388 | return buf.toString(); |
389 | case 106: // dd mon yyyy |
390 | formatNumber( details.day, 2, buf); |
391 | buf.append(' '); |
392 | buf.append( SHORT_MONTHS[ details.month ]); |
393 | buf.append(' '); |
394 | formatNumber( details.year, 4, buf); |
395 | return buf.toString(); |
396 | case 7: // Mon dd, yy |
397 | buf.append( SHORT_MONTHS[ details.month ]); |
398 | buf.append(' '); |
399 | formatNumber( details.day, 2, buf); |
400 | buf.append(','); |
401 | buf.append(' '); |
402 | formatNumber( details.year % 100, 2, buf); |
403 | return buf.toString(); |
404 | case 107: // Mon dd, yyyy |
405 | buf.append( SHORT_MONTHS[ details.month ]); |
406 | buf.append(' '); |
407 | formatNumber( details.day, 2, buf); |
408 | buf.append(','); |
409 | buf.append(' '); |
410 | formatNumber( details.year, 4, buf); |
411 | return buf.toString(); |
412 | case 8: //hh:mm:ss |
413 | case 108: |
414 | formatNumber( details.hour, 2, buf); |
415 | buf.append(':'); |
416 | formatNumber( details.minute, 2, buf); |
417 | buf.append(':'); |
418 | formatNumber( details.second, 2, buf); |
419 | return buf.toString(); |
420 | case 9: |
421 | case 109: // mon dd yyyy hh:mi:ss:mmmAM (oder PM) |
422 | buf.append( SHORT_MONTHS[ details.month ]); |
423 | buf.append(' '); |
424 | formatNumber( details.day, 2, buf); |
425 | buf.append(' '); |
426 | formatNumber( details.year, 4, buf); |
427 | buf.append(' '); |
428 | formatHour12( details.hour, buf ); |
429 | buf.append(':'); |
430 | formatNumber( details.minute, 2, buf); |
431 | buf.append(':'); |
432 | formatNumber( details.second, 2, buf); |
433 | buf.append(':'); |
434 | formatMillis( details.millis, buf); |
435 | buf.append( details.hour < 12 ? "AM" : "PM" ); |
436 | return buf.toString(); |
437 | case 10: // USA mm-dd-yy |
438 | formatNumber( details.month+1, 2, buf); |
439 | buf.append('-'); |
440 | formatNumber( details.day, 2, buf); |
441 | buf.append('-'); |
442 | formatNumber( details.year % 100, 2, buf); |
443 | return buf.toString(); |
444 | case 110: // USA mm-dd-yyyy |
445 | formatNumber( details.month+1, 2, buf); |
446 | buf.append('-'); |
447 | formatNumber( details.day, 2, buf); |
448 | buf.append('-'); |
449 | formatNumber( details.year, 4, buf); |
450 | return buf.toString(); |
451 | case 11: // Japan yy/mm/dd |
452 | formatNumber( details.year % 100, 2, buf); |
453 | buf.append('/'); |
454 | formatNumber( details.month+1, 2, buf); |
455 | buf.append('/'); |
456 | formatNumber( details.day, 2, buf); |
457 | return buf.toString(); |
458 | case 111: // Japan yy/mm/dd |
459 | formatNumber( details.year, 4, buf); |
460 | buf.append('/'); |
461 | formatNumber( details.month+1, 2, buf); |
462 | buf.append('/'); |
463 | formatNumber( details.day, 2, buf); |
464 | return buf.toString(); |
465 | case 12: // ISO yymmdd |
466 | formatNumber( details.year % 100, 2, buf); |
467 | formatNumber( details.month+1, 2, buf); |
468 | formatNumber( details.day, 2, buf); |
469 | return buf.toString(); |
470 | case 112: // ISO yyyymmdd |
471 | formatNumber( details.year, 4, buf); |
472 | formatNumber( details.month+1, 2, buf); |
473 | formatNumber( details.day, 2, buf); |
474 | return buf.toString(); |
475 | case 13: |
476 | case 113: // default + millis; dd mon yyyy hh:mm:ss:mmm(24h) |
477 | formatNumber( details.day, 2, buf); |
478 | buf.append(' '); |
479 | buf.append( SHORT_MONTHS[ details.month ]); |
480 | buf.append(' '); |
481 | formatNumber( details.year, 4, buf); |
482 | buf.append(' '); |
483 | formatNumber( details.hour, 2, buf ); |
484 | buf.append(':'); |
485 | formatNumber( details.minute, 2, buf); |
486 | buf.append(':'); |
487 | formatNumber( details.second, 2, buf); |
488 | buf.append(':'); |
489 | formatMillis( details.millis, buf); |
490 | return buf.toString(); |
491 | case 14: |
492 | case 114: // hh:mi:ss:mmm(24h) |
493 | formatNumber( details.hour, 2, buf); |
494 | buf.append(':'); |
495 | formatNumber( details.minute, 2, buf); |
496 | buf.append(':'); |
497 | formatNumber( details.second, 2, buf); |
498 | buf.append(':'); |
499 | formatMillis( details.millis, buf ); |
500 | return buf.toString(); |
501 | case 20: |
502 | case 120: // ODBC kannonish; yyyy-mm-dd hh:mi:ss(24h) |
503 | formatNumber( details.year, 4, buf); |
504 | buf.append('-'); |
505 | formatNumber( details.month+1, 2, buf); |
506 | buf.append('-'); |
507 | formatNumber( details.day, 2, buf); |
508 | buf.append(' '); |
509 | formatNumber( details.hour, 2, buf); |
510 | buf.append(':'); |
511 | formatNumber( details.minute, 2, buf); |
512 | buf.append(':'); |
513 | formatNumber( details.second, 2, buf); |
514 | return buf.toString(); |
515 | case 21: |
516 | case 121: // ODBC kannonish + millis; yyyy-mm-dd hh:mi:ss.mmm(24h) |
517 | formatNumber( details.year, 4, buf); |
518 | buf.append('-'); |
519 | formatNumber( details.month+1, 2, buf); |
520 | buf.append('-'); |
521 | formatNumber( details.day, 2, buf); |
522 | buf.append(' '); |
523 | formatNumber( details.hour, 2, buf); |
524 | buf.append(':'); |
525 | formatNumber( details.minute, 2, buf); |
526 | buf.append(':'); |
527 | formatNumber( details.second, 2, buf); |
528 | buf.append('.'); |
529 | formatMillis( details.millis, buf ); |
530 | return buf.toString(); |
531 | case 26: |
532 | case 126: // ISO8601; yyyy-mm-ddThh:mi:ss.mmm(24h) |
533 | formatNumber( details.year, 4, buf); |
534 | buf.append('-'); |
535 | formatNumber( details.month+1, 2, buf); |
536 | buf.append('-'); |
537 | formatNumber( details.day, 2, buf); |
538 | buf.append('T'); |
539 | formatNumber( details.hour, 2, buf); |
540 | buf.append(':'); |
541 | formatNumber( details.minute, 2, buf); |
542 | buf.append(':'); |
543 | formatNumber( details.second, 2, buf); |
544 | buf.append('.'); |
545 | formatMillis( details.millis, buf ); |
546 | return buf.toString(); |
547 | case 130: // Kuwaiti dd mon yyyy hh:mi:ss:mmmAM |
548 | formatNumber( details.day, 2, buf); |
549 | buf.append(' '); |
550 | buf.append( SHORT_MONTHS[ details.month ]); |
551 | buf.append(' '); |
552 | formatNumber( details.year, 4, buf); |
553 | buf.append(' '); |
554 | formatHour12( details.hour, buf ); |
555 | buf.append(':'); |
556 | formatNumber( details.minute, 2, buf); |
557 | buf.append(':'); |
558 | formatNumber( details.second, 2, buf); |
559 | buf.append(':'); |
560 | formatMillis( details.millis, buf); |
561 | buf.append( details.hour < 12 ? "AM" : "PM" ); |
562 | return buf.toString(); |
563 | case 131: // Kuwaiti dd/mm/yy hh:mi:ss:mmmAM |
564 | formatNumber( details.day, 2, buf); |
565 | buf.append('/'); |
566 | formatNumber( details.month+1, 2, buf); |
567 | buf.append('/'); |
568 | formatNumber( details.year % 100, 2, buf); |
569 | buf.append(' '); |
570 | formatNumber( details.hour, 2, buf); |
571 | buf.append(':'); |
572 | formatNumber( details.minute, 2, buf); |
573 | buf.append(':'); |
574 | formatNumber( details.second, 2, buf); |
575 | buf.append(':'); |
576 | formatMillis( details.millis, buf ); |
577 | return buf.toString(); |
578 | default: |
579 | return toString(); |
580 | } |
581 | |
582 | } |
583 | |
584 | |
585 | private final static void formatNumber(int value, int digitCount, StringBuffer buf){ |
586 | buf.setLength(buf.length() + digitCount); |
587 | if(value < 0) value = - value; |
588 | for(int i=1; i<=digitCount; i++){ |
589 | buf.setCharAt( buf.length()-i, Utils.digits[ value % 10 ] ); |
590 | value /= 10; |
591 | } |
592 | } |
593 | |
594 | |
595 | private final static void formatMillis(int millis, StringBuffer buf){ |
596 | buf.append(Utils.digits[ (millis / 100) % 10 ]); |
597 | int value = millis % 100; |
598 | if(value != 0){ |
599 | buf.append(Utils.digits[ value / 10 ]); |
600 | value %= 10; |
601 | if(value != 0) |
602 | buf.append(Utils.digits[ value ]); |
603 | } |
604 | } |
605 | |
606 | |
607 | /** |
608 | * The hour is print in the range from 1 - 12 |
609 | */ |
610 | private final static void formatHour12(int hour, StringBuffer buf){ |
611 | hour %= 12; |
612 | if(hour == 0) hour = 12; |
613 | formatNumber( hour, 2, buf ); |
614 | } |
615 | |
616 | |
617 | private final static long addDateTimeOffset(long datetime){ |
618 | synchronized(cal){ |
619 | cal.setTimeZone( TimeZone.getDefault() ); |
620 | cal.setTimeInMillis( datetime ); |
621 | return datetime - cal.get( Calendar.ZONE_OFFSET) - cal.get( Calendar.DST_OFFSET); |
622 | } |
623 | } |
624 | |
625 | |
626 | private static long removeDateTimeOffset(long datetime){ |
627 | synchronized(cal){ |
628 | cal.setTimeZone( TimeZone.getDefault() ); |
629 | cal.setTimeInMillis( datetime ); |
630 | return datetime + cal.get( Calendar.ZONE_OFFSET) + cal.get( Calendar.DST_OFFSET); |
631 | } |
632 | } |
633 | |
634 | |
635 | static Timestamp getTimestamp(long time){ |
636 | return new Timestamp( DateTime.addDateTimeOffset(time) ); |
637 | } |
638 | |
639 | |
640 | static Time getTime(long time){ |
641 | return new Time( DateTime.addDateTimeOffset(time) ); |
642 | } |
643 | |
644 | |
645 | static Date getDate(long time){ |
646 | return new Date( DateTime.addDateTimeOffset(time) ); |
647 | } |
648 | |
649 | |
650 | public Object getImmutableObject(){ |
651 | switch(dataType){ |
652 | case SQLTokenizer.DATE: |
653 | return getDate( time ); |
654 | case SQLTokenizer.TIME: |
655 | return getTime( time ); |
656 | default: |
657 | return getTimestamp( time ); |
658 | } |
659 | } |
660 | |
661 | |
662 | static class Details{ |
663 | int year; |
664 | int month; |
665 | int dayofyear; |
666 | int day; |
667 | int hour; |
668 | int minute; |
669 | int second; |
670 | int millis; |
671 | |
672 | Details(long time){ |
673 | int t = (int)(time % 86400000); |
674 | int d = (int)(time / 86400000); |
675 | if(t<0){ |
676 | //Zeit vor 1970 und kein ganzer Tag |
677 | t += 86400000; |
678 | d--; |
679 | } |
680 | millis = t % 1000; |
681 | t /= 1000; |
682 | second = t % 60; |
683 | t /= 60; |
684 | minute = t % 60; |
685 | t /= 60; |
686 | hour = t % 24; |
687 | |
688 | year = 1970 - (int)(t / 365.2425); |
689 | boolean isLeap; |
690 | do{ |
691 | isLeap = false; |
692 | dayofyear = day = d - ((year - 1970)*365 + (year/4) - (year/100) + (year/400) - 477); |
693 | if(year % 4 == 0 && (year%100 != 0 || year%400 == 0)){ |
694 | // is leap year |
695 | if(day < 59){ |
696 | day++; |
697 | isLeap = true; |
698 | } |
699 | dayofyear++; |
700 | } |
701 | if(day < 0){ |
702 | year--; |
703 | continue; |
704 | }else |
705 | if(day >= 365){ |
706 | year++; |
707 | continue; |
708 | } |
709 | break; |
710 | }while(true); |
711 | |
712 | if(isLeap && day == 59){ |
713 | // 29. Feb |
714 | month = 1; |
715 | day = 29; |
716 | }else{ |
717 | for(int m=11; m>=0; m--){ |
718 | if(MONTH_DAYS[m] <= day){ |
719 | month = m; |
720 | day = day - MONTH_DAYS[m] + 1; |
721 | break; |
722 | } |
723 | } |
724 | } |
725 | } |
726 | } |
727 | |
728 | private static final Calendar cal = Calendar.getInstance(); |
729 | |
730 | } |