1 29 30 package com.caucho.quercus.lib; 31 32 import com.caucho.quercus.annotation.Optional; 33 import com.caucho.quercus.env.*; 34 import com.caucho.quercus.module.AbstractQuercusModule; 35 import com.caucho.util.Alarm; 36 import com.caucho.util.CharBuffer; 37 import com.caucho.util.L10N; 38 import com.caucho.util.QDate; 39 40 import java.util.TimeZone ; 41 import java.util.logging.Level ; 42 import java.util.logging.Logger ; 43 44 47 public class DateModule extends AbstractQuercusModule { 48 private static final L10N L = new L10N(DateModule.class); 49 private static final Logger log 50 = Logger.getLogger(DateModule.class.getName()); 51 52 public static final int CAL_GREGORIAN = 0; 53 public static final int CAL_JULIAN = 1; 54 55 private static final String []_shortDayOfWeek = { 56 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" 57 }; 58 59 private static final String []_fullDayOfWeek = { 60 "Sunday", "Monday", "Tuesday", "Wednesday", 61 "Thursday", "Friday", "Saturday", "Sunday" 62 }; 63 64 private static final String []_shortMonth = { 65 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 66 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 67 }; 68 private static final String []_fullMonth = { 69 "January", "February", "March", "April", "May", "June", 70 "July", "August", "September", "October", "November", "December", 71 }; 72 73 private static final long MINUTE = 60000L; 74 private static final long HOUR = 60 * MINUTE; 75 private static final long DAY = 24 * HOUR; 76 77 private QDate _localCalendar = QDate.createLocal(); 78 private QDate _gmtCalendar = new QDate(); 79 80 83 public static int cal_days_in_month(int cal, int month, int year) 84 { 85 QDate date = new QDate(); 86 87 date.setYear(year); 88 date.setMonth(month - 1); 89 90 return date.getDaysInMonth(); 91 } 92 93 96 public static boolean checkdate(int month, int day, int year) 97 { 98 if (! (1 <= year && year <= 32767)) 99 return false; 100 101 if (! (1 <= month && month <= 12)) 102 return false; 103 104 return 1 <= day && day <= cal_days_in_month(0, month, year); 105 } 106 107 108 111 public String date(String format, 112 @Optional("time()") long time) 113 { 114 return date(format, time, false); 115 } 116 117 120 public static long easter_date(@Optional("-1") int year) 121 { 122 QDate date = new QDate(); 123 124 if (year < 0) { 125 date.setGMTTime(Alarm.getCurrentTime()); 126 127 year = date.getYear(); 128 } 129 130 int y = year; 131 132 int c = y / 100; 133 int n = y - 19 * (y / 19); 134 int k = (c - 17) / 25; 135 int i = c - c /4 - (c - k) / 3 + 19 * n + 15; 136 i = i - 30 * (i / 30); 137 i = i - (i / 28) * (1 - ((i / 28) * 138 (29 / (i + 1)) * 139 ((21 - n) / 11))); 140 141 int j = y + y / 4 + i + 2 - c + c / 4; 142 j = j - 7 * (j / 7); 143 int l = i - j; 144 int m = 3 + (l + 40) / 44; 145 int d = l + 28 - 31 * (m / 4); 146 147 date.setYear(year); 148 date.setMonth(m - 1); 149 date.setDayOfMonth(d); 150 151 return date.getGMTTime() / 1000; 152 } 153 154 157 public static long easter_days(@Optional("-1") int year, 158 @Optional int method) 159 { 160 return easter_date(year); 161 } 162 163 166 public Value getdate(@Optional("time()") long time) 167 { 168 QDate date = new QDate(false); 169 170 date.setLocalTime(1000 * time); 171 172 ArrayValue array = new ArrayValueImpl(); 173 174 array.put("seconds", date.getSecond()); 175 array.put("minutes", date.getMinute()); 176 array.put("hours", date.getHour()); 177 array.put("mday", date.getDayOfMonth()); 178 array.put("wday", date.getDayOfWeek()); 179 array.put("mon", date.getMonth() + 1); 180 array.put("year", date.getYear()); 181 array.put("yday", date.getDayOfYear()); 182 array.put("weekday", _fullDayOfWeek[date.getDayOfWeek()]); 183 array.put("month", _fullMonth[date.getMonth()]); 184 array.put(new LongValue(0), new LongValue(time)); 185 186 return array; 187 } 188 189 public Value gettimeofday(@Optional boolean isFloatReturn) 190 { 191 long gmtTime = Alarm.getCurrentTime(); 192 193 if (isFloatReturn) { 194 return new DoubleValue(((double) Alarm.getCurrentTime()) / 1000.0); 195 } 196 else { 197 ArrayValueImpl result = new ArrayValueImpl(); 198 199 TimeZone localTimeZone = TimeZone.getDefault(); 200 201 long sec = gmtTime / 1000L; 202 long microsec = (gmtTime - (sec * 1000)) * 1000L; 203 long minutesWest = localTimeZone.getRawOffset() / 1000L / 60L * -1L; 204 long dstTime = localTimeZone.useDaylightTime() ? 1 : 0; 205 206 result.put("sec", sec); 207 result.put("usec", microsec); 208 result.put("minuteswest", minutesWest); 209 result.put("dsttime", dstTime); 210 211 return result; 212 } 213 } 214 215 218 public String gmdate(String format, 219 @Optional("time()") long time) 220 { 221 return date(format, time, true); 222 } 223 224 227 public long gmmktime(@Optional("-1") int hour, 228 @Optional("-1") int minute, 229 @Optional("-1") int second, 230 @Optional("-1") int month, 231 @Optional("-1") int day, 232 @Optional("-1") int year) 233 { 234 QDate localDate = new QDate(false); 235 QDate gmtDate = new QDate(false); 236 long now = Alarm.getCurrentTime(); 237 238 localDate.setLocalTime(now); 239 240 long gmtNow = localDate.getGMTTime(); 241 242 gmtDate.setGMTTime(gmtNow); 243 244 if (hour >= 0) 245 gmtDate.setHour(hour); 246 247 if (minute >= 0) 248 gmtDate.setMinute(minute); 249 250 if (second >= 0) 251 gmtDate.setSecond(second); 252 253 if (month > 0) 254 gmtDate.setMonth(month - 1); 255 256 if (day > 0) 257 gmtDate.setDayOfMonth(day); 258 259 if (year > 0) 260 gmtDate.setYear(year); 261 262 return gmtDate.getGMTTime() / 1000L; 263 } 264 265 268 public String gmstrftime(String format, 269 @Optional("-1") long phpTime) 270 { 271 long time; 272 273 if (phpTime == -1) 274 time = Alarm.getCurrentTime(); 275 else 276 time = 1000 * phpTime; 277 278 return QDate.formatGMT(time, format); 279 } 280 281 284 public double gregoriantojd(int month, int day, int year) 285 { 286 if (month <= 2) { 287 year -= 1; 288 month += 12; 289 } 290 291 long a = year / 100; 292 long b = a / 4; 293 long c = 2 - a + b; 294 long e = (long) (365.25 * (year + 4716)); 295 long f = (long) (30.6001 * (month + 1)); 296 297 return (c + day + e + f - 1524.5); 298 } 299 300 303 private String date(String format, 304 long time, 305 boolean isGMT) 306 { 307 long now = 1000 * time; 308 309 QDate calendar = isGMT ? _gmtCalendar : _localCalendar; 310 311 synchronized (calendar) { 312 calendar.setGMTTime(now); 313 314 CharBuffer sb = new CharBuffer(); 315 int len = format.length(); 316 317 for (int i = 0; i < len; i++) { 318 char ch = format.charAt(i); 319 320 switch (ch) { 321 case 'd': 322 { 323 int day = calendar.getDayOfMonth(); 324 sb.append(day / 10); 325 sb.append(day % 10); 326 break; 327 } 328 329 case 'D': 330 { 331 int day = calendar.getDayOfWeek(); 332 333 sb.append(_shortDayOfWeek[day - 1]); 334 break; 335 } 336 337 case 'j': 338 { 339 int day = calendar.getDayOfMonth(); 340 sb.append(day); 341 break; 342 } 343 344 case 'l': 345 { 346 int day = calendar.getDayOfWeek(); 347 348 sb.append(_fullDayOfWeek[day]); 349 break; 350 } 351 352 case 'S': 353 { 354 int day = calendar.getDayOfMonth(); 355 356 switch (day) { 357 case 1: case 21: case 31: 358 sb.append("st"); 359 break; 360 case 2: case 22: 361 sb.append("nd"); 362 break; 363 case 3: case 23: 364 sb.append("rd"); 365 break; 366 default: 367 sb.append("th"); 368 break; 369 } 370 break; 371 } 372 373 case 'w': 374 { 375 int day = calendar.getDayOfWeek(); 376 377 sb.append(day); 378 break; 379 } 380 381 case 'z': 382 { 383 int day = calendar.getDayOfYear(); 384 385 sb.append(day); 386 break; 387 } 388 389 case 'W': 390 { 391 int week = calendar.getWeek(); 392 393 sb.append(week); 394 break; 395 } 396 397 case 'm': 398 { 399 int month = calendar.getMonth() + 1; 400 sb.append(month / 10); 401 sb.append(month % 10); 402 break; 403 } 404 405 case 'M': 406 { 407 int month = calendar.getMonth(); 408 sb.append(_shortMonth[month]); 409 break; 410 } 411 412 case 'F': 413 { 414 int month = calendar.getMonth(); 415 sb.append(_fullMonth[month]); 416 break; 417 } 418 419 case 'n': 420 { 421 int month = calendar.getMonth() + 1; 422 sb.append(month); 423 break; 424 } 425 426 case 't': 427 { 428 int days = calendar.getDaysInMonth(); 429 sb.append(days); 430 break; 431 } 432 433 case 'Y': 434 { 435 int year = calendar.getYear(); 436 437 sb.append((year / 1000) % 10); 438 sb.append((year / 100) % 10); 439 sb.append((year / 10) % 10); 440 sb.append((year) % 10); 441 break; 442 } 443 444 case 'y': 445 { 446 int year = calendar.getYear(); 447 448 sb.append((year / 10) % 10); 449 sb.append((year) % 10); 450 break; 451 } 452 453 case 'L': 454 { 455 if (calendar.isLeapYear()) 456 sb.append(1); 457 else 458 sb.append(0); 459 break; 460 } 461 462 case 'a': 463 { 464 int hour = calendar.getHour(); 465 466 if (hour < 12) 467 sb.append("am"); 468 else 469 sb.append("pm"); 470 break; 471 } 472 473 case 'A': 474 { 475 int hour = calendar.getHour(); 476 477 if (hour < 12) 478 sb.append("AM"); 479 else 480 sb.append("PM"); 481 break; 482 } 483 484 case 'g': 485 { 486 int hour = calendar.getHour() % 12; 487 488 if (hour == 0) 489 hour = 12; 490 491 sb.append(hour); 492 break; 493 } 494 495 case 'G': 496 { 497 int hour = calendar.getHour(); 498 499 sb.append(hour); 500 break; 501 } 502 503 case 'h': 504 { 505 int hour = calendar.getHour() % 12; 506 507 if (hour == 0) 508 hour = 12; 509 510 sb.append(hour / 10); 511 sb.append(hour % 10); 512 break; 513 } 514 515 case 'H': 516 { 517 int hour = calendar.getHour(); 518 519 sb.append(hour / 10); 520 sb.append(hour % 10); 521 break; 522 } 523 524 case 'i': 525 { 526 int minutes = calendar.getMinute(); 527 528 sb.append(minutes / 10); 529 sb.append(minutes % 10); 530 break; 531 } 532 533 case 's': 534 { 535 int seconds = calendar.getSecond(); 536 537 sb.append(seconds / 10); 538 sb.append(seconds % 10); 539 break; 540 } 541 542 case 'O': 543 { 544 long offset = calendar.getZoneOffset(); 545 546 int minute = (int) (offset / (60 * 1000)); 547 548 if (minute < 0) 549 sb.append('-'); 550 else 551 sb.append('+'); 552 553 sb.append((minute / 60) / 10); 554 sb.append((minute / 60) % 10); 555 sb.append((minute / 10) % 10); 556 sb.append(minute % 10); 557 break; 558 } 559 560 case 'I': 561 { 562 if (calendar.isDST()) 563 sb.append('1'); 564 else 565 sb.append('0'); 566 break; 567 } 568 569 case 'T': 570 { 571 TimeZone zone = calendar.getLocalTimeZone(); 572 573 sb.append(zone.getDisplayName(calendar.isDST(), TimeZone.SHORT)); 574 break; 575 } 576 577 case 'Z': 578 { 579 long offset = calendar.getZoneOffset(); 580 581 sb.append(offset / (1000)); 582 break; 583 } 584 585 case 'c': 586 { 587 sb.append(calendar.printISO8601()); 588 break; 589 } 590 591 case 'r': 592 { 593 sb.append(calendar.printDate()); 594 break; 595 } 596 597 case 'U': 598 { 599 sb.append(now / 1000); 600 break; 601 } 602 603 case '\\': 604 sb.append(format.charAt(++i)); 605 break; 606 607 default: 608 sb.append(ch); 609 break; 610 } 611 } 612 613 return sb.toString(); 614 } 615 } 616 617 620 public static Value microtime(@Optional boolean getAsFloat) 621 { 622 long now = Alarm.getExactTimeNanoseconds() / 1000; 623 624 if (getAsFloat) { 625 return new DoubleValue(((double) now) / 1e6); 626 } 627 else { 628 return (new StringBuilderValue() 629 .append(now % 1000000L / 1e6) 630 .append(' ') 631 .append(now / 1000000L)); 632 } 633 } 634 635 638 public long mktime(Env env, 639 @Optional("-1") int hour, 640 @Optional("-1") int minute, 641 @Optional("-1") int second, 642 @Optional("-1") int month, 643 @Optional("-1") int day, 644 @Optional("-1") int year, 645 @Optional("-1") int isDST) 646 { 647 if (isDST != -1) 648 env.deprecatedArgument("isDST"); 649 650 QDate date = new QDate(true); 651 652 long now = Alarm.getCurrentTime(); 653 654 date.setLocalTime(now); 655 656 if (hour >= 0) 657 date.setHour(hour); 658 659 if (minute >= 0) 660 date.setMinute(minute); 661 662 if (second >= 0) 663 date.setSecond(second); 664 665 if (month > 0) 666 date.setMonth(month - 1); 667 668 if (day > 0) 669 date.setDayOfMonth(day); 670 671 if (year > 0) 672 date.setYear(year); 673 674 return date.getGMTTime() / 1000L; 675 } 676 677 680 public String strftime(String format, 681 @Optional("-1") long phpTime) 682 { 683 long time; 684 685 if (phpTime == -1) 686 time = Alarm.getCurrentTime(); 687 else 688 time = 1000 * phpTime; 689 690 return QDate.formatLocal(time, format); 691 } 692 693 696 public Value strtotime(String timeString, 697 @Optional("-1") long now) 698 { 699 try { 700 if (now >= 0) 701 now = 1000L * now; 702 else 703 now = Alarm.getCurrentTime(); 704 705 QDate date = new QDate(true); 706 date.setGMTTime(now); 707 708 if (timeString.equals("")) { 709 date.setHour(0); 710 date.setMinute(0); 711 date.setSecond(0); 712 713 return new LongValue(date.getGMTTime() / 1000L); 714 } 715 716 DateParser parser = new DateParser(timeString, date); 717 718 return new LongValue(parser.parse() / 1000L); 719 } catch (Exception e) { 720 log.log(Level.FINE, e.toString(), e); 721 722 return BooleanValue.FALSE; 723 } 724 } 725 726 729 public static long time() 730 { 731 return Alarm.getCurrentTime() / 1000L; 732 } 733 734 737 public long jdtounix(double jd) 738 { 739 long z = (long) (jd + 0.5); 740 long w = (long) ((z - 1867216.25) / 36524.25); 741 long x = (long) (w / 4); 742 long a = (long) (z + 1 + w - x); 743 long b = (long) (a + 1524); 744 long c = (long) ((b - 122.1) / 365.25); 745 long d = (long) (365.25 * c); 746 long e = (long) ((b - d) / 30.6001); 747 long f = (long) (30.6001 * e); 748 749 long day = b - d - f; 750 long month = e - 1; 751 long year = c - 4716; 752 753 if (month > 12) { 754 month -= 12; 755 year += 1; 756 } 757 758 synchronized (_localCalendar) { 759 _localCalendar.setHour(0); 760 _localCalendar.setMinute(0); 761 _localCalendar.setSecond(0); 762 _localCalendar.setDayOfMonth((int) day); 763 _localCalendar.setMonth((int) (month - 1)); 764 _localCalendar.setYear((int) year); 765 766 return _localCalendar.getLocalTime() / 1000L; 767 } 768 } 769 770 class DateParser { 771 private static final int INT = 1; 772 private static final int PERIOD = 2; 773 private static final int AGO = 3; 774 private static final int AM = 4; 775 private static final int PM = 5; 776 private static final int MONTH = 6; 777 private static final int WEEKDAY = 7; 778 private static final int UTC = 8; 779 780 private static final int UNIT_YEAR = 1; 781 private static final int UNIT_MONTH = 2; 782 private static final int UNIT_FORTNIGHT = 3; 783 private static final int UNIT_WEEK = 4; 784 private static final int UNIT_DAY = 5; 785 private static final int UNIT_HOUR = 6; 786 private static final int UNIT_MINUTE = 7; 787 private static final int UNIT_SECOND = 8; 788 private static final int UNIT_NOW = 9; 789 790 private static final int NULL_VALUE = Integer.MAX_VALUE; 791 792 private QDate _date; 793 794 private String _s; 795 private int _index; 796 private int _length; 797 798 private StringBuilder _sb = new StringBuilder (); 799 800 private int _peekToken; 801 802 private int _value; 803 private int _digits; 804 private int _unit; 805 private int _weekday; 806 807 private boolean _hasDate; 808 private boolean _hasTime; 809 810 DateParser(String s, QDate date) 811 { 812 _date = date; 813 _s = s; 814 _length = s.length(); 815 } 816 817 long parse() 818 { 819 _value = NULL_VALUE; 820 _unit = 0; 821 822 while (true) { 823 int token = nextToken(); 824 825 if (token == '-') { 826 token = nextToken(); 827 828 if (token == INT) 829 _value = -_value; 830 else { 831 _peekToken = token; 832 continue; 833 } 834 } 835 836 if (token < 0) { 837 return _date.getGMTTime(); 838 } 839 else if (token == INT) { 840 int digits = _digits; 841 int value = _value; 842 843 token = nextToken(); 844 845 if (token == PERIOD) { 846 parsePeriod(); 847 } 848 else if (token == ':') { 849 parseTime(); 850 _hasTime = true; 851 } 852 else if (token == '-') { 853 parseISODate(value); 854 _hasDate = true; 855 } 856 else if (token == '/') { 857 parseUSDate(value); 858 _hasDate = true; 859 } 860 else if (token == MONTH) { 861 parseDayMonthDate(value); 862 _hasDate = true; 863 } 864 else { 865 _peekToken = token; 866 867 parseBareInt(value, digits); 868 } 869 } 870 else if (token == PERIOD) { 871 parsePeriod(); 872 } 873 else if (token == WEEKDAY) { 874 addWeekday(_value, _weekday); 875 _value = NULL_VALUE; 876 } 877 else if (token == MONTH) { 878 parseMonthDate(_value); 879 _hasDate = true; 880 } 881 else if (token == '@') { 882 token = nextToken(); 883 884 if (token == INT) { 885 int value = _value; 886 _value = NULL_VALUE; 887 888 _date.setGMTTime(value * 1000L); 889 890 token = nextToken(); 891 if (token == '.') { 892 token = nextToken(); 893 894 if (token != INT) 895 _peekToken = token; 896 } 897 else { 898 _peekToken = token; 899 } 900 } 901 } 902 } 903 } 904 905 private void parsePeriod() 906 { 907 int value = _value; 908 int unit = _unit; 909 910 _value = NULL_VALUE; 911 _unit = 0; 912 913 int token = nextToken(); 914 if (token == AGO) 915 value = -value; 916 else 917 _peekToken = token; 918 919 addTime(value, unit); 920 } 921 922 private void parseISODate(int value1) 923 { 924 int year = _date.getYear(); 925 int month = 0; 926 int day = 0; 927 928 if (value1 < 0) 929 value1 = - value1; 930 931 int token = nextToken(); 932 933 int value2 = 0; 934 935 if (token == INT) { 936 value2 = _value; 937 _value = NULL_VALUE; 938 } 939 else { 940 _peekToken = token; 941 return; 942 } 943 944 token = nextToken(); 945 946 if (token == '-') { 947 token = nextToken(); 948 949 if (token == INT) { 950 if (value1 < 0) 951 _date.setYear(value1); 952 else if (value1 <= 68) 953 _date.setYear(2000 + value1); 954 else if (value1 < 100) 955 _date.setYear(1900 + value1); 956 else 957 _date.setYear(value1); 958 959 _date.setMonth(value2 - 1); 960 _date.setDayOfMonth(_value); 961 } 962 else { 963 _date.setMonth(value1 - 1); 964 _date.setDayOfMonth(value2); 965 966 _peekToken = token; 967 } 968 } 969 else { 970 _date.setMonth(value1 - 1); 971 _date.setDayOfMonth(value2); 972 973 _peekToken = token; 974 } 975 } 976 977 private void parseUSDate(int value1) 978 { 979 int year = _date.getYear(); 980 int month = 0; 981 int day = 0; 982 983 if (value1 < 0) 984 value1 = - value1; 985 986 int token = nextToken(); 987 988 int value2 = 0; 989 990 if (token == INT) { 991 value2 = _value; 992 } 993 else { 994 _peekToken = token; 995 return; 996 } 997 998 _value = NULL_VALUE; 999 token = nextToken(); 1000 1001 if (token == '/') { 1002 token = nextToken(); 1003 1004 if (token == INT) { 1005 _date.setMonth(value1 - 1); 1006 _date.setDayOfMonth(value2); 1007 1008 if (_value < 0) 1009 _date.setYear(_value); 1010 else if (_value <= 68) 1011 _date.setYear(2000 + _value); 1012 else if (_value < 100) 1013 _date.setYear(1900 + _value); 1014 else 1015 _date.setYear(_value); 1016 } 1017 else { 1018 _date.setMonth(value1 - 1); 1019 _date.setDayOfMonth(value2); 1020 1021 _peekToken = token; 1022 } 1023 _value = NULL_VALUE; 1024 } 1025 else { 1026 _date.setMonth(value1 - 1); 1027 _date.setDayOfMonth(value2); 1028 1029 _peekToken = token; 1030 } 1031 } 1032 1033 private void parseDayMonthDate(int value1) 1034 { 1035 int year = _date.getYear(); 1036 int month = 0; 1037 int day = 0; 1038 1039 if (value1 < 0) 1040 value1 = - value1; 1041 1042 int value2 = _value; 1043 1044 _value = NULL_VALUE; 1045 int token = nextToken(); 1046 1047 if (token == '-') { 1048 _value = NULL_VALUE; 1049 token = nextToken(); 1050 } 1051 1052 if (token == INT) { 1053 _date.setDayOfMonth(value1); 1054 _date.setMonth(value2 - 1); 1055 1056 if (_value < 0) 1057 _date.setYear(_value); 1058 else if (_value <= 68) 1059 _date.setYear(2000 + _value); 1060 else if (_value < 100) 1061 _date.setYear(1900 + _value); 1062 else 1063 _date.setYear(_value); 1064 1065 _value = NULL_VALUE; 1066 } 1067 else { 1068 _date.setDayOfMonth(value1); 1069 _date.setMonth(value2 - 1); 1070 1071 _peekToken = token; 1072 } 1073 } 1074 1075 private void parseMonthDate(int value1) 1076 { 1077 if (value1 < 0) 1078 value1 = - value1; 1079 1080 _value = NULL_VALUE; 1081 int token = nextToken(); 1082 1083 if (token == '-') { 1084 _value = NULL_VALUE; 1085 token = nextToken(); 1086 } 1087 1088 if (token == INT) { 1089 int value2 = _value; 1090 1091 _value = NULL_VALUE; 1092 token = nextToken(); 1093 if (token == '-') { 1094 _value = NULL_VALUE; 1095 token = nextToken(); 1096 } 1097 1098 if (token == INT) { 1099 _date.setMonth(value1 - 1); 1100 _date.setDayOfMonth(value2); 1101 1102 if (_value < 0) 1103 _date.setYear(_value); 1104 else if (_value <= 68) 1105 _date.setYear(2000 + _value); 1106 else if (_value < 100) 1107 _date.setYear(1900 + _value); 1108 else 1109 _date.setYear(_value); 1110 1111 _value = NULL_VALUE; 1112 } 1113 else { 1114 _date.setMonth(value1 - 1); 1115 _date.setDayOfMonth(value2); 1116 1117 _peekToken = token; 1118 } 1119 } 1120 else { 1121 _date.setMonth(value1 - 1); 1122 1123 _peekToken = token; 1124 } 1125 } 1126 1127 private void parseTime() 1128 { 1129 int hour = _value; 1130 _value = NULL_VALUE; 1131 1132 if (hour < 0) 1133 hour = - hour; 1134 1135 _date.setHour(hour); 1136 _date.setMinute(0); 1137 _date.setSecond(0); 1138 _date.setMillisecond(0); 1139 1140 int token = nextToken(); 1141 1142 if (token == INT) { 1143 _date.setMinute(_value); 1144 _value = NULL_VALUE; 1145 } 1146 else { 1147 _peekToken = token; 1148 return; 1149 } 1150 1151 token = nextToken(); 1152 1153 if (token == ':') { 1154 token = nextToken(); 1155 1156 if (token == INT) { 1157 _date.setSecond(_value); 1158 _value = NULL_VALUE; 1159 } 1160 else { 1161 _peekToken = token; 1162 return; 1163 } 1164 1165 token = nextToken(); 1166 1167 if (token == '.') { token = nextToken(); 1169 1170 _value = NULL_VALUE; 1171 if (token != INT) { 1172 _peekToken = token; 1173 return; 1174 } 1175 } 1176 } 1177 1178 if (token == AM) { 1179 hour = _date.getHour(); 1180 1181 if (hour == 12) 1182 _date.setHour(0); 1183 } 1184 else if (token == PM) { 1185 hour = _date.getHour(); 1186 1187 if (hour == 12) 1188 _date.setHour(12); 1189 else 1190 _date.setHour(hour + 12); 1191 } 1192 else 1193 _peekToken = token; 1194 1195 parseTimezone(); 1196 } 1197 1198 private void parseTimezone() 1199 { 1200 int token = nextToken(); 1201 int sign = 1; 1202 boolean hasUTC = false; 1203 1204 if (token == UTC) { 1205 token = nextToken(); 1206 1207 hasUTC = true; 1208 } 1209 1210 if (token == '-') 1211 sign = -1; 1212 else if (token == '+') 1213 sign = 1; 1214 else { 1215 _peekToken = token; 1216 1217 if (hasUTC) 1218 _date.setGMTTime(_date.getGMTTime() + _date.getZoneOffset()); 1219 1220 return; 1221 } 1222 1223 int offset = 0; 1224 1225 token = nextToken(); 1226 if (token != INT) { 1227 _peekToken = token; 1228 1229 if (hasUTC) 1230 _date.setGMTTime(_date.getGMTTime() + _date.getZoneOffset()); 1231 1232 return; 1233 } 1234 else if (_digits == 4) { 1235 int value = sign * _value; 1236 _value = NULL_VALUE; 1237 1238 _date.setGMTTime(_date.getGMTTime() - value * 60000L + _date.getZoneOffset()); 1239 return; 1240 } 1241 else if (_digits == 2) { 1242 int value = _value; 1243 1244 token = nextToken(); 1245 1246 if (token != ':') { 1247 _value = sign * _value; 1248 _peekToken = token; 1249 1250 if (hasUTC) 1251 _date.setGMTTime(_date.getGMTTime() + _date.getZoneOffset()); 1252 return; 1253 } 1254 1255 value = sign * (100 * value + _value); 1256 1257 _date.setGMTTime(_date.getGMTTime() - value * 60000L + _date.getZoneOffset()); 1258 return; 1259 } 1260 else { 1261 _value = sign * _value; 1262 _peekToken = token; 1263 1264 if (hasUTC) 1265 _date.setGMTTime(_date.getGMTTime() + _date.getZoneOffset()); 1266 1267 return; 1268 } 1269 } 1270 1271 private void addTime(int value, int unit) 1272 { 1273 if (value == NULL_VALUE) 1274 value = 1; 1275 else if (value == -NULL_VALUE) 1276 value = -1; 1277 1278 switch (unit) { 1279 case UNIT_YEAR: 1280 _date.setYear(_date.getYear() + value); 1281 break; 1282 case UNIT_MONTH: 1283 _date.setMonth(_date.getMonth() + value); 1284 break; 1285 case UNIT_FORTNIGHT: 1286 _date.setGMTTime(_date.getGMTTime() + 14 * DAY * value); 1287 break; 1288 case UNIT_WEEK: 1289 _date.setGMTTime(_date.getGMTTime() + 7 * DAY * value); 1290 break; 1291 case UNIT_DAY: 1292 _date.setGMTTime(_date.getGMTTime() + DAY * value); 1293 break; 1294 case UNIT_HOUR: 1295 _date.setGMTTime(_date.getGMTTime() + HOUR * value); 1296 break; 1297 case UNIT_MINUTE: 1298 _date.setGMTTime(_date.getGMTTime() + MINUTE * value); 1299 break; 1300 case UNIT_SECOND: 1301 _date.setGMTTime(_date.getGMTTime() + 1000L * value); 1302 break; 1303 } 1304 } 1305 1306 private void addWeekday(int value, int weekday) 1307 { 1308 if (value == NULL_VALUE) 1309 value = 0; 1310 else if (value == -NULL_VALUE) 1311 value = -1; 1312 1313 _date.setDayOfMonth(_date.getDayOfMonth() + 1314 (8 + weekday - _date.getDayOfWeek()) % 7 + 1315 7 * value); 1316 } 1317 1318 private void parseBareInt(int value, int digits) 1319 { 1320 if (digits == 8 && ! _hasDate) { 1321 _hasDate = true; 1322 1323 _date.setYear(value / 10000); 1324 _date.setMonth((value / 100 % 12) - 1); 1325 _date.setDayOfMonth(value % 100); 1326 } 1327 else if (digits == 6 && ! _hasTime) { 1328 _hasTime = true; 1329 _date.setHour(value / 10000); 1330 _date.setMinute(value / 100 % 100); 1331 _date.setSecond(value % 100); 1332 1333 parseTimezone(); 1334 } 1335 else if (digits == 4 && ! _hasTime) { 1336 _hasTime = true; 1337 _date.setHour(value / 100); 1338 _date.setMinute(value % 100); 1339 _date.setSecond(0); 1340 parseTimezone(); 1341 } 1342 else if (digits == 2 && ! _hasTime) { 1343 _hasTime = true; 1344 _date.setHour(value); 1345 _date.setMinute(0); 1346 _date.setSecond(0); 1347 parseTimezone(); 1348 } 1349 1350 int token = nextToken(); 1351 if (token == '.') { 1352 _value = NULL_VALUE; 1353 token = nextToken(); 1354 1355 if (token == INT) 1356 _value = NULL_VALUE; 1357 else 1358 _peekToken = token; 1359 } 1360 else 1361 _peekToken = token; 1362 } 1363 1364 int nextToken() 1365 { 1366 if (_peekToken > 0) { 1367 int token = _peekToken; 1368 _peekToken = 0; 1369 return token; 1370 } 1371 1372 while (true) { 1373 skipSpaces(); 1374 1375 int ch = read(); 1376 1377 if (ch < 0) 1378 return -1; 1379 else if (ch == '-') 1380 return '-'; 1381 else if (ch == '+') 1382 return '+'; 1383 else if (ch == ':') 1384 return ':'; 1385 else if (ch == '.') 1386 return '.'; 1387 else if (ch == '/') 1388 return '/'; 1389 else if (ch == '@') 1390 return '@'; 1391 else if ('0' <= ch && ch <= '9') { 1392 int value = 0; 1393 int digits = 0; 1394 1395 for (; '0' <= ch && ch <= '9'; ch = read()) { 1396 digits++; 1397 value = 10 * value + ch - '0'; 1398 } 1399 1400 _value = value; 1401 _digits = digits; 1402 1403 unread(); 1404 1405 return INT; 1406 } 1407 else if ('a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z') { 1408 _sb.setLength(0); 1409 1410 for (; 1411 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '.'; 1412 ch = read()) { 1413 _sb.append(Character.toLowerCase((char) ch)); 1414 } 1415 1416 unread(); 1417 1418 String s = _sb.toString(); 1419 1420 return parseString(s); 1421 } 1422 else { 1423 } 1425 } 1426 } 1427 1428 private int parseString(String s) 1429 { 1430 if (s.endsWith(".")) 1431 s = s.substring(0, s.length() - 1); 1432 1433 if ("now".equals(s) || 1434 "today".equals(s)) { 1435 _value = 0; 1436 _unit = UNIT_NOW; 1437 return PERIOD; 1438 } 1439 else if ("last".equals(s)) { 1440 _value = -1; 1441 return INT; 1442 } 1443 else if ("this".equals(s)) { 1444 _value = 0; 1445 return INT; 1446 } 1447 else if ("am".equals(s) || "a.m".equals(s)) { 1448 return AM; 1449 } 1450 else if ("pm".equals(s) || "p.m".equals(s)) { 1451 return PM; 1452 } 1453 else if ("next".equals(s)) { 1454 _value = 1; 1455 return INT; 1456 } 1457 else if ("third".equals(s)) { 1458 _value = 3; 1459 return INT; 1460 } 1461 else if ("fourth".equals(s)) { 1462 _value = 4; 1463 return INT; 1464 } 1465 else if ("fifth".equals(s)) { 1466 _value = 5; 1467 return INT; 1468 } 1469 else if ("sixth".equals(s)) { 1470 _value = 6; 1471 return INT; 1472 } 1473 else if ("seventh".equals(s)) { 1474 _value = 7; 1475 return INT; 1476 } 1477 else if ("eighth".equals(s)) { 1478 _value = 8; 1479 return INT; 1480 } 1481 else if ("ninth".equals(s)) { 1482 _value = 9; 1483 return INT; 1484 } 1485 else if ("tenth".equals(s)) { 1486 _value = 10; 1487 return INT; 1488 } 1489 else if ("eleventh".equals(s)) { 1490 _value = 11; 1491 return INT; 1492 } 1493 else if ("twelfth".equals(s)) { 1494 _value = 12; 1495 return INT; 1496 } 1497 else if ("yesterday".equals(s)) { 1498 _value = -1; 1499 _unit = UNIT_DAY; 1500 return PERIOD; 1501 } 1502 else if ("tomorrow".equals(s)) { 1503 _value = 1; 1504 _unit = UNIT_DAY; 1505 return PERIOD; 1506 } 1507 else if ("ago".equals(s)) { 1508 return AGO; 1509 } 1510 else if ("year".equals(s) || "years".equals(s)) { 1511 _unit = UNIT_YEAR; 1512 return PERIOD; 1513 } 1514 else if ("month".equals(s) || "months".equals(s)) { 1515 _unit = UNIT_MONTH; 1516 return PERIOD; 1517 } 1518 else if ("fortnight".equals(s) || "fortnights".equals(s)) { 1519 _unit = UNIT_FORTNIGHT; 1520 return PERIOD; 1521 } 1522 else if ("week".equals(s) || "weeks".equals(s)) { 1523 _unit = UNIT_WEEK; 1524 return PERIOD; 1525 } 1526 else if ("day".equals(s) || "days".equals(s)) { 1527 _unit = UNIT_DAY; 1528 return PERIOD; 1529 } 1530 else if ("hour".equals(s) || "hours".equals(s)) { 1531 _unit = UNIT_HOUR; 1532 return PERIOD; 1533 } 1534 else if ("minute".equals(s) || "minutes".equals(s)) { 1535 _unit = UNIT_MINUTE; 1536 return PERIOD; 1537 } 1538 else if ("second".equals(s) || "seconds".equals(s)) { 1539 _unit = UNIT_SECOND; 1540 return PERIOD; 1541 } 1542 else if ("second".equals(s) || "seconds".equals(s)) { 1543 _unit = UNIT_SECOND; 1544 return PERIOD; 1545 } 1546 else if ("january".equals(s) || "jan".equals(s)) { 1547 _value = 1; 1548 return MONTH; 1549 } 1550 else if ("february".equals(s) || "feb".equals(s)) { 1551 _value = 2; 1552 return MONTH; 1553 } 1554 else if ("march".equals(s) || "mar".equals(s)) { 1555 _value = 3; 1556 return MONTH; 1557 } 1558 else if ("april".equals(s) || "apr".equals(s)) { 1559 _value = 4; 1560 return MONTH; 1561 } 1562 else if ("may".equals(s)) { 1563 _value = 5; 1564 return MONTH; 1565 } 1566 else if ("june".equals(s) || "jun".equals(s)) { 1567 _value = 6; 1568 return MONTH; 1569 } 1570 else if ("july".equals(s) || "jul".equals(s)) { 1571 _value = 7; 1572 return MONTH; 1573 } 1574 else if ("august".equals(s) || "aug".equals(s)) { 1575 _value = 8; 1576 return MONTH; 1577 } 1578 else if ("september".equals(s) || "sep".equals(s) || "sept".equals(s)) { 1579 _value = 9; 1580 return MONTH; 1581 } 1582 else if ("october".equals(s) || "oct".equals(s)) { 1583 _value = 10; 1584 return MONTH; 1585 } 1586 else if ("november".equals(s) || "nov".equals(s)) { 1587 _value = 11; 1588 return MONTH; 1589 } 1590 else if ("december".equals(s) || "dec".equals(s)) { 1591 _value = 12; 1592 return MONTH; 1593 } 1594 else if ("sunday".equals(s) || "sun".equals(s)) { 1595 _weekday = 0; 1596 return WEEKDAY; 1597 } 1598 else if ("monday".equals(s) || "mon".equals(s)) { 1599 _weekday = 1; 1600 return WEEKDAY; 1601 } 1602 else if ("tuesday".equals(s) || "tue".equals(s) || "tues".equals(s)) { 1603 _weekday = 2; 1604 return WEEKDAY; 1605 } 1606 else if ("wednesday".equals(s) || "wed".equals(s) || 1607 "wednes".equals(s)) { 1608 _weekday = 3; 1609 return WEEKDAY; 1610 } 1611 else if ("thursday".equals(s) || "thu".equals(s) || 1612 "thur".equals(s) || "thurs".equals(s)) { 1613 _weekday = 4; 1614 return WEEKDAY; 1615 } 1616 else if ("friday".equals(s) || "fri".equals(s)) { 1617 _weekday = 5; 1618 return WEEKDAY; 1619 } 1620 else if ("saturday".equals(s) || "sat".equals(s)) { 1621 _weekday = 6; 1622 return WEEKDAY; 1623 } 1624 else if ("z".equals(s) || "gmt".equals(s) || "utc".equals(s)) { 1625 return UTC; 1626 } 1627 else 1628 return 0; 1629 } 1630 1631 private void skipSpaces() 1632 { 1633 while (true) { 1634 int ch = read(); 1635 1636 if (Character.isWhitespace((char) ch)) { 1637 continue; 1638 } 1639 else if (ch == '(') { 1640 for (ch = read(); ch > 0 && ch != ')'; ch = read()) { 1641 } 1642 } 1643 else { 1644 unread(); 1645 return; 1646 } 1647 } 1648 } 1649 1650 int read() 1651 { 1652 if (_index < _length) 1653 return _s.charAt(_index++); 1654 else { 1655 _index++; 1656 return -1; 1657 } 1658 } 1659 1660 void unread() 1661 { 1662 _index--; 1663 } 1664 } 1665} 1666 1667 | Popular Tags |