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  <[EMAIL PROTECTED]>

        Resynced with GNU Classpath.

        2005-01-23  Sven de Marothy <[EMAIL PROTECTED]>

        * 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 <[EMAIL PROTECTED]>
+
+        * 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  <[EMAIL PROTECTED]>
+
+       Resynced with GNU Classpath.
+
        2005-01-23  Andrew John Hughes  <[EMAIL PROTECTED]>
 
         * 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];
   }
 
   /**

_______________________________________________
kaffe mailing list
[email protected]
http://kaffe.org/cgi-bin/mailman/listinfo/kaffe

Reply via email to