1 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){ 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; 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 114 static int dayOfWeek(long time){ 115 return (int)((time / 86400000 + 3) % 7); 117 } 118 119 static long parse(java.util.Date date){ 120 long t = date.getTime(); 121 return removeDateTimeOffset(t); 122 } 123 124 static DateTime valueOf(java.util.Date date){ 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){ 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){ 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){ 151 if(date == null) return null; 152 return new DateTime( parse(date), SQLTokenizer.TIMESTAMP); 153 } 154 155 156 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 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 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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 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 return addDateTimeOffset( datetime, TimeZone.getDefault()); 619 } 620 621 622 final static long addDateTimeOffset(long datetime, TimeZone timezone){ 623 synchronized(cal){ 624 cal.setTimeZone( timezone ); 625 cal.setTimeInMillis( datetime ); 626 return datetime - cal.get( Calendar.ZONE_OFFSET) - cal.get( Calendar.DST_OFFSET); 627 } 628 } 629 630 631 private static long removeDateTimeOffset(long datetime){ 632 synchronized(cal){ 633 cal.setTimeZone( TimeZone.getDefault() ); 634 cal.setTimeInMillis( datetime ); 635 return datetime + cal.get( Calendar.ZONE_OFFSET) + cal.get( Calendar.DST_OFFSET); 636 } 637 } 638 639 640 static Timestamp getTimestamp(long time){ 641 return new Timestamp( DateTime.addDateTimeOffset(time) ); 642 } 643 644 645 static Time getTime(long time){ 646 return new Time( DateTime.addDateTimeOffset(time) ); 647 } 648 649 650 static Date getDate(long time){ 651 return new Date( DateTime.addDateTimeOffset(time) ); 652 } 653 654 655 public Object getImmutableObject(){ 656 switch(dataType){ 657 case SQLTokenizer.DATE: 658 return getDate( time ); 659 case SQLTokenizer.TIME: 660 return getTime( time ); 661 default: 662 return getTimestamp( time ); 663 } 664 } 665 666 667 static class Details{ 668 int year; 669 int month; 670 int dayofyear; 671 int day; 672 int hour; 673 int minute; 674 int second; 675 int millis; 676 677 Details(long time){ 678 int t = (int)(time % 86400000); 679 int d = (int)(time / 86400000); 680 if(t<0){ 681 t += 86400000; 683 d--; 684 } 685 millis = t % 1000; 686 t /= 1000; 687 second = t % 60; 688 t /= 60; 689 minute = t % 60; 690 t /= 60; 691 hour = t % 24; 692 693 year = 1970 - (int)(t / 365.2425); 694 boolean isLeap; 695 do{ 696 isLeap = false; 697 dayofyear = day = d - ((year - 1970)*365 + (year/4) - (year/100) + (year/400) - 477); 698 if(year % 4 == 0 && (year%100 != 0 || year%400 == 0)){ 699 if(day < 59){ 701 day++; 702 isLeap = true; 703 } 704 dayofyear++; 705 } 706 if(day < 0){ 707 year--; 708 continue; 709 }else 710 if(day >= 365){ 711 year++; 712 continue; 713 } 714 break; 715 }while(true); 716 717 if(isLeap && day == 59){ 718 month = 1; 720 day = 29; 721 }else{ 722 for(int m=11; m>=0; m--){ 723 if(MONTH_DAYS[m] <= day){ 724 month = m; 725 day = day - MONTH_DAYS[m] + 1; 726 break; 727 } 728 } 729 } 730 } 731 } 732 733 private static final Calendar cal = Calendar.getInstance(); 734 735 } 736 | Popular Tags |