FileDocCategorySizeDatePackage
DateParser.javaAPI DocphoneME MR2 API (J2ME)28495Wed May 02 18:00:10 BST 2007com.sun.midp.util

DateParser

public class DateParser extends Object
This class implements somewhat of a subset of the J2SE Date class. However, since the semantics of parse() is slightly different (DateParser will not handle dates prior to 1/1/1970, amd to be able to provide methods that will set timezone and DST information, it is called DateParser.

Fields Summary
protected int
year
The year represented by this date
protected int
month
The month represented by this date
protected int
day
The day of the month represented by this date
protected int
hour
The hour represented by this date
protected int
minute
The minute represented by this date
protected int
second
The second represented by this date
protected int
milli
The millisecond represented by this date
protected int
tzoffset
The offset, in milliseconds, from GMT represented by this date
protected static int
local_tz
The offset, in milliseconds, from GMT for the local time zone
private static Hashtable
timezones
A table of valid timezones
private int[]
days_in_month
Number of days in each month in a non leap year
private String[]
month_shorts
Short versions of the month strings
private String[]
weekday_shorts
Short versions of the weekday strings
private static long
julianDayOffset
Offset from Jan 1, year 1 (Julian) and Jan 1, 1970
private static int
millisPerHour
Number of milliseconds per hour
private static int
millisPerDay
Number of milliseconds per day
private static final int
JAN_1_1_JULIAN_DAY
Jan 1, year 1 (Gregorian)
private static final String[]
wtb
All of the valid strings for the date
private static final int[]
ttb
Used to process date strings. Each value corresponds to a string in the wtb variable.
private static final int[]
NUM_DAYS
Cumulative number of days for each month in a non leap year.
private static final int[]
LEAP_NUM_DAYS
Cumulative number of days for each month in a leap year.
Constructors Summary
DateParser(int inp_year, int inp_month, int inp_day, int inp_hour, int inp_minute, int inp_second)
Allocates a DateParser object and initializes it so that it represents the instant at the start of the second specified by the year, month, date, hrs, min, and sec arguments, in the local time zone.

param
inp_year the year, >= 1583.
param
inp_month the month between 0-11.
param
inp_day the day of the month between 1-31.
param
inp_hour the hours between 0-23.
param
inp_minute the minutes between 0-59.
param
inp_second the seconds between 0-59.

        if (inp_year < 1583
            || inp_month < 0 || inp_month > 11
            || inp_day < 0 || (inp_day > days_in_month[inp_month] 
                   && !(inp_month == 1 && inp_day == 29 && inp_year % 4 == 0))
            || inp_hour < 0 || inp_hour > 23
            || inp_minute < 0 || inp_minute > 59
            || inp_second < 0 || inp_second > 59) {
            throw new IllegalArgumentException();
        }
        
        year   = inp_year;
        month  = inp_month;
        day    = inp_day;
        hour   = inp_hour;
        minute = inp_minute;
        second = inp_second;
        milli = 0;
    
DateParser(String s)
Allocates a DateParser object and initializes it so that it represents the date and time indicated by the string s, which is interpreted as if by the {@link DateParser#parse} method.

param
s a string representation of the date.

        internalParse(s);
    
DateParser(String s, boolean iso)
Allocates a DateParser object and initializes it so that it represents the date and time indicated by the string s, which is interpreted as if by the {@link DateParser#parse} method.

param
s a string representation of the date.

        if (iso == false) {
            internalParse(s);
        } else {
            internalParseISO(s);
        }
    
Methods Summary
private final longcomputeJulianDay(int inp_year, int inp_month, int inp_day)
Calculate the number of Julian days since Jan 1, year 1 as represented by the year, month, and day.

param
inp_year The Gegorian year
param
inp_month The month
param
inp_day The day of the month month
return
the number of Julian days.

        int y;
        
        boolean isLeap = inp_year%4 == 0;
        y = inp_year - 1;
        long julianDay = 365L*y + floorDivide(y, 4) + (JAN_1_1_JULIAN_DAY - 3);
        
        isLeap = isLeap && ((inp_year%100 != 0) || (inp_year%400 == 0));
        // Add 2 because Gregorian calendar starts 2 days after Julian calendar
        julianDay += floorDivide(y, 400) - floorDivide(y, 100) + 2;
        julianDay += isLeap ? LEAP_NUM_DAYS[inp_month] : NUM_DAYS[inp_month];
        julianDay += inp_day;

        return julianDay;
    
private static final longfloorDivide(long numerator, long denominator)
Divide two long integers, returning the floor of the quotient.

Unlike the built-in division, this is mathematically well-behaved. E.g., -1/4 => 0 but floorDivide(-1,4) => -1.

param
numerator the numerator
param
denominator a divisor which must be > 0
return
the floor of the quotient.

        // We do this computation in order to handle
        // a numerator of Long.MIN_VALUE correctly
        return (numerator >= 0) ?
            numerator / denominator :
            ((numerator + 1) / denominator) - 1;
    
intgetDay()
Get the day of the month represented by this date.

return
The day of the month.

        return day;
    
intgetHour()
Get the hour represented by this date.

return
The hour.

        return hour;
    
intgetMinute()
Get the minute represented by this date.

return
The minute.

        return minute;
    
intgetMonth()
Get the month represented by this date.

return
The month.

        return month;
    
intgetSecond()
Get the second represented by this date.

return
The second.

        return second;
    
longgetTime()
Calculate the number of milliseconds since 01/01/1970 represented by this date.

return
the number of milliseconds.

        long julianDay = computeJulianDay(year, month, day);
        long millis = julianDayToMillis(julianDay);
        
        int millisInDay = 0;
        millisInDay += hour;
        millisInDay *= 60;
        millisInDay += minute; // now have minutes
        millisInDay *= 60;
        millisInDay += second; // now have seconds
        millisInDay *= 1000;
        millisInDay += milli; // now have millis
        
        return millis + millisInDay - tzoffset;
    
intgetYear()
Get the year represented by this date.

return
The year.

        return year;
    
private voidinternalParse(java.lang.String s)
Parse the date string s

param
s a string representation of the date.

        int inp_year = -1;
        int mon = -1;
        int mday = -1;
        int inp_hour = -1;
        int min = -1;
        int sec = -1;
        int c = -1;
        int i = 0;
        int n = -1;
        int inp_tzoffset = -1;
        int prevc = 0;

        syntax: {
            if (s == null)
                break syntax;
            int limit = s.length();
            while (i < limit) {
                c = s.charAt(i);
                i++;
                if (c <= ' " || c == ',")
                    continue;
                if (c == '(") { // skip comments
                    int depth = 1;
                    while (i < limit) {
                        c = s.charAt(i);
                        i++;
                        if (c == '(") depth++;
                        else if (c == ')")
                            if (--depth <= 0)
                                break;
                    }
                    continue;
                }
                if ('0" <= c && c <= '9") {
                    n = c - '0";
                    while (i < limit && '0" <= (c = s.charAt(i)) && c <= '9") {
                        n = n * 10 + c - '0";
                        i++;
                    }
                    if (prevc == '+" || prevc == '-" && inp_year >= 0) {
                        // timezone offset
                        if (n < 24)
                            n = n * 60; // EG. "GMT-3"
                        else
                            n = n % 100 + n / 100 * 60; // eg "GMT-0430"
                        if (prevc == '+")       // plus means east of GMT
                            n = -n;
                        if (inp_tzoffset != 0 && inp_tzoffset != -1)
                            break syntax;
                        inp_tzoffset = n;
                    } else if (n >= 70)
                        if (inp_year >= 0)
                            break syntax;
                        else if (c <= ' " || c == '," || c == '/" || i >= limit)
                            // year = n < 1900 ? n : n - 1900;
                            inp_year = n < 100 ? n + 1900 : n;
                        else
                            break syntax;
                    else if (c == ':")
                        if (inp_hour < 0)
                            inp_hour = (byte) n;
                        else if (min < 0)
                            min = (byte) n;
                        else
                            break syntax;
                    else if (c == '/")
                        if (mon < 0)
                            mon = (byte) (n - 1);
                        else if (mday < 0)
                            mday = (byte) n;
                        else
                            break syntax;
                    else if (i < limit && c != '," && c > ' " && c != '-")
                        break syntax;
                    else if (inp_hour >= 0 && min < 0)
                        min = (byte) n;
                    else if (min >= 0 && sec < 0)
                        sec = (byte) n;
                    else if (mday < 0)
                        mday = (byte) n;
                    else
                        break syntax;
                    prevc = 0;
                } else if (c == '/" || c == ':" || c == '+" || c == '-")
                    prevc = c;
                else {
                    int st = i - 1;
                    while (i < limit) {
                        c = s.charAt(i);
                        if (!('A" <= c && c <= 'Z" || 'a" <= c && c <= 'z"))
                            break;
                        i++;
                    }
                    if (i <= st + 1)
                        break syntax;
                    int k;
                    for (k = wtb.length; --k >= 0; )
                        if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
                            int action = ttb[k];
                            if (action != 0) {
                                if (action == 1) {      // pm
                                    if (inp_hour > 12 || inp_hour < 1)
                                        break syntax;
                                    else if (inp_hour < 12)
                                        inp_hour += 12;
                                } else if (action == 14) {  // am
                                    if (inp_hour > 12 || inp_hour < 1)
                                        break syntax;
                                    else if (inp_hour == 12)
                                        inp_hour = 0;
                                } else if (action <= 13) {      // month!
                                    if (mon < 0)
                                        mon = (byte) (action - 2);
                                    else
                                        break syntax;
                                } else {
                                    inp_tzoffset = action - 10000;
                                }
                            }
                            break;
                        }
                    if (k < 0)
                        break syntax;
                    prevc = 0;
                }
            }
            if (inp_year < 1583 || mon < 0 || mday < 0)
                break syntax;
            if (sec < 0)
                sec = 0;
            if (min < 0)
                min = 0;
            if (inp_hour < 0)
                inp_hour = 0;
            
            year = inp_year;
            month = mon;
            day = mday;
            hour = inp_hour;
            tzoffset = -inp_tzoffset * 60 * 1000;
            minute = min;
            second = sec;
            milli = 0;
            return;
        }
        // syntax error
        throw new IllegalArgumentException();
    
private voidinternalParseISO(java.lang.String date)

        int field[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
        int field_ptr = 0;
        boolean field_ok;
        
        int c = -1;
        int i = 0;
        int num_dig = 4; /* 4 digits for YEAR and 2 for the rest fields */
        int n = -1;
        int prevc = 0;

        if (date == null) {
            throw new IllegalArgumentException();
        }

        int limit = date.length();
        while (i < limit) {
            /* read next char */
            c = date.charAt(i);
            i++;
            if (c == '+" || c == '-" || c == 'Z" || 
                    c == ' " || c == 'T" || c == ':") {
                prevc = c;
                continue;
            }
            
            /* it is digit */
            if (c < '0" || '9" < c) {
                throw new IllegalArgumentException();
            } else {
                n = c - '0";
                num_dig--;
                while (i < limit && num_dig > 0) {
                    if ('0" <= (c = date.charAt(i)) && c <= '9")  {
                        n = n * 10 + c - '0";
                        i++;
                        num_dig--;
                    } else
                        break;
                }
                num_dig = 2; /* only tear has 4 digits, the rest - 2 */
                
                field_ok = false;
                switch (field_ptr) {
                    case 0: /* year */
                        if (prevc == 0)
                            field_ok = true;
                        break;
                    case 1: /* month */
                        if ((prevc == '-") || (prevc == 0))
                            field_ok = true;
                        break;
                    case 2: /* day */
                        if ((prevc == '-") || (prevc == 0))
                            field_ok = true;
                        break;
                    case 3: /* hour */
                        if ((prevc == ' ") || (prevc == 'T"))
                            field_ok = true;
                        break;
                    case 4: /* min */
                        if ((prevc == ':") || (prevc == 0))
                            field_ok = true;
                        break;
                    case 5: /* sec */
                        if ((prevc == ':") || (prevc == 0)) {
                            field_ok = true;
                        } else if ((prevc == '+") || (prevc == '-")) {
                            field[field_ptr++] = 0;
                            field[field_ptr++] = (prevc == '-")?-1:+1;
                            field_ok = true;
                        }
                        break;
                    /* tz_sign can not be reached here */
                    case 7: /* tz_hour */
                        if ((prevc == '+") || (prevc == '-") || (prevc == 0)) {
                            field[field_ptr++] = (prevc == '-")?-1:+1;
                            field_ok = true;
                        }
                        break;
                    case 8: /* tz_min */
                        if ((prevc == ':") || (prevc == 0)) {
                            field_ok = true;
                        }
                        break;
                }
                if (field_ok) {
                    field[field_ptr++] = n;
                } else {
                    throw new IllegalArgumentException();
                }
                prevc = 0;
            }   
        }
    
        if ((field_ptr >= 5) || (prevc == 'Z")) {
            field_ptr = 9;
        }
        if (field_ptr < 8) {
            throw new IllegalArgumentException();
        }

        year = field[0];
        month = field[1]-1;
        day = field[2];
        hour = field[3];
        minute = field[4];
        second = field[5];
        tzoffset = field[6] * ((((field[7]*60) + field[8]) * 60) * 1000);
        milli = 0;
    
private longjulianDayToMillis(long julian)
Convert the Julian day, julian into milliseconds.

param
julian Number of days since Jan 1, year 1 (Julian).
return
the number of millis since the 01/01/1970.

        return (julian - julianDayOffset) * millisPerDay;
    
public static longparse(java.lang.String s)
Attempts to interpret the string s as a representation of a date and time. If the attempt is successful, the time indicated is returned represented as teh distance, measured in milliseconds, of that time from the epoch (00:00:00 GMT on January 1, 1970). If the attempt fails, an IllegalArgumentException is thrown.

It accepts many syntaxes; in particular, it recognizes the IETF standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also understands the continental U.S. time-zone abbreviations, but for general use, a time-zone offset should be used: "Sat, 12 Aug 1995 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich meridian). If no time zone is specified, the local time zone is assumed. GMT and UTC are considered equivalent.

The string s is processed from left to right, looking for data of interest. Any material in s that is within the ASCII parenthesis characters ( and ) is ignored. Parentheses may be nested. Otherwise, the only characters permitted within s are these ASCII characters:

abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ
0123456789,+-:/
and whitespace characters.

A consecutive sequence of decimal digits is treated as a decimal number:

  • If a number is preceded by + or - and a year has already been recognized, then the number is a time-zone offset. If the number is less than 24, it is an offset measured in hours. Otherwise, it is regarded as an offset in minutes, expressed in 24-hour time format without punctuation. A preceding - means a westward offset. Time zone offsets are always relative to UTC (Greenwich). Thus, for example, -5 occurring in the string would mean "five hours west of Greenwich" and +0430 would mean "four hours and thirty minutes east of Greenwich." It is permitted for the string to specify GMT, UT, or UTC redundantly-for example, GMT-5 or utc+0430.
  • If a number is greater than 70, it is regarded as a year number. It must be followed by a space, comma, slash, or end of string.
  • If the number is followed by a colon, it is regarded as an hour, unless an hour has already been recognized, in which case it is regarded as a minute.
  • If the number is followed by a slash, it is regarded as a month (it is decreased by 1 to produce a number in the range 0 to 11), unless a month has already been recognized, in which case it is regarded as a day of the month.
  • If the number is followed by whitespace, a comma, a hyphen, or end of string, then if an hour has been recognized but not a minute, it is regarded as a minute; otherwise, if a minute has been recognized but not a second, it is regarded as a second; otherwise, it is regarded as a day of the month.

A consecutive sequence of letters is regarded as a word and treated as follows:

  • A word that matches AM, ignoring case, is ignored (but the parse fails if an hour has not been recognized or is less than 1 or greater than 12).
  • A word that matches PM, ignoring case, adds 12 to the hour (but the parse fails if an hour has not been recognized or is less than 1 or greater than 12).
  • Any word that matches any prefix of SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, or SATURDAY, ignoring case, is ignored. For example, sat, Friday, TUE, and Thurs are ignored.
  • Otherwise, any word that matches any prefix of JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, or DECEMBER, ignoring case, and considering them in the order given here, is recognized as specifying a month and is converted to a number (0 to 11). For example, aug, Sept, april, and NOV are recognized as months. So is Ma, which is recognized as MARCH, not MAY.
  • Any word that matches GMT, UT, or UTC, ignoring case, is treated as referring to UTC.
  • Any word that matches EST, CST, MST, or PST, ignoring case, is recognized as referring to the time zone in North America that is five, six, seven, or eight hours west of Greenwich, respectively. Any word that matches EDT, CDT, MDT, or PDT, ignoring case, is recognized as referring to the same time zone, respectively, during daylight saving time.

Once the entire string s has been scanned, it is converted to a time result in one of two ways. If a time zone or time-zone offset has been recognized, then the year, month, day of month, hour, minute, and second are interpreted in UTC and then the time-zone offset is applied. Otherwise, the year, month, day of month, hour, minute, and second are interpreted in the local time zone.

param
s a string to be parsed as a date.
return
the distance in milliseconds from January 1, 1970, 00:00:00 GMT represented by the string argument. Note that this method will throw an IllegalArgumentException if the year indicated in s is less than 1583.

        return (new DateParser(s)).getTime();
    
public static longparseISO(java.lang.String date)
Parses a date string according to the ISO 8601 standard.

param
date the date string in the format YYYY-MM-DDTHH:MM[:SS][[+|-] HH[MM]]
return
the number of milliseconds elapsed since 1970-1-1 GMT to this date
throws
IllegalArgumentException if the format of the date string is incorrect or the date is invalid

        return (new DateParser(date, true)).getTime();
    
static voidsetTimeZone(java.lang.String tz)
Set the local time zone for the DateParser class. tz must in abbreviated format, e.g. "PST" for Pacific Standard Time.

param
tz The time zone string in abbreviated format.

        if (timezones.get(tz) == null) {
            return;
        }
        local_tz = ((Integer)timezones.get(tz)).intValue();