001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.util;
028:
029: import java.util.Hashtable;
030:
031: /**
032: * This class implements somewhat of a subset of the J2SE Date class.
033: * However, since the semantics of parse() is slightly different
034: * (DateParser will not handle dates prior to 1/1/1970, amd to
035: * be able to provide methods that will set timezone and DST
036: * information, it is called DateParser.
037: */
038: public class DateParser {
039: /** The year represented by this date */
040: protected int year;
041: /** The month represented by this date */
042: protected int month;
043: /** The day of the month represented by this date */
044: protected int day;
045: /** The hour represented by this date */
046: protected int hour;
047: /** The minute represented by this date */
048: protected int minute;
049: /** The second represented by this date */
050: protected int second;
051: /** The millisecond represented by this date */
052: protected int milli;
053: /** The offset, in milliseconds, from GMT represented by this date */
054: protected int tzoffset;
055: /** The offset, in milliseconds, from GMT for the local time zone */
056: protected static int local_tz;
057:
058: /**
059: * Allocates a <code>DateParser</code> object and initializes it so that
060: * it represents the instant at the start of the second specified
061: * by the <code>year</code>, <code>month</code>, <code>date</code>,
062: * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments,
063: * in the local time zone.
064: *
065: * @param inp_year the year, >= 1583.
066: * @param inp_month the month between 0-11.
067: * @param inp_day the day of the month between 1-31.
068: * @param inp_hour the hours between 0-23.
069: * @param inp_minute the minutes between 0-59.
070: * @param inp_second the seconds between 0-59.
071: */
072: DateParser(int inp_year, int inp_month, int inp_day, int inp_hour,
073: int inp_minute, int inp_second) {
074: if (inp_year < 1583
075: || inp_month < 0
076: || inp_month > 11
077: || inp_day < 0
078: || (inp_day > days_in_month[inp_month] && !(inp_month == 1
079: && inp_day == 29 && inp_year % 4 == 0))
080: || inp_hour < 0 || inp_hour > 23 || inp_minute < 0
081: || inp_minute > 59 || inp_second < 0 || inp_second > 59) {
082: throw new IllegalArgumentException();
083: }
084:
085: year = inp_year;
086: month = inp_month;
087: day = inp_day;
088: hour = inp_hour;
089: minute = inp_minute;
090: second = inp_second;
091: milli = 0;
092: }
093:
094: /**
095: * Allocates a <code>DateParser</code> object and initializes it so that
096: * it represents the date and time indicated by the string
097: * <code>s</code>, which is interpreted as if by the
098: * {@link DateParser#parse} method.
099: *
100: * @param s a string representation of the date.
101: */
102: DateParser(String s) {
103: internalParse(s);
104: }
105:
106: /**
107: * Allocates a <code>DateParser</code> object and initializes it so that
108: * it represents the date and time indicated by the string
109: * <code>s</code>, which is interpreted as if by the
110: * {@link DateParser#parse} method.
111: *
112: * @param s a string representation of the date.
113: */
114: DateParser(String s, boolean iso) {
115: if (iso == false) {
116: internalParse(s);
117: } else {
118: internalParseISO(s);
119: }
120: }
121:
122: /**
123: * Set the local time zone for the DateParser class.
124: * <code>tz</code> must in abbreviated format, e.g. "PST"
125: * for Pacific Standard Time.
126: *
127: * @param tz The time zone string in abbreviated format.
128: */
129: static void setTimeZone(String tz) {
130: if (timezones.get(tz) == null) {
131: return;
132: }
133: local_tz = ((Integer) timezones.get(tz)).intValue();
134: }
135:
136: /**
137: * Attempts to interpret the string <tt>s</tt> as a representation
138: * of a date and time. If the attempt is successful, the time
139: * indicated is returned represented as teh distance, measured in
140: * milliseconds, of that time from the epoch (00:00:00 GMT on
141: * January 1, 1970). If the attempt fails, an
142: * <tt>IllegalArgumentException</tt> is thrown.
143: * <p>
144: * It accepts many syntaxes; in particular, it recognizes the IETF
145: * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
146: * understands the continental U.S. time-zone abbreviations, but for
147: * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
148: * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
149: * meridian). If no time zone is specified, the local time zone is
150: * assumed. GMT and UTC are considered equivalent.
151: * <p>
152: * The string <tt>s</tt> is processed from left to right, looking for
153: * data of interest. Any material in <tt>s</tt> that is within the
154: * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored.
155: * Parentheses may be nested. Otherwise, the only characters permitted
156: * within <tt>s</tt> are these ASCII characters:
157: * <blockquote><pre>
158: * abcdefghijklmnopqrstuvwxyz
159: * ABCDEFGHIJKLMNOPQRSTUVWXYZ
160: * 0123456789,+-:/</pre></blockquote>
161: * and whitespace characters.<p>
162: * A consecutive sequence of decimal digits is treated as a decimal
163: * number:<ul>
164: * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year
165: * has already been recognized, then the number is a time-zone
166: * offset. If the number is less than 24, it is an offset measured
167: * in hours. Otherwise, it is regarded as an offset in minutes,
168: * expressed in 24-hour time format without punctuation. A
169: * preceding <tt>-</tt> means a westward offset. Time zone offsets
170: * are always relative to UTC (Greenwich). Thus, for example,
171: * <tt>-5</tt> occurring in the string would mean "five hours west
172: * of Greenwich" and <tt>+0430</tt> would mean "four hours and
173: * thirty minutes east of Greenwich." It is permitted for the
174: * string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt>
175: * redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
176: * <li>If a number is greater than 70, it is regarded as a year number.
177: * It must be followed by a space, comma, slash, or end of string.
178: * <li>If the number is followed by a colon, it is regarded as an hour,
179: * unless an hour has already been recognized, in which case it is
180: * regarded as a minute.
181: * <li>If the number is followed by a slash, it is regarded as a month
182: * (it is decreased by 1 to produce a number in the range <tt>0</tt>
183: * to <tt>11</tt>), unless a month has already been recognized, in
184: * which case it is regarded as a day of the month.
185: * <li>If the number is followed by whitespace, a comma, a hyphen, or
186: * end of string, then if an hour has been recognized but not a
187: * minute, it is regarded as a minute; otherwise, if a minute has
188: * been recognized but not a second, it is regarded as a second;
189: * otherwise, it is regarded as a day of the month. </ul><p>
190: * A consecutive sequence of letters is regarded as a word and treated
191: * as follows:<ul>
192: * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but
193: * the parse fails if an hour has not been recognized or is less
194: * than <tt>1</tt> or greater than <tt>12</tt>).
195: * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt>
196: * to the hour (but the parse fails if an hour has not been
197: * recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
198: * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY,
199: * WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring
200: * case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and
201: * <tt>Thurs</tt> are ignored.
202: * <li>Otherwise, any word that matches any prefix of <tt>JANUARY,
203: * FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
204: * OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and
205: * considering them in the order given here, is recognized as
206: * specifying a month and is converted to a number (<tt>0</tt> to
207: * <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and
208: * <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which
209: * is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
210: * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring
211: * case, is treated as referring to UTC.
212: * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
213: * ignoring case, is recognized as referring to the time zone in
214: * North America that is five, six, seven, or eight hours west of
215: * Greenwich, respectively. Any word that matches <tt>EDT, CDT,
216: * MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
217: * referring to the same time zone, respectively, during daylight
218: * saving time.</ul><p>
219: * Once the entire string s has been scanned, it is converted to a time
220: * result in one of two ways. If a time zone or time-zone offset has been
221: * recognized, then the year, month, day of month, hour, minute, and
222: * second are interpreted in UTC and then the time-zone offset is
223: * applied. Otherwise, the year, month, day of month, hour, minute, and
224: * second are interpreted in the local time zone.
225: *
226: * @param s a string to be parsed as a date.
227: * @return the distance in milliseconds from January 1, 1970, 00:00:00 GMT
228: * represented by the string argument. Note that this method will
229: * throw an <code>IllegalArgumentException</code> if the year
230: * indicated in <code>s</code> is less than 1583.
231: */
232: public static long parse(String s) {
233: return (new DateParser(s)).getTime();
234: }
235:
236: /**
237: * Parses a date string according to the ISO 8601 standard.
238: *
239: * @param date the date string in the format YYYY-MM-DDTHH:MM[:SS][[+|-]
240: * HH[MM]]
241: * @return the number of milliseconds elapsed since 1970-1-1 GMT to this
242: * date
243: * @throws IllegalArgumentException if the format of the date string is
244: * incorrect or the date is invalid
245: */
246: public static long parseISO(String date) {
247: return (new DateParser(date, true)).getTime();
248: }
249:
250: private void internalParseISO(String date) {
251: int field[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
252: int field_ptr = 0;
253: boolean field_ok;
254:
255: int c = -1;
256: int i = 0;
257: int num_dig = 4; /* 4 digits for YEAR and 2 for the rest fields */
258: int n = -1;
259: int prevc = 0;
260:
261: if (date == null) {
262: throw new IllegalArgumentException();
263: }
264:
265: int limit = date.length();
266: while (i < limit) {
267: /* read next char */
268: c = date.charAt(i);
269: i++;
270: if (c == '+' || c == '-' || c == 'Z' || c == ' '
271: || c == 'T' || c == ':') {
272: prevc = c;
273: continue;
274: }
275:
276: /* it is digit */
277: if (c < '0' || '9' < c) {
278: throw new IllegalArgumentException();
279: } else {
280: n = c - '0';
281: num_dig--;
282: while (i < limit && num_dig > 0) {
283: if ('0' <= (c = date.charAt(i)) && c <= '9') {
284: n = n * 10 + c - '0';
285: i++;
286: num_dig--;
287: } else
288: break;
289: }
290: num_dig = 2; /* only tear has 4 digits, the rest - 2 */
291:
292: field_ok = false;
293: switch (field_ptr) {
294: case 0: /* year */
295: if (prevc == 0)
296: field_ok = true;
297: break;
298: case 1: /* month */
299: if ((prevc == '-') || (prevc == 0))
300: field_ok = true;
301: break;
302: case 2: /* day */
303: if ((prevc == '-') || (prevc == 0))
304: field_ok = true;
305: break;
306: case 3: /* hour */
307: if ((prevc == ' ') || (prevc == 'T'))
308: field_ok = true;
309: break;
310: case 4: /* min */
311: if ((prevc == ':') || (prevc == 0))
312: field_ok = true;
313: break;
314: case 5: /* sec */
315: if ((prevc == ':') || (prevc == 0)) {
316: field_ok = true;
317: } else if ((prevc == '+') || (prevc == '-')) {
318: field[field_ptr++] = 0;
319: field[field_ptr++] = (prevc == '-') ? -1 : +1;
320: field_ok = true;
321: }
322: break;
323: /* tz_sign can not be reached here */
324: case 7: /* tz_hour */
325: if ((prevc == '+') || (prevc == '-')
326: || (prevc == 0)) {
327: field[field_ptr++] = (prevc == '-') ? -1 : +1;
328: field_ok = true;
329: }
330: break;
331: case 8: /* tz_min */
332: if ((prevc == ':') || (prevc == 0)) {
333: field_ok = true;
334: }
335: break;
336: }
337: if (field_ok) {
338: field[field_ptr++] = n;
339: } else {
340: throw new IllegalArgumentException();
341: }
342: prevc = 0;
343: }
344: }
345:
346: if ((field_ptr >= 5) || (prevc == 'Z')) {
347: field_ptr = 9;
348: }
349: if (field_ptr < 8) {
350: throw new IllegalArgumentException();
351: }
352:
353: year = field[0];
354: month = field[1] - 1;
355: day = field[2];
356: hour = field[3];
357: minute = field[4];
358: second = field[5];
359: tzoffset = field[6]
360: * ((((field[7] * 60) + field[8]) * 60) * 1000);
361: milli = 0;
362: }
363:
364: /**
365: * Get the year represented by this date.
366: *
367: * @return The year.
368: */
369: int getYear() {
370: return year;
371: }
372:
373: /**
374: * Get the month represented by this date.
375: *
376: * @return The month.
377: */
378: int getMonth() {
379: return month;
380: }
381:
382: /**
383: * Get the day of the month represented by this date.
384: *
385: * @return The day of the month.
386: */
387: int getDay() {
388: return day;
389: }
390:
391: /**
392: * Get the hour represented by this date.
393: *
394: * @return The hour.
395: */
396: int getHour() {
397: return hour;
398: }
399:
400: /**
401: * Get the minute represented by this date.
402: *
403: * @return The minute.
404: */
405: int getMinute() {
406: return minute;
407: }
408:
409: /**
410: * Get the second represented by this date.
411: *
412: * @return The second.
413: */
414: int getSecond() {
415: return second;
416: }
417:
418: /**
419: * Calculate the number of milliseconds since 01/01/1970 represented
420: * by this date.
421: *
422: * @return the number of milliseconds.
423: */
424: long getTime() {
425: long julianDay = computeJulianDay(year, month, day);
426: long millis = julianDayToMillis(julianDay);
427:
428: int millisInDay = 0;
429: millisInDay += hour;
430: millisInDay *= 60;
431: millisInDay += minute; // now have minutes
432: millisInDay *= 60;
433: millisInDay += second; // now have seconds
434: millisInDay *= 1000;
435: millisInDay += milli; // now have millis
436:
437: return millis + millisInDay - tzoffset;
438: }
439:
440: /**
441: * Calculate the number of Julian days since Jan 1, year 1 as
442: * represented by the <code>year</code>, <code>month</code>,
443: * and <code>day</code>.
444: *
445: * @param inp_year The Gegorian year
446: * @param inp_month The month
447: * @param inp_day The day of the month <code>month</code>
448: * @return the number of Julian days.
449: */
450: private final long computeJulianDay(int inp_year, int inp_month,
451: int inp_day) {
452: int y;
453:
454: boolean isLeap = inp_year % 4 == 0;
455: y = inp_year - 1;
456: long julianDay = 365L * y + floorDivide(y, 4)
457: + (JAN_1_1_JULIAN_DAY - 3);
458:
459: isLeap = isLeap
460: && ((inp_year % 100 != 0) || (inp_year % 400 == 0));
461: // Add 2 because Gregorian calendar starts 2 days after Julian calendar
462: julianDay += floorDivide(y, 400) - floorDivide(y, 100) + 2;
463: julianDay += isLeap ? LEAP_NUM_DAYS[inp_month]
464: : NUM_DAYS[inp_month];
465: julianDay += inp_day;
466:
467: return julianDay;
468: }
469:
470: /**
471: * Divide two long integers, returning the floor of the quotient.
472: * <p>
473: * Unlike the built-in division, this is mathematically well-behaved.
474: * E.g., <code>-1/4</code> => 0
475: * but <code>floorDivide(-1,4)</code> => -1.
476: * @param numerator the numerator
477: * @param denominator a divisor which must be > 0
478: * @return the floor of the quotient.
479: */
480: private static final long floorDivide(long numerator,
481: long denominator) {
482: // We do this computation in order to handle
483: // a numerator of Long.MIN_VALUE correctly
484: return (numerator >= 0) ? numerator / denominator
485: : ((numerator + 1) / denominator) - 1;
486: }
487:
488: // public String toString() {
489: // return "" + month + "/" + day + "/" + year
490: // + " " + hour + ":" + minute + ":" + second;
491: // }
492:
493: /**
494: * Convert the Julian day, <code>julian</code> into milliseconds.
495: *
496: * @param julian Number of days since Jan 1, year 1 (Julian).
497: * @return the number of millis since the 01/01/1970.
498: */
499: private long julianDayToMillis(long julian) {
500: return (julian - julianDayOffset) * millisPerDay;
501: }
502:
503: /**
504: * Parse the date string <code>s</code>
505: *
506: * @param s a string representation of the date.
507: */
508: private void internalParse(String s) {
509: int inp_year = -1;
510: int mon = -1;
511: int mday = -1;
512: int inp_hour = -1;
513: int min = -1;
514: int sec = -1;
515: int c = -1;
516: int i = 0;
517: int n = -1;
518: int inp_tzoffset = -1;
519: int prevc = 0;
520:
521: syntax: {
522: if (s == null)
523: break syntax;
524: int limit = s.length();
525: while (i < limit) {
526: c = s.charAt(i);
527: i++;
528: if (c <= ' ' || c == ',')
529: continue;
530: if (c == '(') { // skip comments
531: int depth = 1;
532: while (i < limit) {
533: c = s.charAt(i);
534: i++;
535: if (c == '(')
536: depth++;
537: else if (c == ')')
538: if (--depth <= 0)
539: break;
540: }
541: continue;
542: }
543: if ('0' <= c && c <= '9') {
544: n = c - '0';
545: while (i < limit && '0' <= (c = s.charAt(i))
546: && c <= '9') {
547: n = n * 10 + c - '0';
548: i++;
549: }
550: if (prevc == '+' || prevc == '-' && inp_year >= 0) {
551: // timezone offset
552: if (n < 24)
553: n = n * 60; // EG. "GMT-3"
554: else
555: n = n % 100 + n / 100 * 60; // eg "GMT-0430"
556: if (prevc == '+') // plus means east of GMT
557: n = -n;
558: if (inp_tzoffset != 0 && inp_tzoffset != -1)
559: break syntax;
560: inp_tzoffset = n;
561: } else if (n >= 70)
562: if (inp_year >= 0)
563: break syntax;
564: else if (c <= ' ' || c == ',' || c == '/'
565: || i >= limit)
566: // year = n < 1900 ? n : n - 1900;
567: inp_year = n < 100 ? n + 1900 : n;
568: else
569: break syntax;
570: else if (c == ':')
571: if (inp_hour < 0)
572: inp_hour = (byte) n;
573: else if (min < 0)
574: min = (byte) n;
575: else
576: break syntax;
577: else if (c == '/')
578: if (mon < 0)
579: mon = (byte) (n - 1);
580: else if (mday < 0)
581: mday = (byte) n;
582: else
583: break syntax;
584: else if (i < limit && c != ',' && c > ' '
585: && c != '-')
586: break syntax;
587: else if (inp_hour >= 0 && min < 0)
588: min = (byte) n;
589: else if (min >= 0 && sec < 0)
590: sec = (byte) n;
591: else if (mday < 0)
592: mday = (byte) n;
593: else
594: break syntax;
595: prevc = 0;
596: } else if (c == '/' || c == ':' || c == '+' || c == '-')
597: prevc = c;
598: else {
599: int st = i - 1;
600: while (i < limit) {
601: c = s.charAt(i);
602: if (!('A' <= c && c <= 'Z' || 'a' <= c
603: && c <= 'z'))
604: break;
605: i++;
606: }
607: if (i <= st + 1)
608: break syntax;
609: int k;
610: for (k = wtb.length; --k >= 0;)
611: if (wtb[k]
612: .regionMatches(true, 0, s, st, i - st)) {
613: int action = ttb[k];
614: if (action != 0) {
615: if (action == 1) { // pm
616: if (inp_hour > 12 || inp_hour < 1)
617: break syntax;
618: else if (inp_hour < 12)
619: inp_hour += 12;
620: } else if (action == 14) { // am
621: if (inp_hour > 12 || inp_hour < 1)
622: break syntax;
623: else if (inp_hour == 12)
624: inp_hour = 0;
625: } else if (action <= 13) { // month!
626: if (mon < 0)
627: mon = (byte) (action - 2);
628: else
629: break syntax;
630: } else {
631: inp_tzoffset = action - 10000;
632: }
633: }
634: break;
635: }
636: if (k < 0)
637: break syntax;
638: prevc = 0;
639: }
640: }
641: if (inp_year < 1583 || mon < 0 || mday < 0)
642: break syntax;
643: if (sec < 0)
644: sec = 0;
645: if (min < 0)
646: min = 0;
647: if (inp_hour < 0)
648: inp_hour = 0;
649:
650: year = inp_year;
651: month = mon;
652: day = mday;
653: hour = inp_hour;
654: tzoffset = -inp_tzoffset * 60 * 1000;
655: minute = min;
656: second = sec;
657: milli = 0;
658: return;
659: }
660: // syntax error
661: throw new IllegalArgumentException();
662: }
663:
664: /** A table of valid timezones */
665: private static Hashtable timezones;
666:
667: /** Number of days in each month in a non leap year */
668: private int[] days_in_month = { 31, 28, 31, 30, 31, 30, 31, 31, 30,
669: 31, 30, 31 };
670: /** Short versions of the month strings */
671: private String[] month_shorts = { "Jan", "Feb", "Mar", "Apr",
672: "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
673: /** Short versions of the weekday strings */
674: private String[] weekday_shorts = { "Mon", "Tue", "Wed", "Thu",
675: "Fri", "Sat", "Sun" };
676:
677: /** Offset from Jan 1, year 1 (Julian) and Jan 1, 1970 */
678: private static long julianDayOffset = 2440588;
679: /** Number of milliseconds per hour */
680: private static int millisPerHour = 60 * 60 * 1000;
681: /** Number of milliseconds per day */
682: private static int millisPerDay = 24 * millisPerHour;
683: /** Jan 1, year 1 (Gregorian) */
684: private static final int JAN_1_1_JULIAN_DAY = 1721426;
685:
686: /** All of the valid strings for the date */
687: private final static String wtb[] = { "am", "pm", "monday",
688: "tuesday", "wednesday", "thursday", "friday", "saturday",
689: "sunday", "january", "february", "march", "april", "may",
690: "june", "july", "august", "september", "october",
691: "november", "december", "gmt", "ut", "utc", "est", "edt",
692: "cst", "cdt", "mst", "mdt", "pst", "pdt"
693: // this time zone table needs to be expanded
694: };
695:
696: /**
697: * Used to process date strings. Each value corresponds to a string
698: * in the wtb variable.
699: */
700: private final static int ttb[] = { 14, 1, 0, 0, 0, 0, 0, 0, 0, 2,
701: 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 10000 + 0,
702: 10000 + 0,
703: 10000 + 0, // GMT/UT/UTC
704: 10000 + 5 * 60,
705: 10000 + 4 * 60, // EST/EDT
706: 10000 + 6 * 60, 10000 + 5 * 60, 10000 + 7 * 60,
707: 10000 + 6 * 60, 10000 + 8 * 60, 10000 + 7 * 60 };
708:
709: /** Cumulative number of days for each month in a non leap year. */
710: private static final int NUM_DAYS[] = { 0, 31, 59, 90, 120, 151,
711: 181, 212, 243, 273, 304, 334 };
712:
713: /** Cumulative number of days for each month in a leap year. */
714: private static final int LEAP_NUM_DAYS[] = { 0, 31, 60, 91, 121,
715: 152, 182, 213, 244, 274, 305, 335 };
716:
717: static {
718: timezones = new Hashtable();
719: timezones.put("GMT", new Integer(0 * millisPerHour));
720: timezones.put("UT", new Integer(0 * millisPerHour));
721: timezones.put("UTC", new Integer(0 * millisPerHour));
722: timezones.put("PST", new Integer(-8 * millisPerHour));
723: timezones.put("PDT", new Integer(-7 * millisPerHour));
724: timezones.put("JST", new Integer(9 * millisPerHour));
725:
726: local_tz = ((Integer) timezones.get("PST")).intValue();
727: }
728: }
|