1 29 30 package com.caucho.util; 31 32 import com.caucho.vfs.WriteStream; 33 34 import java.io.IOException ; 35 import java.text.DateFormat ; 36 import java.util.Date ; 37 import java.util.GregorianCalendar ; 38 import java.util.TimeZone ; 39 import java.util.logging.Level ; 40 import java.util.logging.Logger ; 41 42 45 public class QDate { 46 private static final Logger 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 []DAY_NAMES = { 69 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 70 }; 71 static final String []MONTH_NAMES = { 72 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 73 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 74 }; 75 76 private static final String []SHORT_WEEKDAY = { 77 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 78 }; 79 private static final String []LONG_WEEKDAY = { 80 "Sunday", "Monday", "Tuesday", "Wednesday", 81 "Thursday", "Friday", "Saturday" 82 }; 83 private static final String []SHORT_MONTH = { 84 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 85 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 86 }; 87 private static final String []LONG_MONTH = { 88 "January", "February", "March", "April", "May", "June", 89 "July", "August", "September", "October", "November", "December", 90 }; 91 92 private static TimeZone _localTimeZone = TimeZone.getDefault(); 93 private static TimeZone _gmtTimeZone = TimeZone.getTimeZone("GMT"); 94 95 private static String _localDstName = 96 _localTimeZone.getDisplayName(true, TimeZone.SHORT); 97 private static String _localStdName = 98 _localTimeZone.getDisplayName(false, TimeZone.SHORT); 99 100 private static String _gmtDstName = 101 _gmtTimeZone.getDisplayName(true, TimeZone.SHORT); 102 private static String _gmtStdName = 103 _gmtTimeZone.getDisplayName(false, TimeZone.SHORT); 104 105 private static QDate _gmtDate = new QDate(false); 107 private static QDate _localDate = new QDate(true); 108 109 private TimeZone _timeZone; 110 111 private String _dstName; 112 private String _stdName; 113 114 private DateFormat _dateFormat; 115 private Date _date = new Date (); 116 117 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 _zoneName; 135 136 private long _lastTime; 137 private String _lastDate; 138 139 142 public QDate() 143 { 144 this(_gmtTimeZone); 145 } 146 147 150 public QDate(boolean isLocal) 151 { 152 this(isLocal ? _localTimeZone : _gmtTimeZone); 153 } 154 155 158 public QDate(TimeZone 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 183 public QDate(long year, long month, long dayOfMonth) 184 { 185 this(_localTimeZone); 186 setDate(year, month, dayOfMonth); 187 } 188 189 192 public static QDate createLocal() 193 { 194 return new QDate(true); 195 } 196 197 201 public void setLocalTime(long time) 202 { 203 if (_timeZone != _gmtTimeZone) { 205 calculateSplit(time); 206 } 207 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 e) { 221 log.log(Level.FINE, e.toString(), e); 222 } 223 } 224 } 225 226 229 public long getLocalTime() 230 { 231 if (_timeZone != _gmtTimeZone) { 233 return _localTimeOfEpoch; 234 } 235 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 252 public void setGMTTime(long time) 253 { 254 calculateSplit(time + _timeZone.getRawOffset()); 255 256 if (_isDaylightTime) 258 calculateSplit(time + _zoneOffset); 259 } 260 261 264 public long getGMTTime() 265 { 266 return _localTimeOfEpoch - _zoneOffset; 267 } 268 269 272 public long getTimeOfDay() 273 { 274 return _timeOfDay; 275 } 276 277 280 public int getYear() 281 { 282 return (int) _year; 283 } 284 285 288 public void setYear(int year) 289 { 290 _year = year; 291 292 calculateJoin(); 293 calculateSplit(_localTimeOfEpoch); 294 } 295 296 299 public int getMonth() 300 { 301 return (int) _month; 302 } 303 304 307 public void setMonth(int month) 308 { 309 _month = month; 310 calculateJoin(); 311 calculateSplit(_localTimeOfEpoch); 312 } 313 314 317 public int getDayOfMonth() 318 { 319 return (int) _dayOfMonth + 1; 320 } 321 322 325 public void setDayOfMonth(int day) 326 { 327 _dayOfMonth = day - 1; 328 calculateJoin(); 329 calculateSplit(_localTimeOfEpoch); 330 } 331 332 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 346 public int getDayOfWeek() 347 { 348 return (int) ((_dayOfEpoch % 7) + 11) % 7 + 1; 349 } 350 351 354 public int getDayOfYear() 355 { 356 return (int) _dayOfYear; 357 } 358 359 362 public int getHour() 363 { 364 return (int) _hour; 365 } 366 367 370 public void setHour(int hour) 371 { 372 _hour = hour; 373 374 calculateJoin(); 375 calculateSplit(_localTimeOfEpoch); 376 } 377 378 381 public int getMinute() 382 { 383 return (int) _minute; 384 } 385 386 389 public void setMinute(int minute) 390 { 391 _minute = minute; 392 393 calculateJoin(); 394 calculateSplit(_localTimeOfEpoch); 395 } 396 397 400 public int getSecond() 401 { 402 return (int) _second; 403 } 404 405 408 public void setSecond(int second) 409 { 410 _second = second; 411 412 calculateJoin(); 413 calculateSplit(_localTimeOfEpoch); 414 } 415 416 419 public long getMillisecond() 420 { 421 return _ms; 422 } 423 424 427 public void setMillisecond(long millisecond) 428 { 429 _ms = millisecond; 430 431 calculateJoin(); 432 calculateSplit(_localTimeOfEpoch); 433 } 434 435 438 public long getZoneOffset() 439 { 440 return _zoneOffset; 441 } 442 443 446 public boolean isDST() 447 { 448 return _isDaylightTime; 449 } 450 451 454 public TimeZone getLocalTimeZone() 455 { 456 return _localTimeZone; 457 } 458 459 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 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 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 (); 553 } 554 555 return _localTimeOfEpoch; 556 } 557 558 561 public String 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 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 625 public void printDate(WriteStream os) 626 throws IOException 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 677 public String 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 735 736 return cb.toString(); 737 } 738 739 742 public String 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 768 public synchronized static String formatGMT(long gmtTime, String format) 769 { 770 _gmtDate.setGMTTime(gmtTime); 771 772 return _gmtDate.format(new CharBuffer(), format).toString(); 773 } 774 775 780 public synchronized static String formatGMT(long gmtTime) 781 { 782 _gmtDate.setGMTTime(gmtTime); 783 784 return _gmtDate.printDate(); 785 } 786 787 793 public synchronized static String formatLocal(long gmtTime, String format) 794 { 795 _localDate.setGMTTime(gmtTime); 796 797 return _localDate.format(new CharBuffer(), format).toString(); 798 } 799 800 805 public synchronized static String formatLocal(long gmtTime) 806 { 807 _localDate.setGMTTime(gmtTime); 808 809 return _localDate.printDate(); 810 } 811 812 818 public synchronized static CharBuffer formatLocal(CharBuffer cb, 819 long gmtTime, 820 String format) 821 { 822 _localDate.setGMTTime(gmtTime); 823 824 return _localDate.format(cb, format); 825 } 826 827 public synchronized static String 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 840 public static QDate getGlobalDate() 841 { 842 return _localDate; 843 } 844 845 848 public String format(String format) 849 { 850 CharBuffer cb = new CharBuffer(); 851 852 return format(cb, format).close(); 853 } 854 855 881 public CharBuffer format(CharBuffer cb, String 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 1022 public String printLocaleDate() 1023 { 1024 _date.setTime(_localTimeOfEpoch); 1025 1026 1029 if (_dateFormat == null) 1030 _dateFormat = DateFormat.getInstance(); 1031 1032 return _dateFormat.format(_date); 1033 } 1034 1035 1041 public long parseLocalDate(String string) throws Exception 1042 { 1043 long time = parseDate(string); 1044 1045 synchronized (this) { 1046 setLocalTime(time); 1047 return getGMTTime(); 1048 } 1049 } 1050 1051 1057 public long parseDate(String string) throws Exception 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 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 (); 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 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 e) { 1133 } 1134 1135 return _localTimeOfEpoch - _zoneOffset; 1136 } catch (Exception e) { 1137 return Long.MAX_VALUE; 1138 } 1139 } 1140 1141 private long parseISO8601Date(String string, int pos) 1142 throws Exception 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 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 ("extra junk at end of ISO date"); 1252 1253 setGMTTime(time); 1254 1255 return _localTimeOfEpoch; 1256 } 1257 1258 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 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 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 string, int pos, int length, int digits) 1300 throws Exception 1301 { 1302 int value = 0; 1303 for (int i = 0; i < digits; i++) { 1304 if (pos >= length) 1305 throw new Exception ("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 ("expected ISO8601 digit"); 1311 } 1312 1313 return value; 1314 } 1315 1316 private int skipWhitespace(String 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 1331 private int scan(String string, int i, CharBuffer cb, boolean dash) 1332 throws Exception 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 (); 1354 1355 return i; 1356 } 1357 1358 private int parseInt(CharBuffer cb) throws Exception 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 (); 1373 } 1374 1375 return sign * value; 1376 } 1377 1378 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 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 1459 private void calculateYear() 1460 { 1461 long days = _dayOfEpoch; 1462 1463 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 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 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 clone() 1543 { 1544 QDate newObj = new QDate(_timeZone); 1545 1546 newObj.calculateSplit(_localTimeOfEpoch); 1547 1548 return newObj; 1549 } 1550 1551 public String toString() 1552 { 1553 return "QDate[" + printDate() + "]"; 1554 } 1555} 1556 | Popular Tags |