[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 < 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
@@ -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