[kaffe] CVS kaffe (robilad): Resynced with GNU Classpath: Various Calendar and DateFormat patches
Kaffe CVS
cvs-commits at kaffe.org
Thu Feb 3 09:05:41 PST 2005
PatchSet 5966
Date: 2005/02/03 17:01:23
Author: robilad
Branch: HEAD
Tag: (none)
Log:
Resynced with GNU Classpath: Various Calendar and DateFormat patches
2005-02-03 Dalibor Topic <robilad at kaffe.org>
Resynced with GNU Classpath.
2005-02-02 Sven de Marothy <sven at physto.se>
* java/util/Calendar.java
(set) Invalidate all fields on first call to set().
2005-02-02 Andrew John Hughes <gnu_andrew at member.fsf.org>
* java/text/SimpleDateFormat.java
Lots of documentation updates.
(readObject(java.io.ObjectInputStream)): Wraps
IllegalArgumentException as specified.
(compileFormat(String)): Uses standardChars
rather than the local pattern characters.
Throws IllegalArgumentException rather than
storing a -1 field.
(toString()): Extended to include all variables
in a better format.
(translateLocalizedPattern(String, String, String)):
Renamed to better define the use of this method.
2005-02-01 Sven de Marothy <sven at physto.se>
* java/util/GregorianCalendar.java
(computeTime): Fixed handling of time zones.
2005-02-01 Sven de Marothy <sven at physto.se>
* java/util/Calendar.java
(clear): Set values to Epoch instead of zero.
(set): Set isSet to the relevant field pattern instead of just the
field.
* java/util/GregorianCalendar.java
(getBundle): Removed.
(getDayOfYear): Removed.
(getFirstDayOfMonth): New private method.
(nonLeniencyCheck): New private method.
(computeTime): Correct handling of insufficient data.
Members:
ChangeLog:1.3505->1.3506
libraries/javalib/java/text/SimpleDateFormat.java:1.42->1.43
libraries/javalib/java/util/Calendar.java:1.30->1.31
libraries/javalib/java/util/GregorianCalendar.java:1.33->1.34
Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.3505 kaffe/ChangeLog:1.3506
--- kaffe/ChangeLog:1.3505 Thu Feb 3 04:10:10 2005
+++ kaffe/ChangeLog Thu Feb 3 17:01:23 2005
@@ -1,5 +1,47 @@
2005-02-03 Dalibor Topic <robilad at kaffe.org>
+ Resynced with GNU Classpath.
+
+ 2005-02-02 Sven de Marothy <sven at physto.se>
+
+ * java/util/Calendar.java
+ (set) Invalidate all fields on first call to set().
+
+ 2005-02-02 Andrew John Hughes <gnu_andrew at member.fsf.org>
+
+ * java/text/SimpleDateFormat.java
+ Lots of documentation updates.
+ (readObject(java.io.ObjectInputStream)): Wraps
+ IllegalArgumentException as specified.
+ (compileFormat(String)): Uses standardChars
+ rather than the local pattern characters.
+ Throws IllegalArgumentException rather than
+ storing a -1 field.
+ (toString()): Extended to include all variables
+ in a better format.
+ (translateLocalizedPattern(String, String, String)):
+ Renamed to better define the use of this method.
+
+ 2005-02-01 Sven de Marothy <sven at physto.se>
+
+ * java/util/GregorianCalendar.java
+ (computeTime): Fixed handling of time zones.
+
+ 2005-02-01 Sven de Marothy <sven at physto.se>
+
+ * java/util/Calendar.java
+ (clear): Set values to Epoch instead of zero.
+ (set): Set isSet to the relevant field pattern instead of just the
+ field.
+ * java/util/GregorianCalendar.java
+ (getBundle): Removed.
+ (getDayOfYear): Removed.
+ (getFirstDayOfMonth): New private method.
+ (nonLeniencyCheck): New private method.
+ (computeTime): Correct handling of insufficient data.
+
+2005-02-03 Dalibor Topic <robilad at kaffe.org>
+
* configure.ac: Abort if zip can't be found.
2005-02-03 Dalibor Topic <robilad at kaffe.org>
Index: kaffe/libraries/javalib/java/text/SimpleDateFormat.java
diff -u kaffe/libraries/javalib/java/text/SimpleDateFormat.java:1.42 kaffe/libraries/javalib/java/text/SimpleDateFormat.java:1.43
--- kaffe/libraries/javalib/java/text/SimpleDateFormat.java:1.42 Sat Jan 29 15:47:08 2005
+++ kaffe/libraries/javalib/java/text/SimpleDateFormat.java Thu Feb 3 17:01:25 2005
@@ -45,6 +45,7 @@
import gnu.java.text.FormatCharacterIterator;
import gnu.java.text.StringFormatBuffer;
+import java.io.InvalidObjectException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
@@ -68,14 +69,12 @@
* This class is used by <code>SimpleDateFormat</code> as a
* compiled representation of a format string. The field
* ID, size, and character used are stored for each sequence
- * of pattern characters or invalid characters in the format
- * pattern.
+ * of pattern characters.
*/
private class CompiledField
{
/**
* The ID of the field within the local pattern characters,
- * or -1 if the sequence is invalid.
*/
private int field;
@@ -106,8 +105,7 @@
/**
* Retrieves the ID of the field relative to
- * the local pattern characters, or -1 if
- * the sequence is invalid.
+ * the local pattern characters.
*/
public int getField()
{
@@ -154,12 +152,81 @@
}
}
+ /**
+ * A list of <code>CompiledField</code>s,
+ * representing the compiled version of the pattern.
+ *
+ * @see CompiledField
+ * @serial Ignored.
+ */
private transient ArrayList tokens;
+
+ /**
+ * The localised data used in formatting,
+ * such as the day and month names in the local
+ * language, and the localized pattern characters.
+ *
+ * @see DateFormatSymbols
+ * @serial The localisation data. May not be null.
+ */
private DateFormatSymbols formatData; // formatData
+
+ /**
+ * The date representing the start of the century
+ * used for interpreting two digit years. For
+ * example, 24/10/2004 would cause two digit
+ * years to be interpreted as representing
+ * the years between 2004 and 2104.
+ *
+ * @see get2DigitYearStart()
+ * @see set2DigitYearStart(java.util.Date)
+ * @see Date
+ * @serial The start date of the century for parsing two digit years.
+ * May not be null.
+ */
private Date defaultCenturyStart;
+
+ /**
+ * The year at which interpretation of two
+ * digit years starts.
+ *
+ * @see get2DigitYearStart()
+ * @see set2DigitYearStart(java.util.Date)
+ * @serial Ignored.
+ */
private transient int defaultCentury;
+
+ /**
+ * The non-localized pattern string. This
+ * only ever contains the pattern characters
+ * stored in standardChars. Localized patterns
+ * are translated to this form.
+ *
+ * @see applyPattern(String)
+ * @see applyLocalizedPattern(String)
+ * @see toPattern()
+ * @see toLocalizedPattern()
+ * @serial The non-localized pattern string. May not be null.
+ */
private String pattern;
+
+ /**
+ * The version of serialized data used by this class.
+ * Version 0 only includes the pattern and formatting
+ * data. Version 1 adds the start date for interpreting
+ * two digit years.
+ *
+ * @serial This specifies the version of the data being serialized.
+ * Version 0 (or no version) specifies just <code>pattern</code>
+ * and <code>formatData</code>. Version 1 adds
+ * the <code>defaultCenturyStart</code>. This implementation
+ * always writes out version 1 data.
+ */
private int serialVersionOnStream = 1; // 0 indicates JDK1.1.3 or earlier
+
+ /**
+ * For compatability.
+ */
private static final long serialVersionUID = 4774881970558875024L;
// This string is specified in the root of the CLDR. We set it here
@@ -167,6 +234,20 @@
// since someone could theoretically change those values (though unlikely).
private static final String standardChars = "GyMdkHmsSEDFwWahKzYeugAZ";
+ /**
+ * Reads the serialized version of this object.
+ * If the serialized data is only version 0,
+ * then the date for the start of the century
+ * for interpreting two digit years is computed.
+ * The pattern is parsed and compiled following the process
+ * of reading in the serialized data.
+ *
+ * @param stream the object stream to read the data from.
+ * @throws IOException if an I/O error occurs.
+ * @throws ClassNotFoundException if the class of the serialized data
+ * could not be found.
+ * @throws InvalidObjectException if the pattern is invalid.
+ */
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
@@ -182,9 +263,25 @@
// Set up items normally taken care of by the constructor.
tokens = new ArrayList();
- compileFormat(pattern);
+ try
+ {
+ compileFormat(pattern);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new InvalidObjectException("The stream pattern was invalid.");
+ }
}
+ /**
+ * Compiles the supplied non-localized pattern into a form
+ * from which formatting and parsing can be performed.
+ * This also detects errors in the pattern, which will
+ * be raised on later use of the compiled data.
+ *
+ * @param pattern the non-localized pattern to compile.
+ * @throws IllegalArgumentException if the pattern is invalid.
+ */
private void compileFormat(String pattern)
{
// Any alphabetical characters are treated as pattern characters
@@ -197,20 +294,21 @@
for (int i=0; i<pattern.length(); i++) {
thisChar = pattern.charAt(i);
- field = formatData.getLocalPatternChars().indexOf(thisChar);
+ field = standardChars.indexOf(thisChar);
if (field == -1) {
current = null;
if ((thisChar >= 'A' && thisChar <= 'Z')
|| (thisChar >= 'a' && thisChar <= 'z')) {
- // Not a valid letter
- tokens.add(new CompiledField(-1,0,thisChar));
+ // Not a valid letter
+ throw new IllegalArgumentException("Invalid letter " + thisChar +
+ "encountered at character " + i
+ + ".");
} else if (thisChar == '\'') {
// Quoted text section; skip to next single quote
pos = pattern.indexOf('\'',i+1);
if (pos == -1) {
- // This ought to be an exception, but spec does not
- // let us throw one.
- tokens.add(new CompiledField(-1,0,thisChar));
+ throw new IllegalArgumentException("Quotes starting at character "
+ + i + " not closed.");
}
if ((pos+1 < pattern.length()) && (pattern.charAt(pos+1) == '\'')) {
tokens.add(pattern.substring(i+1,pos+1));
@@ -234,13 +332,31 @@
}
}
+ /**
+ * Returns a string representation of this
+ * class.
+ *
+ * @return a string representation of the <code>SimpleDateFormat</code>
+ * instance.
+ */
public String toString()
{
- StringBuffer output = new StringBuffer();
- Iterator i = tokens.iterator();
- while (i.hasNext()) {
- output.append(i.next().toString());
- }
+ StringBuilder output = new StringBuilder(getClass().getName());
+ output.append("[tokens=");
+ output.append(tokens);
+ output.append(", formatData=");
+ output.append(formatData);
+ output.append(", defaultCenturyStart=");
+ output.append(defaultCenturyStart);
+ output.append(", defaultCentury=");
+ output.append(defaultCentury);
+ output.append(", pattern=");
+ output.append(pattern);
+ output.append(", serialVersionOnStream=");
+ output.append(serialVersionOnStream);
+ output.append(", standardChars=");
+ output.append(standardChars);
+ output.append("]");
return output.toString();
}
@@ -271,8 +387,12 @@
}
/**
- * Creates a date formatter using the specified pattern, with the default
- * DateFormatSymbols for the default locale.
+ * Creates a date formatter using the specified non-localized pattern,
+ * with the default DateFormatSymbols for the default locale.
+ *
+ * @param pattern the pattern to use.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public SimpleDateFormat(String pattern)
{
@@ -280,8 +400,13 @@
}
/**
- * Creates a date formatter using the specified pattern, with the default
- * DateFormatSymbols for the given locale.
+ * Creates a date formatter using the specified non-localized pattern,
+ * with the default DateFormatSymbols for the given locale.
+ *
+ * @param pattern the non-localized pattern to use.
+ * @param locale the locale to use for the formatting symbols.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public SimpleDateFormat(String pattern, Locale locale)
{
@@ -299,8 +424,14 @@
}
/**
- * Creates a date formatter using the specified pattern. The
- * specified DateFormatSymbols will be used when formatting.
+ * Creates a date formatter using the specified non-localized
+ * pattern. The specified DateFormatSymbols will be used when
+ * formatting.
+ *
+ * @param pattern the non-localized pattern to use.
+ * @param formatData the formatting symbols to use.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public SimpleDateFormat(String pattern, DateFormatSymbols formatData)
{
@@ -317,9 +448,6 @@
numberFormat.setMaximumFractionDigits (0);
}
- // What is the difference between localized and unlocalized? The
- // docs don't say.
-
/**
* This method returns a string with the formatting pattern being used
* by this object. This string is unlocalized.
@@ -340,7 +468,7 @@
public String toLocalizedPattern()
{
String localChars = formatData.getLocalPatternChars();
- return applyLocalizedPattern (pattern, standardChars, localChars);
+ return translateLocalizedPattern(pattern, standardChars, localChars);
}
/**
@@ -348,6 +476,8 @@
* object. This string is not localized.
*
* @param pattern The new format pattern.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public void applyPattern(String pattern)
{
@@ -361,16 +491,34 @@
* object. This string is localized.
*
* @param pattern The new format pattern.
+ * @throws NullPointerException if the pattern is null.
+ * @throws IllegalArgumentException if the pattern is invalid.
*/
public void applyLocalizedPattern(String pattern)
{
String localChars = formatData.getLocalPatternChars();
- pattern = applyLocalizedPattern (pattern, localChars, standardChars);
+ pattern = translateLocalizedPattern(pattern, localChars, standardChars);
applyPattern(pattern);
}
- private String applyLocalizedPattern(String pattern,
- String oldChars, String newChars)
+ /**
+ * Translates either from or to a localized variant of the pattern
+ * string. For example, in the German locale, 't' (for 'tag') is
+ * used instead of 'd' (for 'date'). This method translates
+ * a localized pattern (such as 'ttt') to a non-localized pattern
+ * (such as 'ddd'), or vice versa. Non-localized patterns use
+ * a standard set of characters, which match those of the U.S. English
+ * locale.
+ *
+ * @param pattern the pattern to translate.
+ * @param oldChars the old set of characters (used in the pattern).
+ * @param newChars the new set of characters (which will be used in the
+ * pattern).
+ * @return a version of the pattern using the characters in
+ * <code>newChars</code>.
+ */
+ private String translateLocalizedPattern(String pattern,
+ String oldChars, String newChars)
{
int len = pattern.length();
StringBuffer buf = new StringBuffer(len);
Index: kaffe/libraries/javalib/java/util/Calendar.java
diff -u kaffe/libraries/javalib/java/util/Calendar.java:1.30 kaffe/libraries/javalib/java/util/Calendar.java:1.31
--- kaffe/libraries/javalib/java/util/Calendar.java:1.30 Mon Jan 24 15:59:45 2005
+++ kaffe/libraries/javalib/java/util/Calendar.java Thu Feb 3 17:01:25 2005
@@ -676,21 +676,72 @@
*/
public void set(int field, int value)
{
+ if (isTimeSet)
+ for (int i = 0; i < FIELD_COUNT; i++)
+ isSet[i] = false;
isTimeSet = false;
fields[field] = value;
isSet[field] = true;
+
+ // The five valid date patterns, in order of validity
+ // 1 YEAR + MONTH + DAY_OF_MONTH
+ // 2 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+ // 3 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+ // 4 YEAR + DAY_OF_YEAR
+ // 5 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
switch (field)
{
- case YEAR:
- case MONTH:
- case DATE:
+ case MONTH: // pattern 1,2 or 3
+ isSet[DAY_OF_YEAR] = false;
isSet[WEEK_OF_YEAR] = false;
+ break;
+ case DAY_OF_MONTH: // pattern 1
+ isSet[YEAR] = true;
+ isSet[MONTH] = true;
+ isSet[WEEK_OF_MONTH] = true;
+ isSet[DAY_OF_WEEK] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ isSet[DAY_OF_YEAR] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ break;
+ case WEEK_OF_MONTH: // pattern 2
+ isSet[YEAR] = true;
+ isSet[MONTH] = true;
+ isSet[DAY_OF_WEEK] = true;
+ isSet[DAY_OF_MONTH] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ isSet[DAY_OF_YEAR] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ break;
+ case DAY_OF_WEEK_IN_MONTH: // pattern 3
+ isSet[YEAR] = true;
+ isSet[MONTH] = true;
+ isSet[DAY_OF_WEEK] = true;
isSet[DAY_OF_YEAR] = false;
+ isSet[DAY_OF_MONTH] = false;
isSet[WEEK_OF_MONTH] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ break;
+ case DAY_OF_YEAR: // pattern 4
+ isSet[YEAR] = true;
+ isSet[MONTH] = false;
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_MONTH] = false;
isSet[DAY_OF_WEEK] = false;
+ isSet[WEEK_OF_YEAR] = false;
+ isSet[DAY_OF_WEEK_IN_MONTH] = false;
+ break;
+ case WEEK_OF_YEAR: // pattern 5
+ isSet[YEAR] = true;
+ isSet[DAY_OF_WEEK] = true;
+ isSet[MONTH] = false;
+ isSet[DAY_OF_MONTH] = false;
+ isSet[WEEK_OF_MONTH] = false;
+ isSet[DAY_OF_YEAR] = false;
isSet[DAY_OF_WEEK_IN_MONTH] = false;
break;
case AM_PM:
+ isSet[HOUR] = true;
isSet[HOUR_OF_DAY] = false;
break;
case HOUR_OF_DAY:
@@ -698,6 +749,7 @@
isSet[HOUR] = false;
break;
case HOUR:
+ isSet[AM_PM] = true;
isSet[HOUR_OF_DAY] = false;
break;
case DST_OFFSET:
@@ -775,11 +827,23 @@
{
isTimeSet = false;
areFieldsSet = false;
- for (int i = 0; i < FIELD_COUNT; i++)
- {
- isSet[i] = false;
- fields[i] = 0;
- }
+
+ int hour = fields[ZONE_OFFSET] / (60 * 60 * 1000);
+ int minute = (fields[ZONE_OFFSET] - 60 * 60 * 1000 * hour) / (60 * 1000);
+ int seconds = (fields[ZONE_OFFSET] - 60 * 60 * 1000 * hour
+ - 60 * 1000 * minute) / 1000;
+ int millis = fields[ZONE_OFFSET] - 60 * 60 * 1000 * hour
+ - 60 * 1000 * minute - seconds * 1000;
+ int[] tempFields =
+ {
+ 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, hour,
+ hour, minute, seconds, millis, fields[ZONE_OFFSET],
+ fields[DST_OFFSET]
+ };
+ fields = tempFields;
+ for (int i = 0; i < FIELD_COUNT - 2; i++)
+ isSet[i] = false;
+ isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true;
}
/**
Index: kaffe/libraries/javalib/java/util/GregorianCalendar.java
diff -u kaffe/libraries/javalib/java/util/GregorianCalendar.java:1.33 kaffe/libraries/javalib/java/util/GregorianCalendar.java:1.34
--- kaffe/libraries/javalib/java/util/GregorianCalendar.java:1.33 Sat Jan 29 15:27:42 2005
+++ kaffe/libraries/javalib/java/util/GregorianCalendar.java Thu Feb 3 17:01:25 2005
@@ -182,20 +182,6 @@
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.
- *
- * @param locale the locale in use for this calendar.
- * @return A resource bundle for the calendar for the specified locale.
- */
- private static ResourceBundle getBundle(Locale locale)
- {
- return ResourceBundle.getBundle(bundleName, locale,
- ClassLoader.getSystemClassLoader());
- }
-
- /**
* Constructs a new GregorianCalender representing the current
* time, using the default time zone and the default locale.
*/
@@ -250,7 +236,9 @@
private GregorianCalendar(TimeZone zone, Locale locale, boolean unused)
{
super(zone, locale);
- ResourceBundle rb = getBundle(locale);
+ ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale,
+ ClassLoader
+ .getSystemClassLoader());
gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime();
}
@@ -376,103 +364,25 @@
}
/**
- * <p>
- * Calculate the dayOfYear from the fields array.
- * The relativeDays is used, to account for weeks that begin before
- * the Gregorian change and end after it.
- * </p>
- * <p>
- * We return two values. The first is used to determine, if we
- * should use the Gregorian calendar or the Julian calendar, in order
- * to handle the change year. The second is a relative day after the given
- * day. This is necessary for week calculation in the year in
- * which the Gregorian change occurs.
- * </p>
- *
- * @param year the year, negative for BC.
- * @return an array of two integer values, the first containing a reference
- * day in the current year, the second a relative count since this reference
- * day.
+ * Returns the day of the week for the first day of a given month (0..11)
*/
- private int[] getDayOfYear(int year)
+ private int getFirstDayOfMonth(int year, int month)
{
- if (isSet[MONTH])
- {
- int dayOfYear;
- if (fields[MONTH] > FEBRUARY)
- {
- // The months after February are regular:
- // 9 is an offset found by try and error.
- dayOfYear = (fields[MONTH] * (31 + 30 + 31 + 30 + 31) - 9) / 5;
- if (isLeapYear(year))
- dayOfYear++;
- }
- else
- dayOfYear = 31 * fields[MONTH];
-
- if (isSet[DAY_OF_MONTH])
- return new int[] { dayOfYear + fields[DAY_OF_MONTH], 0 };
- if (isSet[WEEK_OF_MONTH] && isSet[DAY_OF_WEEK])
- {
- // the weekday of the first day in that month is:
- int weekday = getWeekDay(year, ++dayOfYear);
-
- return new int[]
- {
- dayOfYear,
- // the day of week in the first week
- // (weeks starting on sunday) is:
- fields[DAY_OF_WEEK] - weekday
- + // Now jump to the right week and correct the possible
- // error made by assuming sunday is the first week day.
- 7 * (fields[WEEK_OF_MONTH]
- + (fields[DAY_OF_WEEK] < getFirstDayOfWeek() ? 0 : -1)
- + (weekday < getFirstDayOfWeek() ? -1 : 0))
- };
- }
- if (isSet[DAY_OF_WEEK] && isSet[DAY_OF_WEEK_IN_MONTH])
- {
- // the weekday of the first day in that month is:
- int weekday = getWeekDay(year, ++dayOfYear);
- return new int[]
- {
- dayOfYear,
- fields[DAY_OF_WEEK] - weekday
- + 7 * (fields[DAY_OF_WEEK_IN_MONTH]
- + (fields[DAY_OF_WEEK] < weekday ? 0 : -1))
- };
- }
- }
-
- // MONTH + something did not succeed.
- if (isSet[DAY_OF_YEAR])
- return new int[] { 0, fields[DAY_OF_YEAR] };
+ int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ int dayOfYear = dayCount[month] + 1;
- if (isSet[DAY_OF_WEEK] && isSet[WEEK_OF_YEAR])
- {
- int dayOfYear = getMinimalDaysInFirstWeek();
+ if (month > 1)
+ if (isLeapYear(year))
+ dayOfYear++;
- // the weekday of the day, that begins the first week
- // in that year is:
- int weekday = getWeekDay(year, dayOfYear);
-
- return new int[]
- {
- dayOfYear,
-
- // the day of week in the first week
- // (weeks starting on sunday) is:
- fields[DAY_OF_WEEK] - weekday
- // Now jump to the right week and correct the possible
- // error made by assuming sunday is the first week day.
- + 7 * (fields[WEEK_OF_YEAR]
- + (fields[DAY_OF_WEEK] < getFirstDayOfWeek() ? 0 : -1)
- + (weekday < getFirstDayOfWeek() ? -1 : 0))
- };
- }
+ boolean greg = isGregorian(year, dayOfYear);
+ int day = (int) getLinearDay(year, dayOfYear, greg);
- // As last resort return Jan, 1st.
- return new int[] { 1, 0 };
+ // The epoch was a thursday.
+ int weekday = (day + THURSDAY) % 7;
+ if (weekday <= 0)
+ weekday += 7;
+ return weekday;
}
/**
@@ -490,6 +400,90 @@
}
/**
+ * Check set fields for validity, without leniency.
+ *
+ * @throws IllegalArgumentException if a field is invalid
+ */
+ private void nonLeniencyCheck() throws IllegalArgumentException
+ {
+ int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ int year = fields[YEAR];
+ int month = fields[MONTH];
+ int leap = isLeapYear(year) ? 1 : 0;
+
+ if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC)
+ throw new IllegalArgumentException("Illegal ERA.");
+ if (isSet[YEAR] && fields[YEAR] < 1)
+ throw new IllegalArgumentException("Illegal YEAR.");
+ if (isSet[MONTH] && (month < 0 || month > 11))
+ throw new IllegalArgumentException("Illegal MONTH.");
+ if (isSet[WEEK_OF_YEAR])
+ {
+ int daysInYear = 365 + leap;
+ daysInYear += (getFirstDayOfMonth(year, 0) - 1); // pad first week
+ int last = getFirstDayOfMonth(year, 11) + 4;
+ if (last > 7)
+ last -= 7;
+ daysInYear += 7 - last;
+ int weeks = daysInYear / 7;
+ if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks)
+ throw new IllegalArgumentException("Illegal WEEK_OF_YEAR.");
+ }
+
+ if (isSet[WEEK_OF_MONTH])
+ {
+ int weeks = (month == 1 && leap == 0) ? 4 : 5;
+ if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks)
+ throw new IllegalArgumentException("Illegal WEEK_OF_MONTH.");
+ }
+
+ if (isSet[DAY_OF_MONTH])
+ if (fields[DAY_OF_MONTH] < 1
+ || fields[DAY_OF_MONTH] > month_days[month]
+ + ((month == 1) ? leap : 0))
+ throw new IllegalArgumentException("Illegal DAY_OF_MONTH.");
+
+ if (isSet[DAY_OF_YEAR]
+ && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap))
+ throw new IllegalArgumentException("Illegal DAY_OF_YEAR.");
+
+ if (isSet[DAY_OF_WEEK]
+ && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7))
+ throw new IllegalArgumentException("Illegal DAY_OF_WEEK.");
+
+ if (isSet[DAY_OF_WEEK_IN_MONTH])
+ {
+ int weeks = (month == 1 && leap == 0) ? 4 : 5;
+ if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks
+ || fields[DAY_OF_WEEK_IN_MONTH] > weeks)
+ throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH.");
+ }
+
+ if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM)
+ throw new IllegalArgumentException("Illegal AM_PM.");
+ if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 12))
+ throw new IllegalArgumentException("Illegal HOUR.");
+ if (isSet[HOUR_OF_DAY]
+ && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23))
+ throw new IllegalArgumentException("Illegal HOUR_OF_DAY.");
+ if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59))
+ throw new IllegalArgumentException("Illegal MINUTE.");
+ if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59))
+ throw new IllegalArgumentException("Illegal SECOND.");
+ if (isSet[MILLISECOND]
+ && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999))
+ throw new IllegalArgumentException("Illegal MILLISECOND.");
+ if (isSet[ZONE_OFFSET]
+ && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L
+ || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L))
+ throw new IllegalArgumentException("Illegal ZONE_OFFSET.");
+ if (isSet[DST_OFFSET]
+ && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L
+ || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L))
+ throw new IllegalArgumentException("Illegal DST_OFFSET.");
+ }
+
+ /**
* Converts the time field values (<code>fields</code>) to
* milliseconds since the epoch UTC (<code>time</code>).
*
@@ -499,20 +493,73 @@
protected synchronized void computeTime()
{
int millisInDay = 0;
- int era = isSet[ERA] ? fields[ERA] : AD;
- int year = isSet[YEAR] ? fields[YEAR] : 1970;
- 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 era = fields[ERA];
+ int year = fields[YEAR];
+ int month = fields[MONTH];
+ int day = fields[DAY_OF_MONTH];
+
+ int minute = fields[MINUTE];
+ int second = fields[SECOND];
+ int millis = fields[MILLISECOND];
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 (! isLenient())
+ nonLeniencyCheck();
+
+ if (! isSet[MONTH])
+ {
+ // 5: YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
+ if (isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR])
+ {
+ int first = getFirstDayOfMonth(year, 0);
+ int offs;
+ if ((8 - first) >= getMinimalDaysInFirstWeek())
+ // start counting on first week
+ offs = 1;
+ else
+ offs = 1 + (8 - first);
+
+ month = 0;
+ day = offs + 7 * (fields[WEEK_OF_YEAR] - 1);
+ day += fields[DAY_OF_WEEK] - first;
+ }
+ else
+ {
+ // 4: YEAR + DAY_OF_YEAR
+ month = 0;
+ day = fields[DAY_OF_YEAR];
+ }
+ }
+ else
+ {
+ if (isSet[DAY_OF_WEEK])
+ {
+ int first = getFirstDayOfMonth(year, month);
+
+ // 3: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
+ if (isSet[DAY_OF_WEEK_IN_MONTH])
+ {
+ int offs = fields[DAY_OF_WEEK] - first;
+ if (offs < 0)
+ offs += 7;
+ day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1);
+ day += offs;
+ }
+ else
+ { // 2: YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
+ day = 1 + 7 * (fields[WEEK_OF_MONTH] - 1);
+ day += fields[DAY_OF_WEEK] - first;
+ }
+ }
+
+ // 1: YEAR + MONTH + DAY_OF_MONTH
+ }
if (era == BC && year > 0)
year = 1 - year;
+ // rest of code assumes day/month/year set
// should negative BC years be AD?
// get the hour (but no check for validity)
if (isSet[HOUR_OF_DAY])
@@ -528,71 +575,50 @@
hour = 0;
}
- if (isLenient())
- {
- // 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;
- day += allMillis / (24 * 60 * 60 * 1000L);
- millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L));
+ // 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;
+ 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)
{
- 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;
- }
+ month += 12;
+ year--;
}
+ }
+ if (month > 11)
+ {
+ year += (month / 12);
+ month = month % 12;
+ }
+
+ month_days[1] = isLeapYear(year) ? 29 : 28;
- if (isSet[DAY_OF_MONTH])
+ while (day <= 0)
+ {
+ if (month == 0)
{
+ year--;
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;
- }
- }
}
+ month = (month + 11) % 12;
+ day += month_days[month];
}
- else
+ while (day > month_days[month])
{
- // 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;
+ day -= (month_days[month]);
+ month = (month + 1) % 12;
+ if (month == 0)
+ {
+ year++;
*** Patch too long, truncated ***
More information about the kaffe
mailing list