[kaffe] CVS kaffe (robilad): Resynced with gnu classpath: sven's calendaring fixes

Kaffe CVS cvs-commits at kaffe.org
Mon Jan 24 08:05:13 PST 2005


PatchSet 5914 
Date: 2005/01/24 15:59:42
Author: robilad
Branch: HEAD
Tag: (none) 
Log:
Resynced with gnu classpath: sven's calendaring fixes

2005-01-24  Dalibor Topic  <robilad at kaffe.org>

        Resynced with GNU Classpath.

        2005-01-23  Sven de Marothy <sven at physto.se>

        * java/util/Calendar.java: Invalidate ERA field on setting the YEAR.
        * java/util/SimpleTimeZone.java:
        (getDaysInMonth): Reimplemented.
        * java/util/GregorianCalendar.java:
        (getLinearTime): Removed.
        (isLeapYear(int,boolean)): Removed.
        (before(), after()): Removed.
        (computeTime): Reimplemented.

Members: 
	ChangeLog:1.3453->1.3454 
	libraries/javalib/java/util/Calendar.java:1.29->1.30 
	libraries/javalib/java/util/GregorianCalendar.java:1.31->1.32 
	libraries/javalib/java/util/SimpleTimeZone.java:1.21->1.22 

Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.3453 kaffe/ChangeLog:1.3454
--- kaffe/ChangeLog:1.3453	Mon Jan 24 15:47:11 2005
+++ kaffe/ChangeLog	Mon Jan 24 15:59:42 2005
@@ -2,6 +2,21 @@
 
 	Resynced with GNU Classpath.
 
+	2005-01-23  Sven de Marothy <sven at physto.se>
+
+        * java/util/Calendar.java: Invalidate ERA field on setting the YEAR.
+        * java/util/SimpleTimeZone.java:
+        (getDaysInMonth): Reimplemented.
+        * java/util/GregorianCalendar.java:
+        (getLinearTime): Removed.
+        (isLeapYear(int,boolean)): Removed.
+        (before(), after()): Removed.
+        (computeTime): Reimplemented.
+
+2005-01-24  Dalibor Topic  <robilad at kaffe.org>
+
+	Resynced with GNU Classpath.
+
 	2005-01-23  Andrew John Hughes  <gnu_andrew at member.fsf.org>
 
         * gnu/java/locale/LocaleInformation.java:
Index: kaffe/libraries/javalib/java/util/Calendar.java
diff -u kaffe/libraries/javalib/java/util/Calendar.java:1.29 kaffe/libraries/javalib/java/util/Calendar.java:1.30
--- kaffe/libraries/javalib/java/util/Calendar.java:1.29	Sat Jan 22 19:17:04 2005
+++ kaffe/libraries/javalib/java/util/Calendar.java	Mon Jan 24 15:59:45 2005
@@ -727,6 +727,7 @@
     isSet[WEEK_OF_MONTH] = false;
     isSet[DAY_OF_WEEK] = false;
     isSet[DAY_OF_WEEK_IN_MONTH] = false;
+    isSet[ERA] = false;
 
     if (! explicitDSTOffset)
       isSet[DST_OFFSET] = false; // May have crossed a DST boundary.
Index: kaffe/libraries/javalib/java/util/GregorianCalendar.java
diff -u kaffe/libraries/javalib/java/util/GregorianCalendar.java:1.31 kaffe/libraries/javalib/java/util/GregorianCalendar.java:1.32
--- kaffe/libraries/javalib/java/util/GregorianCalendar.java:1.31	Sat Jan 22 19:17:05 2005
+++ kaffe/libraries/javalib/java/util/GregorianCalendar.java	Mon Jan 24 15:59:45 2005
@@ -165,6 +165,23 @@
   private static final String bundleName = "gnu.java.locale.Calendar";
 
   /**
+   * Days in the epoch. Relative Jan 1, year '0' which is not a leap year.
+   * (although there is no year zero, this does not matter.)
+   * This is consistent with the formula:
+   * = (year-1)*365L + ((year-1) >> 2)
+   *
+   * Plus the gregorian correction:
+   *  Math.floor((year-1) / 400.) - Math.floor((year-1) / 100.);
+   * For a correct julian date, the correction is -2 instead.
+   *
+   * The gregorian cutover in 1582 was 10 days, so by calculating the
+   * correction from year zero, we have 15 non-leap days (even centuries)
+   * minus 3 leap days (year 400,800,1200) = 12. Subtracting two corrects
+   * this to the correct number 10.
+   */
+  private static final int EPOCH_DAYS = 719162;
+
+  /**
    * Retrieves the resource bundle.  The resources should be loaded
    * via this method only. Iff an application uses this method, the
    * resourcebundle is required.
@@ -326,67 +343,19 @@
    */
   public boolean isLeapYear(int year)
   {
+    // Only years divisible by 4 can be leap years
     if ((year & 3) != 0)
-      // Only years divisible by 4 can be leap years
       return false;
 
-    // compute the linear day of the 29. February of that year.
-    // The 13 is the number of days, that were omitted in the Gregorian
-    // Calender until the epoch.
-    int julianDay = (((year - 1) * (365 * 4 + 1)) >> 2)
-                    + (31 + 29 - (((1970 - 1) * (365 * 4 + 1)) / 4 + 1 - 13));
-
-    // If that day is smaller than the gregorianChange the julian
-    // rule applies:  This is a leap year since it is divisible by 4.
-    if (julianDay * (24 * 60 * 60 * 1000L) < gregorianCutover)
+    // Is the leap-day a Julian date? Then it's a leap year
+    if (! isGregorian(year, 31 + 29 - 1))
       return true;
 
+    // Apply gregorian rules otherwise
     return ((year % 100) != 0 || (year % 400) == 0);
   }
 
   /**
-   * Get the linear time in milliseconds since the epoch.  If you
-   * specify a nonpositive year it is interpreted as BC as
-   * following: 0 is 1 BC, -1 is 2 BC and so on.  The date is
-   * interpreted as gregorian if the change occurred before that date.
-   *
-   * @param year the year of the date.
-   * @param dayOfYear the day of year of the date; 1 based.
-   * @param millis the millisecond in that day.
-   * @return the days since the epoch, may be negative.
-   */
-  private long getLinearTime(int year, int dayOfYear, int millis)
-  {
-    // The 13 is the number of days, that were omitted in the Gregorian
-    // Calendar until the epoch.
-    // We shift right by 2 instead of dividing by 4, to get correct
-    // results for negative years (and this is even more efficient).
-    int julianDay = ((year * (365 * 4 + 1)) >> 2) + dayOfYear
-                    - ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
-    long time = julianDay * (24 * 60 * 60 * 1000L) + millis;
-
-    if (time >= gregorianCutover)
-      {
-	// subtract the days that are missing in gregorian calendar
-	// with respect to julian calendar.
-	//
-	// Okay, here we rely on the fact that the gregorian
-	// calendar was introduced in the AD era.  This doesn't work
-	// with negative years.
-	//
-	// The additional leap year factor accounts for the fact that
-	// a leap day is not seen on Jan 1 of the leap year.
-	// And on and after the leap day, the leap day has already been
-	// included in dayOfYear. 
-	int gregOffset = (year / 400) - (year / 100) + 2;
-	if (isLeapYear(year, true))
-	  --gregOffset;
-	time += gregOffset * (24 * 60 * 60 * 1000L);
-      }
-    return time;
-  }
-
-  /**
    * Retrieves the day of the week corresponding to the specified
    * day of the specified year.
    *
@@ -396,7 +365,8 @@
    */
   private int getWeekDay(int year, int dayOfYear)
   {
-    int day = (int) (getLinearTime(year, dayOfYear, 0) / (24 * 60 * 60 * 1000L));
+    boolean greg = isGregorian(year, dayOfYear);
+    int day = (int) getLinearDay(year, dayOfYear, greg);
 
     // The epoch was a thursday.
     int weekday = (day + THURSDAY) % 7;
@@ -506,6 +476,20 @@
   }
 
   /**
+   * Takes a year, and a (zero based) day of year and determines
+   * if it is gregorian or not.
+   */
+  private boolean isGregorian(int year, int dayOfYear)
+  {
+    int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
+                      - EPOCH_DAYS; // gregorian days from 1 to epoch.
+    int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
+                     - (int) Math.floor((double) (year - 1) / 100.);
+
+    return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover);
+  }
+
+  /**
    * Converts the time field values (<code>fields</code>) to
    * milliseconds since the epoch UTC (<code>time</code>).
    *
@@ -514,29 +498,23 @@
    */
   protected synchronized void computeTime()
   {
+    int millisInDay = 0;
     int era = isSet[ERA] ? fields[ERA] : AD;
     int year = isSet[YEAR] ? fields[YEAR] : 1970;
-    if (isLenient() && isSet[MONTH])
-      {
-	int month = fields[MONTH];
-	year += month / 12;
-	month %= 12;
-	if (month < 0)
-	  {
-	    month += 12;
-	    year--;
-	  }
-	fields[MONTH] = month;
-	isSet[YEAR] = true;
-	fields[YEAR] = year;
-      }
+    int month = isSet[MONTH] ? fields[MONTH] : 0;
+    int day = isSet[DAY_OF_MONTH] ? fields[DAY_OF_MONTH] : 1;
+    int minute = isSet[MINUTE] ? fields[MINUTE] : 0;
+    int second = isSet[SECOND] ? fields[SECOND] : 0;
+    int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0;
+    int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+    int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+    int hour = 0;
 
-    if (era == BC)
+    if (era == BC && year > 0)
       year = 1 - year;
 
-    int[] daysOfYear = getDayOfYear(year);
-
-    int hour = 0;
+    // should negative BC years be AD?
+    // get the hour (but no check for validity)
     if (isSet[HOUR_OF_DAY])
       hour = fields[HOUR_OF_DAY];
     else if (isSet[HOUR])
@@ -550,89 +528,112 @@
 	  hour = 0;
       }
 
-    int minute = isSet[MINUTE] ? fields[MINUTE] : 0;
-    int second = isSet[SECOND] ? fields[SECOND] : 0;
-    int millis = isSet[MILLISECOND] ? fields[MILLISECOND] : 0;
-    int millisInDay;
-
     if (isLenient())
       {
-	// prevent overflow
+	// Read the era,year,month,day fields and convert as appropriate.
+	// Calculate number of milliseconds into the day
+	// This takes care of both h, m, s, ms over/underflows.
 	long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L
 	                 + millis;
-	daysOfYear[1] += allMillis / (24 * 60 * 60 * 1000L);
+	day += allMillis / (24 * 60 * 60 * 1000L);
 	millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
+
+	if (isSet[MONTH])
+	  {
+	    if (month < 0)
+	      {
+		year += (int) month / 12;
+		month = month % 12;
+		if (month < 0)
+		  {
+		    month += 12;
+		    year--;
+		  }
+	      }
+	    if (month > 11)
+	      {
+		year += (month / 12);
+		month = month % 12;
+	      }
+	  }
+
+	if (isSet[DAY_OF_MONTH])
+	  {
+	    month_days[1] = isLeapYear(year) ? 29 : 28;
+
+	    while (day <= 0)
+	      {
+		if (month == 0)
+		  {
+		    year--;
+		    month_days[1] = isLeapYear(year) ? 29 : 28;
+		  }
+		month = (month + 11) % 12;
+		day += month_days[month];
+	      }
+	    while (day > month_days[month])
+	      {
+		day -= (month_days[month]);
+		month = (month + 1) % 12;
+		if (month == 0)
+		  {
+		    year++;
+		    month_days[1] = isLeapYear(year) ? 29 : 28;
+		  }
+	      }
+	  }
       }
     else
       {
-	if (hour < 0 || hour >= 24 || minute < 0 || minute > 59 || second < 0
-	    || second > 59 || millis < 0 || millis >= 1000)
+	// non-lenient
+	if (month < 0 || month > 11 || hour < 0 || hour >= 24 || minute < 0
+	    || minute > 59 || second < 0 || second > 59 || millis < 0
+	    || millis >= 1000)
+	  throw new IllegalArgumentException();
+	if (day < 1 || day > month_days[month])
 	  throw new IllegalArgumentException();
 	millisInDay = (((hour * 60) + minute) * 60 + second) * 1000 + millis;
       }
-    time = getLinearTime(year, daysOfYear[0], millisInDay);
 
-    // Add the relative days after calculating the linear time, to
-    // get right behaviour when jumping over the gregorianCutover.
-    time += daysOfYear[1] * (24 * 60 * 60 * 1000L);
+    // ok, by here we have valid day,month,year,era and millisinday
+    int dayOfYear = dayCount[month] + day - 1; // (day starts on 1)
+    if (isLeapYear(year) && month > 1)
+      dayOfYear++;
+
+    int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear
+                      - EPOCH_DAYS; // gregorian days from 1 to epoch.
+    int gregFactor = (int) Math.floor((double) (year - 1) / 400.)
+                     - (int) Math.floor((double) (year - 1) / 100.);
+
+    if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover)
+      relativeDay += gregFactor;
+    else
+      relativeDay -= 2;
+
+    time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay;
 
     TimeZone zone = getTimeZone();
     int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET]
                                        : zone.getRawOffset();
 
-    int day = (int) (time / (24 * 60 * 60 * 1000L));
-    millisInDay = (int) (time % (24 * 60 * 60 * 1000L));
-    if (millisInDay < 0)
-      {
-	millisInDay += (24 * 60 * 60 * 1000);
-	day--;
-      }
+    // the epoch was a Thursday.
+    int weekday = (int) (relativeDay + THURSDAY) % 7;
+    if (weekday <= 0)
+      weekday += 7;
+    fields[DAY_OF_WEEK] = weekday;
 
-    int[] f = new int[FIELD_COUNT];
-    calculateDay(f, day, time - rawOffset >= gregorianCutover);
-    year = f[YEAR];
-    int month = f[MONTH];
-    day = f[DAY_OF_MONTH];
-    int weekday = f[DAY_OF_WEEK];
     int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET]
-                                      : (zone.getOffset((year < 0) ? BC : AD,
-                                                        (year < 0) ? 1 - year
+                                      : (zone.getOffset((year < 1) ? BC : AD,
+                                                        (year < 1) ? 1 - year
                                                                    : year,
                                                         month, day, weekday,
                                                         millisInDay)
                                       - zone.getRawOffset());
-    time -= rawOffset + dstOffset;
+    time -= (rawOffset + dstOffset);
     isTimeSet = true;
   }
 
   /**
-   * <p>
-   * Determines if the given year is a leap year.
-   * </p>
-   * <p>
-   * To specify a year in the BC era, use a negative value calculated
-   * as 1 - y, where y is the required year in BC.  So, 1 BC is 0,
-   * 2 BC is -1, 3 BC is -2, etc.
-   * </p>
-   *
-   * @param year a year (use a negative value for BC).
-   * @param gregorian if true, use the gregorian leap year rule.
-   * @return true, if the given year is a leap year, false otherwise.
-   */
-  private boolean isLeapYear(int year, boolean gregorian)
-  {
-    if ((year & 3) != 0)
-      // Only years divisible by 4 can be leap years
-      return false;
-
-    if (! gregorian)
-      return true;
-
-    // We rely on AD area here.
-    return ((year % 100) != 0 || (year % 400) == 0);
-  }
-
-  /**
    * Get the linear day in days since the epoch, using the
    * Julian or Gregorian calendar as specified.  If you specify a
    * nonpositive year it is interpreted as BC as following: 0 is 1
@@ -643,14 +644,14 @@
    * @param gregorian <code>true</code>, if we should use the Gregorian rules.
    * @return the days since the epoch, may be negative.
    */
-  private long getLinearDay(int year, int dayOfYear, boolean gregorian)
+  public long getLinearDay(int year, int dayOfYear, boolean gregorian)
   {
     // The 13 is the number of days, that were omitted in the Gregorian
     // Calender until the epoch.
     // We shift right by 2 instead of dividing by 4, to get correct
     // results for negative years (and this is even more efficient).
-    long julianDay = ((year * (365L * 4 + 1)) >> 2) + dayOfYear
-                     - ((1970 * (365 * 4 + 1)) / 4 + 1 - 13);
+    long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1)
+                     - EPOCH_DAYS; // gregorian days from 1 to epoch.
 
     if (gregorian)
       {
@@ -663,11 +664,13 @@
 	//
 	// The additional leap year factor accounts for the fact that
 	// a leap day is not seen on Jan 1 of the leap year.
-	int gregOffset = (year / 400) - (year / 100) + 2;
-	if (isLeapYear(year, true) && dayOfYear < 31 + 29)
-	  --gregOffset;
-	julianDay += gregOffset;
+	int gregOffset = (int) Math.floor((double) (year - 1) / 400.)
+	                 - (int) Math.floor((double) (year - 1) / 100.);
+
+	return julianDay + gregOffset;
       }
+    else
+      julianDay -= 2;
     return julianDay;
   }
 
@@ -681,7 +684,7 @@
    */
   private void calculateDay(int[] fields, long day, boolean gregorian)
   {
-    // the epoch is a Thursday.
+    // the epoch was a Thursday.
     int weekday = (int) (day + THURSDAY) % 7;
     if (weekday <= 0)
       weekday += 7;
@@ -691,8 +694,8 @@
     // year too big.
     int year = 1970
                + (int) (gregorian
-                        ? ((day - 100) * 400) / (365 * 400 + 100 - 4 + 1)
-                        : ((day - 100) * 4) / (365 * 4 + 1));
+                        ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L
+                        + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L));
     if (day >= 0)
       year++;
 
@@ -719,7 +722,7 @@
 	fields[YEAR] = year;
       }
 
-    int leapday = isLeapYear(year, gregorian) ? 1 : 0;
+    int leapday = isLeapYear(year) ? 1 : 0;
     if (day <= 31 + 28 + leapday)
       {
 	fields[MONTH] = (int) day / 32; // 31->JANUARY, 32->FEBRUARY
@@ -749,6 +752,7 @@
 
     long day = localTime / (24 * 60 * 60 * 1000L);
     int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
+
     if (millisInDay < 0)
       {
 	millisInDay += (24 * 60 * 60 * 1000);
@@ -823,31 +827,6 @@
     GregorianCalendar cal = (GregorianCalendar) o;
     return (cal.getTimeInMillis() == getTimeInMillis());
   }
-
-//     /**
-//      * Compares the given calender with this.  
-//      * @param o the object to that we should compare.
-//      * @return true, if the given object is a calendar, and this calendar
-//      * represents a smaller time than the calender o.
-//      */
-//     public boolean before(Object o) {
-//         if (!(o instanceof GregorianCalendar))
-//             return false;
-//         GregorianCalendar cal = (GregorianCalendar) o;
-//         return (cal.getTimeInMillis() < getTimeInMillis());
-//     }
-//     /**
-//      * Compares the given calender with this.  
-//      * @param o the object to that we should compare.
-//      * @return true, if the given object is a calendar, and this calendar
-//      * represents a bigger time than the calender o.
-//      */
-//     public boolean after(Object o) {
-//         if (!(o instanceof GregorianCalendar))
-//             return false;
-//         GregorianCalendar cal = (GregorianCalendar) o;
-//         return (cal.getTimeInMillis() > getTimeInMillis());
-//     }
 
   /**
    * Adds the specified amount of time to the given time field.  The
Index: kaffe/libraries/javalib/java/util/SimpleTimeZone.java
diff -u kaffe/libraries/javalib/java/util/SimpleTimeZone.java:1.21 kaffe/libraries/javalib/java/util/SimpleTimeZone.java:1.22
--- kaffe/libraries/javalib/java/util/SimpleTimeZone.java:1.21	Sat Jan 22 19:17:05 2005
+++ kaffe/libraries/javalib/java/util/SimpleTimeZone.java	Mon Jan 24 15:59:45 2005
@@ -424,8 +424,6 @@
    */
   private int checkRule(int month, int day, int dayOfWeek)
   {
-    if (month < 0 || month > 11)
-      throw new IllegalArgumentException("month out of range");
     int daysInMonth = getDaysInMonth(month, 1);
     if (dayOfWeek == 0)
       {
@@ -587,7 +585,7 @@
    *
    * Note that this API isn't incredibly well specified.  It appears that the
    * after flag must override the parameters, since normally, the day and
-   * dayofweek can select this.  I.e., if day &lt; 0 and dayOfWeek &lt; 0, on or
+   * dayofweek can select this.  I.e., if day < 0 and dayOfWeek < 0, on or
    * before mode is chosen.  But if after == true, this implementation
    * overrides the signs of the other arguments.  And if dayOfWeek == 0, it
    * falls back to the behavior in the other APIs.  I guess this should be
@@ -681,7 +679,7 @@
     if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
       throw new IllegalArgumentException("dayOfWeek out of range");
     if (month < Calendar.JANUARY || month > Calendar.DECEMBER)
-      throw new IllegalArgumentException("month out of range");
+      throw new IllegalArgumentException("month out of range:" + month);
 
     // This method is called by Calendar, so we mustn't use that class.
     int daylightSavings = 0;
@@ -692,9 +690,9 @@
 	boolean afterStart = ! isBefore(year, month, day, dayOfWeek, millis,
 	                                startMode, startMonth, startDay,
 	                                startDayOfWeek, startTime);
-	boolean beforeEnd = isBefore(year, month, day, dayOfWeek,
-	                             millis + dstSavings, endMode, endMonth,
-	                             endDay, endDayOfWeek, endTime);
+	boolean beforeEnd = isBefore(year, month, day, dayOfWeek, millis,
+	                             endMode, endMonth, endDay, endDayOfWeek,
+	                             endTime);
 
 	if (startMonth < endMonth)
 	  // use daylight savings, if the date is after the start of
@@ -766,20 +764,28 @@
   }
 
   /**
-   * Returns the number of days in the given month.  It does always
-   * use the Gregorian leap year rule.
+   * Returns the number of days in the given month.
+   * Uses gregorian rules prior to 1582 (The default and earliest cutover)
    * @param month The month, zero based; use one of the Calendar constants.
    * @param year  The year.
    */
   private int getDaysInMonth(int month, int year)
   {
-    // Most of this is copied from GregorianCalendar.getActualMaximum()
     if (month == Calendar.FEBRUARY)
-      return ((year & 3) == 0 && (year % 100 != 0 || year % 400 == 0)) ? 29 : 28;
-    else if (month < Calendar.AUGUST)
-      return 31 - (month & 1);
+      {
+	if ((year & 3) != 0)
+	  return 28;
+
+	// Assume default Gregorian cutover, 
+	// all years prior to this must be Julian
+	if (year < 1582)
+	  return 29;
+
+	// Gregorian rules 
+	return ((year % 100) != 0 || (year % 400) == 0) ? 29 : 28;
+      }
     else
-      return 30 + (month & 1);
+      return monthArr[month];
   }
 
   /**




More information about the kaffe mailing list