This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch: SimpleDateFormat & strict calendar fixes


Folks,
This patch restores java.text.SimpleDateFormat.parse to the
pre-Classpath merge version of the method (with a few fixes).  The parse
method that's been in use since the merge has some major problems so I
reverted back to the old version and got that working w/just minor tweaks.

I also added some handling for strict calendars in the native code for
java.util.GregorianCalendar (e.g. lenient calendars allow 31-Apr to be the
equivalent of 1-May but strict calendars don't allow that).

I also fixed a minor bug with determining the local timezone that showed
up now that we're in DST here in California.  I'll make sure the
appropriate fixes go into Classpath and I'll write a regression test for
Mauve, besides checking this in on both the gcc-3_0-branch and the trunk.

Enjoy!
--warrenl


2001-04-20  Warren Levy  <warrenl@redhat.com>

        * java/lang/natSystem.cc (getSystemTimeZone): Adjust for DST.
        * java/text/SimpleDateFormat.java
        (indexInArray): Removed private method.
        (processYear): Removed private method.
        (parseLenient): Removed private method.
        (parseLeadingZeros): Removed private method.
        (parseStrict): Removed private method.
        (expect): Added new private method.
        (parse): Reverted to pre-Claspath merge version with minor fixes.
        * java/util/natGregorianCalendar.cc (computeTime): Handle strict
        calendars.


Index: ChangeLog
===================================================================
RCS file: /cvs/gcc/egcs/libjava/ChangeLog,v
retrieving revision 1.674.2.51
diff -u -p -r1.674.2.51 ChangeLog
--- ChangeLog	2001/04/19 01:06:34	1.674.2.51
+++ ChangeLog	2001/04/20 09:24:12
@@ -1,3 +1,17 @@
+2001-04-20  Warren Levy  <warrenl@redhat.com>
+
+	* java/lang/natSystem.cc (getSystemTimeZone): Adjust for DST.
+	* java/text/SimpleDateFormat.java
+	(indexInArray): Removed private method.
+	(processYear): Removed private method.
+	(parseLenient): Removed private method.
+	(parseLeadingZeros): Removed private method.
+	(parseStrict): Removed private method.
+	(expect): Added new private method.
+	(parse): Reverted to pre-Classpath merge version with minor fixes.
+	* java/util/natGregorianCalendar.cc (computeTime): Handle strict
+	calendars.
+
 2001-04-18  Warren Levy  <warrenl@redhat.com>
 
 	* java/util/TimeZone.java: Sync up with Classpath.  Includes new
Index: java/lang/natSystem.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/lang/natSystem.cc,v
retrieving revision 1.35.2.2
diff -u -p -r1.35.2.2 natSystem.cc
--- natSystem.cc	2001/04/02 05:22:09	1.35.2.2
+++ natSystem.cc	2001/04/20 09:24:12
@@ -249,9 +249,11 @@ java::lang::System::getSystemTimeZone (v
 
   mktime(tim = localtime(&current_time));
 #ifdef STRUCT_TM_HAS_GMTOFF
-  tzoffset = -(tim->tm_gmtoff);	// tm_gmtoff is secs EAST of UTC.
+  // tm_gmtoff is secs EAST of UTC.
+  tzoffset = -(tim->tm_gmtoff) + tim->tm_isdst * 3600L;
 #elif HAVE_TIMEZONE
-  tzoffset = timezone;		// timezone is secs WEST of UTC.
+  // timezone is secs WEST of UTC.
+  tzoffset = timezone;	
 #else
   // FIXME: there must be another global if neither tm_gmtoff nor timezone
   // is available, esp. if tzname is valid.
Index: java/text/SimpleDateFormat.java
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/text/SimpleDateFormat.java,v
retrieving revision 1.8
diff -u -p -r1.8 SimpleDateFormat.java
--- SimpleDateFormat.java	2001/01/20 00:37:09	1.8
+++ SimpleDateFormat.java	2001/04/20 09:24:12
@@ -482,679 +482,228 @@ public class SimpleDateFormat extends Da
     buffer.append(valStr);
   }
 
-  private int indexInArray(String dateStr, int index, String[] values) {
-    int l1 = dateStr.length()-index;
-    int l2;
-
-    for (int i=0; i < values.length; i++) {
-      if (values[i] == null)
-        continue;
-
-      l2 = values[i].length();
-      //System.err.println(values[i] + " " + dateStr.substring(index,index+l2));
-      if ((l1 >= l2) && (dateStr.substring(index,index+l2).equals(values[i])))
-	return i;
-    }
-    return -1;
-  }
-
-  /*
-   * Get the actual year value, converting two digit years if necessary.
-   */
-  private int processYear(int val)
-  {
-    if (val > 100)
-      return val;
-
-    Date d = get2DigitYearStart();
-    Calendar c = Calendar.getInstance();
-    c.setTime(d);
-    int y = c.get(YEAR_FIELD);
-
-    return ((y / 100) * 100) + val;
-  }
-
-  /*
-   * Ok, we ignore the format string and just try to parse what we can
-   * out of the string.  We need, month, day, year at a minimum. The real
-   * killer is stuff like XX/XX/XX.  How do we interpret that?  Is is the
-   * US style MM/DD/YY or the European style DD/MM/YY. Or is it YYYY/MM/DD?
-   * I'm an American, so I guess you know which one I'm choosing....
-   */
-  private Date parseLenient(String dateStr, ParsePosition pos)
-  {
-    int month = -1;
-    int day = -1;
-    int year = -1;
-    int era = -1;
-    int hour = -1;
-    int hour24 = -1;
-    int minute = -1;
-    int second = -1;
-    int millis = -1;
-    int ampm = -1;
-    int last = -1;
-    TimeZone tz = null;
-    char lastsep = ' ';
-    char nextchar = ' ';
-
-    Calendar cal = (Calendar)calendar.clone();
-    cal.clear();
-    cal.setTime(new Date(0));
-
-    int index = pos.getIndex();
-    String buf = dateStr.substring(index, dateStr.length());
-
-    top:
-    for(;;)
-      {
-
-        // Are we at the end of the string?  If so, make sure we have
-        // enough data and return. // FIXME: Also detect sufficient data
-        // and return by setting buf to "" on an unparsible string.
-        if (buf.equals(""))
-          {
-            pos.setIndex(index);
-
-            // This is the minimum we need
-            if ((month == -1) || (day == -1) || (year == -1))
-              {
-                pos.setErrorIndex(index);
-                return null;
-              }
-
-             if (tz != null)
-               cal.setTimeZone(tz);
-
-             cal.set(Calendar.YEAR, year);
-             cal.set(Calendar.MONTH, month - 1);
-             cal.set(Calendar.DATE, day);           
-
-             if (ampm == 0)
-               cal.set(Calendar.AM_PM, Calendar.AM);
-             else if (ampm == 1)
-               cal.set(Calendar.AM_PM, Calendar.PM);
-
-             // If am/pm not set, we assume 24 hour day
-             if (hour != -1)
-               {
-                 if (ampm == -1)
-                   cal.set(Calendar.HOUR_OF_DAY, hour);
-                 else
-                   {
-                     if (ampm == 0)
-                       {
-                         if (hour == 12)
-                           hour = 0;
-                       }
-                     else
-                       {
-                         if (hour != 12)
-                           hour += 12;
-                       }
-    
-                     cal.set(Calendar.HOUR_OF_DAY, hour);
-                   }
-               }
-
-             if (minute != -1)
-               cal.set(Calendar.MINUTE, minute);
-
-             if (second != -1)
-               cal.set(Calendar.SECOND, second);
-
-             if (millis != -1)
-               cal.set(Calendar.MILLISECOND, millis);
-
-             if (era == 0)
-               cal.set(Calendar.ERA, GregorianCalendar.BC);
-             else if (era == 1)
-               cal.set(Calendar.ERA, GregorianCalendar.AD);
-
-             return cal.getTime();
-          }
-
-        // Skip over whitespace and expected punctuation
-        char c = buf.charAt(0);
-        boolean comma_found = false;
-        while(Character.isWhitespace(c) || (c == ':') || 
-              (c == ',') || (c == '.') || (c == '/'))
-          {
-            lastsep = c;
-            if (c == ',') // This is a total and utter crock
-              comma_found = true;
-            buf = buf.substring(1);
-            if (buf.equals(""))
-              continue;
-            c = buf.charAt(0);
-          }
-
-        if (comma_found == true)
-          lastsep = ',';
-
-        // Is it a month name?
-        for (int i = 0; i < formatData.months.length; i++)
-          if ((formatData.months[i] != null) 
-              && buf.startsWith(formatData.months[i]))
-            {
-              month = i + 1;
-              buf = buf.substring(formatData.months[i].length());
-              index += formatData.months[i].length();
-              last = MONTH_FIELD;
-              continue top;
-            }
-
-        // Is it a short month name?
-        for (int i = 0; i < formatData.shortMonths.length; i++)
-          if ((formatData.shortMonths[i] != null) 
-              && buf.startsWith(formatData.shortMonths[i]))
-            {
-              month = i + 1;
-              buf = buf.substring(formatData.shortMonths[i].length());
-              index += formatData.shortMonths[i].length();
-              last = MONTH_FIELD;
-              continue top;
-            }
-
-        // Is it a weekday name?
-        for (int i = 0; i < formatData.weekdays.length; i++)
-          if ((formatData.weekdays[i] != null)
-              && buf.startsWith(formatData.weekdays[i]))
-            {
-              buf = buf.substring(formatData.weekdays[i].length());
-              index += formatData.weekdays[i].length();
-              last = DAY_OF_WEEK_FIELD;
-              continue top;
-            }
-
-        // Is it a short weekday name?
-        for (int i = 0; i < formatData.shortWeekdays.length; i++)
-          if ((formatData.shortWeekdays[i] != null)
-              && buf.startsWith(formatData.shortWeekdays[i]))
-            {
-              buf = buf.substring(formatData.shortWeekdays[i].length());
-              index += formatData.shortWeekdays[i].length();
-              last = DAY_OF_WEEK_FIELD;
-              continue top;
-            }
-
-        // Is this an am/pm string?
-        for (int i = 0; i < formatData.ampms.length; i++) {
-          if ((formatData.ampms[i] != null)
-              && buf.toLowerCase().startsWith(formatData.ampms[i].toLowerCase()))
-            {
-              ampm = i;
-              buf = buf.substring(formatData.ampms[i].length());
-              index += formatData.ampms[i].length();
-              last = AM_PM_FIELD;
-              continue top;
-            }
-        }
-
-        // See if we have a number
-        c = buf.charAt(0);
-        String nbrstr = "";
-        while (Character.isDigit(c))
-          {
-            nbrstr = nbrstr + c;
-            buf = buf.substring(1);
-            if (buf.equals(""))
-              break;
-            c = buf.charAt(0);
-          }
-
-        // If we didn't get a number, try for a timezone, otherwise set buf
-        // to "" and loop to see if we are done.
-        if (nbrstr.equals(""))
-          {
-            // Ok, try for a timezone name
-            while(!Character.isWhitespace(c) && (c != ',') && (c != '.') &&
-                  (c != ':') && (c != '/'))
-              {
-                nbrstr = nbrstr + c;
-                buf = buf.substring(1);
-                if (buf.equals(""))
-                  break;
-                c = buf.charAt(0);
-              }
-            TimeZone tmptz = TimeZone.getTimeZone(nbrstr);
-             
-            // We get GMT on failure, so be sure we asked for it.
-            if (tmptz.getID().equals("GMT"))
-              {
-                if (!nbrstr.equals("GMT"))
-                  {
-                    buf = "";
-                    continue top;
-                  }
-              }
-
-            tz = tmptz;
-            last = TIMEZONE_FIELD;
-            index += nbrstr.length();
-            continue top;
-          }
-
-        // Convert to integer
-        int val = 0;
-        try
-          {
-            val = Integer.parseInt(nbrstr);
-          }
-        catch(Exception e)
-          {
-            return null; // Shouldn't happen
-          }
-
-        if (!buf.equals(""))
-          nextchar = buf.charAt(0);
-        else
-          nextchar = ' ';
-
-        // Figure out which value to assign to
-        // I make bad US assumptions about MM/DD/YYYY
-        if (last == DAY_OF_WEEK_FIELD)
-          {
-            day = val;
-            last = DATE_FIELD;
-          }
-        else if ((last == MONTH_FIELD) && (day != -1))
-          {
-            year = processYear(val);
-            last = YEAR_FIELD;
-          }
-        else if (last == MONTH_FIELD)
-          {
-            day = val;
-            last = DATE_FIELD;
-          }
-        else if (last == -1)
-          {
-            // Assume month
-            if ((val < 13) && (val > 0))
-              {
-                month = val;
-                last = MONTH_FIELD;
-              }
-            // Assume year. This only works for two digit years that aren't
-            // between 01 and 12
-            else
-              {
-                year = processYear(val);
-                last = YEAR_FIELD;
-              } 
-          }
-        else if ((last == YEAR_FIELD) && ((nextchar == '/') ||
-                 (nextchar == '.')))
-          {
-            month = val;
-            last = MONTH_FIELD;
-          }
-        else if (last == YEAR_FIELD)
-          {
-            hour = val;
-            last = HOUR0_FIELD;
-          }
-        else if ((last == DATE_FIELD) && ((nextchar == '/') ||
-                 (nextchar == '.') || buf.equals("")))
-          {
-            year = processYear(val);
-            last = YEAR_FIELD;
-          }
-        else if ((last == DATE_FIELD) && ((lastsep == '/') ||
-                 (lastsep == '.') || (lastsep == ',')))
-          {
-            year = processYear(val);
-            last = YEAR_FIELD;
-          }
-        else if (last == DATE_FIELD)
-          {
-            hour = val;
-            last = HOUR0_FIELD;
-          }
-        else if (last == HOUR0_FIELD)
-          {
-            minute = val;
-            last = MINUTE_FIELD;
-          }
-        else if (last == MINUTE_FIELD)
-          {
-            second = val;
-            last = SECOND_FIELD;
-          }
-        else if (lastsep == '.') 
-          {
-            ; // This is milliseconds or something.  Ignore it
-            last = WEEK_OF_YEAR_FIELD; // Just a random value
-          }
-        else // It is year. I have spoken!
-          {
-            year = processYear(val);
-            last = YEAR_FIELD;
-          }
-      }
-  }
-
-  private int parseLeadingZeros(String dateStr, ParsePosition pos,
-                                FieldSizePair p)
+  private final boolean expect (String source, ParsePosition pos, char ch)
   {
-    int value;
-    int index = pos.getIndex();
-    String buf = null;
-
-    if (p.size == 1)
-      {
-        char c = dateStr.charAt(index+1);
-        if ((dateStr.charAt(index) == '1') && 
-             Character.isDigit(dateStr.charAt(index+1)))
-          buf = dateStr.substring(index, index+2);
-        else
-          buf = dateStr.substring(index, index+1);
-        pos.setIndex(index + buf.length());
-      }
-    else if (p.size == 2)
-      {
-        buf = dateStr.substring(index, index+2);
-        pos.setIndex(index+2);
-      }
-    else if (p.size == 3)
-      {
-        buf = dateStr.substring(index, index+3);
-        pos.setIndex(index+3);
-      }
+    int x = pos.getIndex();
+    boolean r = x < source.length() && source.charAt(x) == ch;
+    if (r)
+      pos.setIndex(x + 1);
     else
-      {
-        buf = dateStr.substring(index, index+4);
-        pos.setIndex(index+4);
-      }
-    try
-      {
-        value = Integer.parseInt(buf);
-      }
-    catch(NumberFormatException nfe)
-      {
-        pos.setIndex(index);
-        pos.setErrorIndex(index);
-        return -1;
-      } 
-
-    return value;
+      pos.setErrorIndex(x);
+    return r;
   }
 
-  /*
-   * Note that this method doesn't properly protect against
-   * StringIndexOutOfBoundsException.  FIXME
+  /**
+   * This method parses the specified string into a date.
+   * 
+   * @param dateStr The date string to parse.
+   * @param pos The input and output parse position
+   *
+   * @return The parsed date, or <code>null</code> if the string cannot be
+   * parsed.
    */
-  private Date parseStrict(String dateStr, ParsePosition pos)
+  public Date parse (String dateStr, ParsePosition pos)
   {
-    // start looking at position pos.index
-    Enumeration e = tokens.elements();
-    Calendar theCalendar = (Calendar) calendar.clone();
-    theCalendar.clear();
-    theCalendar.setTime(new Date(0));
+    int fmt_index = 0;
+    int fmt_max = pattern.length();
 
-    int value, index, hour = -1;
-    String buf;
-    while (pos.getIndex() < dateStr.length()) {
-      Object o = e.nextElement();
-      if (o instanceof FieldSizePair) {
-	FieldSizePair p = (FieldSizePair) o;
-	switch (p.field) {
-
-	case ERA_FIELD:
-	  value = indexInArray(dateStr,pos.getIndex(),formatData.eras);
-	  if (value == -1) {
-	    pos.setErrorIndex(pos.getIndex());
-	    return null;
+    calendar.clear();
+    int quote_start = -1;
+    for (; fmt_index < fmt_max; ++fmt_index)
+      {
+	char ch = pattern.charAt(fmt_index);
+	if (ch == '\'')
+	  {
+	    int index = pos.getIndex();
+	    if (fmt_index < fmt_max - 1
+		&& pattern.charAt(fmt_index + 1) == '\'')
+	      {
+		if (! expect (dateStr, pos, ch))
+		  return null;
+		++fmt_index;
+	      }
+	    else
+	      quote_start = quote_start < 0 ? fmt_index : -1;
+	    continue;
 	  }
-	  pos.setIndex(pos.getIndex() + formatData.eras[value].length());
-	  theCalendar.set(Calendar.ERA,value);
-	  break;
-
-	case YEAR_FIELD:
-          String y;
-	  if (p.size < 4)
-            y = dateStr.substring(pos.getIndex(), pos.getIndex() + 2);
-          else
-            y = dateStr.substring(pos.getIndex(), pos.getIndex() + 4);
-            
-          int year;
-          try
-            {
-              year = Integer.parseInt(y);
-            }
-          catch(NumberFormatException nfe)
-            {
-              pos.setErrorIndex(pos.getIndex());
-              return null;
-            }
-
-	  if (p.size < 4)
-            year += get2DigitYearStart().getYear();
-
-          theCalendar.set(Calendar.YEAR, year);
-	  if (p.size < 4)
-            pos.setIndex(pos.getIndex()+2);
-          else
-            pos.setIndex(pos.getIndex()+4);
-	  break;
-
-	case MONTH_FIELD:
-          if (p.size > 2)
-            {
-              index = pos.getIndex();
-
-	      value = indexInArray(dateStr,pos.getIndex(),
-                 (p.size == 3) ? formatData.shortMonths : formatData.months);
-	      if (value == -1) 
-                {
-	          pos.setErrorIndex(pos.getIndex());
-	          return null;
-	        }
-              if (p.size == 3)
-                pos.setIndex(index + formatData.shortMonths[value].length());
-              else
-                pos.setIndex(index + formatData.months[value].length());
-              theCalendar.set(Calendar.MONTH, value);
-              break;
-            }
-
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-
-          theCalendar.set(Calendar.MONTH, value);
-          break;
-
-	case DATE_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-
-          theCalendar.set(Calendar.DATE, value);
-	  break;
-
-	case HOUR_OF_DAY1_FIELD:
-	case HOUR_OF_DAY0_FIELD:
-          index = pos.getIndex();
-          buf = dateStr.substring(index, index+2);
-          try
-            {
-              value = Integer.parseInt(buf);
-            }
-          catch(NumberFormatException nfe)
-            {
-              return null;
-            }
-          if (p.field == HOUR_OF_DAY0_FIELD)
-           // theCalendar.set(Calendar.HOUR_OF_DAY, value);
-            hour = value + 1;
-          else
-           // theCalendar.set(Calendar.HOUR_OF_DAY, value-1);
-            hour = value;
-          pos.setIndex(index+2);
-
-	  break;
-
-	case MINUTE_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-
-          theCalendar.set(Calendar.MINUTE, value);
-	  break;
-
-	case SECOND_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-
-          theCalendar.set(Calendar.SECOND, value);
-	  break;
-
-	case MILLISECOND_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-         
-          theCalendar.set(Calendar.MILLISECOND, value);
-	  break;
 
-	case DAY_OF_WEEK_FIELD:
-	  value = indexInArray(dateStr,pos.getIndex(),(p.size < 4) ? formatData.shortWeekdays : formatData.weekdays);
-	  if (value == -1) {
-	    pos.setErrorIndex(pos.getIndex());
-	    return null;
+	if (quote_start != -1
+	    || ((ch < 'a' || ch > 'z')
+		&& (ch < 'A' || ch > 'Z')))
+	  {
+	    if (! expect (dateStr, pos, ch))
+	      return null;
+	    continue;
 	  }
-	  pos.setIndex(pos.getIndex() + ((p.size < 4) ? formatData.shortWeekdays[value].length()
-	    : formatData.weekdays[value].length()));
-	  // Note: Calendar.set(Calendar.DAY_OF_WEEK,value) does not work
-	  // as implemented in jdk1.1.5 (possibly DAY_OF_WEEK is meant to
-	  // be read-only). Instead, calculate number of days offset.
-	  theCalendar.add(Calendar.DATE,value 
-			  - theCalendar.get(Calendar.DAY_OF_WEEK));
-	  // in JDK, this seems to clear the hours, so we'll do the same.
-	  theCalendar.set(Calendar.HOUR_OF_DAY,0);
-	  break;
-
-	case DAY_OF_YEAR_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-         
-	  theCalendar.set(Calendar.DAY_OF_YEAR, value);
-	  break;
-
-        // Just parse and ignore
-	case DAY_OF_WEEK_IN_MONTH_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-         
-	  break;
-
-        // Just parse and ignore
-	case WEEK_OF_YEAR_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-         
-	  break;
-
-        // Just parse and ignore
-	case WEEK_OF_MONTH_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-
-	  break;
 
-	case AM_PM_FIELD:
-	  value = indexInArray(dateStr,pos.getIndex(),formatData.ampms);
-	  if (value == -1) {
+	// We've arrived at a potential pattern character in the
+	// pattern.
+	int first = fmt_index;
+	while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch)
+	  ;
+	int count = fmt_index - first;
+	--fmt_index;
+
+	// We can handle most fields automatically: most either are
+	// numeric or are looked up in a string vector.  In some cases
+	// we need an offset.  When numeric, `offset' is added to the
+	// resulting value.  When doing a string lookup, offset is the
+	// initial index into the string array.
+	int calendar_field;
+	boolean is_numeric = true;
+	String[] match = null;
+	int offset = 0;
+	int zone_number = 0;
+	switch (ch)
+	  {
+	  case 'd':
+	    calendar_field = Calendar.DATE;
+	    break;
+	  case 'D':
+	    calendar_field = Calendar.DAY_OF_YEAR;
+	    break;
+	  case 'F':
+	    calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH;
+	    break;
+	  case 'E':
+	    is_numeric = false;
+	    offset = 1;
+	    calendar_field = Calendar.DAY_OF_WEEK;
+	    match = (count <= 3
+		     ? formatData.getShortWeekdays()
+		     : formatData.getWeekdays());
+	    break;
+	  case 'w':
+	    calendar_field = Calendar.WEEK_OF_YEAR;
+	    break;
+	  case 'W':
+	    calendar_field = Calendar.WEEK_OF_MONTH;
+	    break;
+	  case 'M':
+	    calendar_field = Calendar.MONTH;
+	    if (count <= 2)
+	      offset = -1;
+	    else
+	      {
+		is_numeric = false;
+		match = (count <= 3
+			 ? formatData.getShortMonths()
+			 : formatData.getMonths());
+	      }
+	    break;
+	  case 'y':
+	    calendar_field = Calendar.YEAR;
+	    if (count <= 2)
+	      offset = 1900;
+	    break;
+	  case 'K':
+	    calendar_field = Calendar.HOUR;
+	    break;
+	  case 'h':
+	    calendar_field = Calendar.HOUR;
+	    break;
+	  case 'H':
+	    calendar_field = Calendar.HOUR_OF_DAY;
+	    break;
+	  case 'k':
+	    calendar_field = Calendar.HOUR_OF_DAY;
+	    break;
+	  case 'm':
+	    calendar_field = Calendar.MINUTE;
+	    break;
+	  case 's':
+	    calendar_field = Calendar.SECOND;
+	    break;
+	  case 'S':
+	    calendar_field = Calendar.MILLISECOND;
+	    break;
+	  case 'a':
+	    is_numeric = false;
+	    calendar_field = Calendar.AM_PM;
+	    match = formatData.getAmPmStrings();
+	    break;
+	  case 'z':
+	    // We need a special case for the timezone, because it
+	    // uses a different data structure than the other cases.
+	    is_numeric = false;
+	    calendar_field = Calendar.DST_OFFSET;
+	    String[][] zoneStrings = formatData.getZoneStrings();
+	    int zoneCount = zoneStrings.length;
+	    int index = pos.getIndex();
+	    boolean found_zone = false;
+	    for (int j = 0;  j < zoneCount;  j++)
+	      {
+		String[] strings = zoneStrings[j];
+		int k;
+		for (k = 1; k < strings.length; ++k)
+		  {
+		    if (dateStr.startsWith(strings[k], index))
+		      break;
+		  }
+		if (k != strings.length)
+		  {
+		    if (k > 2)
+		      ;		// FIXME: dst.
+		    zone_number = 0; // FIXME: dst.
+		    // FIXME: raw offset to SimpleTimeZone const.
+		    calendar.setTimeZone(new SimpleTimeZone (1, strings[0]));
+		    pos.setIndex(index + strings[k].length());
+		    break;
+		  }
+	      }
+	    if (! found_zone)
+	      {
+		pos.setErrorIndex(pos.getIndex());
+		return null;
+	      }
+	    break;
+	  default:
 	    pos.setErrorIndex(pos.getIndex());
 	    return null;
 	  }
-	  pos.setIndex(pos.getIndex() + formatData.ampms[value].length());
-	  theCalendar.set(Calendar.AM_PM,value);
-	  break;
 
-	case HOUR1_FIELD:
-	case HOUR0_FIELD:
-          value = parseLeadingZeros(dateStr, pos, p);
-          if (value == -1)
-            return null;
-          if (p.field == HOUR1_FIELD)
-            theCalendar.set(Calendar.HOUR, value);
-          if (p.field == HOUR0_FIELD)
-            theCalendar.set(Calendar.HOUR, value+1);
-	  break;
-
-	  /*
-	case TIMEZONE_FIELD:
-	  // TODO: FIXME: XXX
-	  break;
-	  */
+	// Compute the value we should assign to the field.
+	int value;
+	if (is_numeric)
+	  {
+	    numberFormat.setMinimumIntegerDigits(count);
+	    Number n = numberFormat.parse(dateStr, pos);
+	    if (pos == null || ! (n instanceof Long))
+	      return null;
+	    value = n.intValue() + offset;
+	  }
+	else if (match != null)
+	  {
+	    int index = pos.getIndex();
+	    int i;
+	    for (i = offset; i < match.length; ++i)
+	      {
+		if (dateStr.startsWith(match[i], index))
+		  break;
+	      }
+	    if (i == match.length)
+	      {
+		pos.setErrorIndex(index);
+		return null;
+	      }
+	    pos.setIndex(index + match[i].length());
+	    value = i;
+	  }
+	else
+	  value = zone_number;
 
-	default:
-	  throw new IllegalArgumentException("Illegal pattern character: " +
-             p.field);
-	} // end switch
-      } else if (o instanceof String) {
-	String ostr = (String) o;
-	if (dateStr.substring(pos.getIndex(),pos.getIndex()+ostr.length()).equals(ostr)) {
-	  pos.setIndex(pos.getIndex() + ostr.length());
-	} else {
-	  pos.setErrorIndex(pos.getIndex());
-	  return null;
-	}
-      } else if (o instanceof Character) {
-	Character ochar = (Character) o;
-	if (dateStr.charAt(pos.getIndex()) == ochar.charValue()) {
-	  pos.setIndex(pos.getIndex() + 1);
-	} else {
-	  pos.setErrorIndex(pos.getIndex());
-	  return null;
-	}
+	// Assign the value and move on.
+	calendar.set(calendar_field, value);
       }
-    }
 
-    if (hour != -1)
+    try
       {
-        if (theCalendar.get(Calendar.AM_PM) == Calendar.PM)
-          {
-            if (hour == 12)
-              theCalendar.set(Calendar.HOUR_OF_DAY, 12);
-            else
-              theCalendar.set(Calendar.HOUR_OF_DAY, hour + 12);
-          }
-        else
-          {
-            if (hour == 12)
-              theCalendar.set(Calendar.HOUR_OF_DAY, 0);
-            else
-              theCalendar.set(Calendar.HOUR_OF_DAY, hour);
-          }
+        return calendar.getTime();
       }
-
-    return theCalendar.getTime();
-  }
-
-  /**
-   * This method parses the specified string into a date.
-   * 
-   * @param dateStr The date string to parse.
-   * @param pos The input and output parse position
-   *
-   * @return The parsed date, or <code>null</code> if the string cannot be
-   * parsed.
-   */
-  public Date parse(String dateStr, ParsePosition pos) {
-    if (isLenient())
-       return parseLenient(dateStr, pos);
-    else
-       return parseStrict(dateStr, pos);
-
+    catch (IllegalArgumentException x)
+      {
+        pos.setErrorIndex(pos.getIndex());
+	return null;
+      }
   }
 }
-
Index: java/util/natGregorianCalendar.cc
===================================================================
RCS file: /cvs/gcc/egcs/libjava/java/util/natGregorianCalendar.cc,v
retrieving revision 1.8
diff -u -p -r1.8 natGregorianCalendar.cc
--- natGregorianCalendar.cc	2000/12/28 05:55:56	1.8
+++ natGregorianCalendar.cc	2001/04/20 09:24:12
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998, 1999, 2000  Free Software Foundation
+/* Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -15,6 +15,7 @@ details.  */
 #include <gcj/cni.h>
 #include <java/util/TimeZone.h>
 #include <java/util/GregorianCalendar.h>
+#include <java/lang/IllegalArgumentException.h>
 #include <time.h>
 
 void
@@ -27,11 +28,52 @@ java::util::GregorianCalendar::computeTi
   tim.tm_mday = elements(fields)[DATE];
   tim.tm_mon = elements(fields)[MONTH];
   tim.tm_year = elements(fields)[YEAR] - 1900;
-  tim.tm_isdst = 0;  // FIXME
+  tim.tm_isdst = 0;
 #ifndef ECOS
   // FIXME: None of the standard C library access to the ECOS calendar
   // is yet available.
   time_t t = mktime (&tim);
+
+  if (!isLenient ())
+    {
+      // mktime will correct for any time leniencies (e.g. 31-Apr becomes
+      // 1-May).
+      // Daylight savings time is a special case since times in hour 23
+      // will compute to hour 0 of the next day.
+      if (tim.tm_isdst == 0 || elements(fields)[HOUR_OF_DAY] != 23)
+        {
+	  if (tim.tm_sec != elements(fields)[SECOND] ||
+	      tim.tm_min != elements(fields)[MINUTE] ||
+	      tim.tm_hour != elements(fields)[HOUR_OF_DAY] +
+	      		     (tim.tm_isdst > 0 ? 1 : 0) ||
+	      tim.tm_mday != elements(fields)[DATE] ||
+	      tim.tm_mon != elements(fields)[MONTH] ||
+	      tim.tm_year != elements(fields)[YEAR] - 1900)
+	    throw new java::lang::IllegalArgumentException ();
+        }
+      else
+        {
+	  // The easiest thing to do is to temporarily shift the clock
+	  // back from the 23th hour so mktime doesn't cause the extra
+	  // hour for DST to roll the date to the next day.
+	  struct tm tmp_tim;
+	  tmp_tim.tm_sec = elements(fields)[SECOND];
+	  tmp_tim.tm_min = elements(fields)[MINUTE];
+	  tmp_tim.tm_hour = elements(fields)[HOUR_OF_DAY] - 1;
+	  tmp_tim.tm_mday = elements(fields)[DATE];
+	  tmp_tim.tm_mon = elements(fields)[MONTH];
+	  tmp_tim.tm_year = elements(fields)[YEAR] - 1900;
+	  tmp_tim.tm_isdst = 0;
+	  mktime (&tmp_tim);
+	  if (tmp_tim.tm_sec != elements(fields)[SECOND] ||
+	      tmp_tim.tm_min != elements(fields)[MINUTE] ||
+	      tmp_tim.tm_hour != elements(fields)[HOUR_OF_DAY] ||
+	      tmp_tim.tm_mday != elements(fields)[DATE] ||
+	      tmp_tim.tm_mon != elements(fields)[MONTH] ||
+	      tmp_tim.tm_year != elements(fields)[YEAR] - 1900)
+	    throw new java::lang::IllegalArgumentException ();
+	}
+    }
 #else
   time_t t = 0;
 #endif

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]