Index: ChangeLog =================================================================== RCS file: /cvsroot/classpath/classpath/ChangeLog,v retrieving revision 1.2386.2.65 diff -u -3 -p -u -r1.2386.2.65 ChangeLog --- ChangeLog 23 Jan 2005 02:46:22 -0000 1.2386.2.65 +++ ChangeLog 23 Jan 2005 23:59:16 -0000 @@ -1,3 +1,19 @@ +2005-01-23 Sven de Marothy
+ + * gnu/java/awt/peer/gtk/GtkComponentPeer.java: + Reverted to previous version, after a mistake in the previous commit. + +2005-01-23 Sven de Marothy + + * 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-23 Andrew John Hughes * gnu/java/locale/LocaleInformation.java: Index: java/util/Calendar.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/Calendar.java,v retrieving revision 1.25.2.6 diff -u -3 -p -u -r1.25.2.6 Calendar.java --- java/util/Calendar.java 22 Jan 2005 02:20:02 -0000 1.25.2.6 +++ java/util/Calendar.java 23 Jan 2005 23:59:20 -0000 @@ -728,6 +728,7 @@ public abstract class Calendar 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: java/util/GregorianCalendar.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/GregorianCalendar.java,v retrieving revision 1.26.2.4 diff -u -3 -p -u -r1.26.2.4 GregorianCalendar.java --- java/util/GregorianCalendar.java 22 Jan 2005 02:20:02 -0000 1.26.2.4 +++ java/util/GregorianCalendar.java 23 Jan 2005 23:59:23 -0000 @@ -165,6 +165,23 @@ public class GregorianCalendar extends C 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 class GregorianCalendar extends C */ 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 @@ public class GregorianCalendar extends C */ 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 @@ public class GregorianCalendar extends C } /** + * 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 (fields
) to
* milliseconds since the epoch UTC (time
).
*
@@ -514,29 +498,23 @@ public class GregorianCalendar extends C
*/
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 @@ public class GregorianCalendar extends C
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;
}
/**
- * - * Determines if the given year is a leap year. - *
- *- * 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. - *
- * - * @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 @@ public class GregorianCalendar extends C * @param gregoriantrue
, 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 @@ public class GregorianCalendar extends C
//
// 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 @@ public class GregorianCalendar extends C
*/
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 @@ public class GregorianCalendar extends C
// 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 @@ public class GregorianCalendar extends C
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 @@ public class GregorianCalendar extends C
long day = localTime / (24 * 60 * 60 * 1000L);
int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L));
+
if (millisInDay < 0)
{
millisInDay += (24 * 60 * 60 * 1000);
@@ -824,31 +828,6 @@ public class GregorianCalendar extends C
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
* amount may be negative to subtract the time. If the field overflows
Index: java/util/SimpleTimeZone.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/util/SimpleTimeZone.java,v
retrieving revision 1.18.2.2
diff -u -3 -p -u -r1.18.2.2 SimpleTimeZone.java
--- java/util/SimpleTimeZone.java 22 Jan 2005 02:20:02 -0000 1.18.2.2
+++ java/util/SimpleTimeZone.java 23 Jan 2005 23:59:23 -0000
@@ -424,8 +424,6 @@ public class SimpleTimeZone extends Time
*/
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)
{
@@ -586,7 +584,7 @@ public class SimpleTimeZone extends Time
*
* 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 < 0 and dayOfWeek < 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
@@ -680,7 +678,7 @@ public class SimpleTimeZone extends Time
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;
@@ -691,9 +689,9 @@ public class SimpleTimeZone extends Time
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
@@ -765,20 +763,28 @@ public class SimpleTimeZone extends Time
}
/**
- * 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];
}
/**