diff options
-rw-r--r-- | ChangeLog | 29 | ||||
-rw-r--r-- | gnu/java/locale/LocaleInformation.java | 2 | ||||
-rw-r--r-- | gnu/java/locale/LocaleInformation_en.java | 1 | ||||
-rw-r--r-- | gnu/java/locale/LocaleInformation_nl.java | 1 | ||||
-rw-r--r-- | java/text/DateFormat.java | 218 | ||||
-rw-r--r-- | java/text/SimpleDateFormat.java | 167 |
6 files changed, 370 insertions, 48 deletions
@@ -1,3 +1,32 @@ +2005-01-23 Andrew John Hughes <gnu_andrew@member.fsf.org> + + * gnu/java/locale/LocaleInformation.java: + Extended localPatternChars string to match root.xml. + * gnu/java/locale/LocaleInformation_en.java: + Removed invalid localPatternChars string. + * gnu/java/locale/LocaleInformation_nl.java: + Likewise. + * java/text/DateFormat.java: + Documented pattern character offset constants and + added new ones. + (Field): Added new static fields for new pattern chars. + * java/text/SimpleDateFormat.java: + (CompiledField): Changed name of FieldSizePair class + to CompiledField after adding the character as an + attribute. Changed fields to private and added + accessors to give encapsulation. + (CompiledField.CompiledField(int,int,char)): Extended + with character field. + (CompiledField.getField()): New accessor method. + (CompiledField.getSize()): New acceessor method. + (CompiledField.getCharacter()): New accessor method. + (CompiledField.toString()): Added primarily for debugging. + (standardChars): Now uses extended 24 character sequence. + (compileFormat(String)): Changed to use CompiledField. + (formatWithAttribute(java.util.Date, gnu.java.text.FormatBuffer, + java.text.FieldPosition)): Changed to use CompiledField. + New handler for RFC 822 timezones added. + 2005-01-22 Andrew John Hughes <gnu_andrew@member.fsf.org> * java/awt/Checkbox.java: diff --git a/gnu/java/locale/LocaleInformation.java b/gnu/java/locale/LocaleInformation.java index c4bb1bf39..782b1e8ee 100644 --- a/gnu/java/locale/LocaleInformation.java +++ b/gnu/java/locale/LocaleInformation.java @@ -113,7 +113,7 @@ public class LocaleInformation extends ListResourceBundle private static final Object[][] contents = { - { "localPatternChars", "GyMdkHmsSEDFwWahKz" }, + { "localPatternChars", "GyMdkHmsSEDFwWahKzYeugAZ" }, { "currencySymbols", currencySymbols }, { "decimalSeparator", "." }, { "groupingSeparator", "," }, diff --git a/gnu/java/locale/LocaleInformation_en.java b/gnu/java/locale/LocaleInformation_en.java index daec52564..c3500c684 100644 --- a/gnu/java/locale/LocaleInformation_en.java +++ b/gnu/java/locale/LocaleInformation_en.java @@ -241,7 +241,6 @@ public class LocaleInformation_en extends ListResourceBundle { "eras", eras }, { "shortDateFormat", "M/d/yy" }, { "mediumDateFormat", "MMM d, yyyy" }, - { "localPatternChars", "GyMdkHmsSEDFwWahKz" }, { "longDateFormat", "MMMM d, yyyy" }, { "fullDateFormat", "EEEE, MMMM d, yyyy" }, { "shortTimeFormat", "h:mm a" }, diff --git a/gnu/java/locale/LocaleInformation_nl.java b/gnu/java/locale/LocaleInformation_nl.java index e54e8c999..8a6e7d454 100644 --- a/gnu/java/locale/LocaleInformation_nl.java +++ b/gnu/java/locale/LocaleInformation_nl.java @@ -224,7 +224,6 @@ public class LocaleInformation_nl extends ListResourceBundle private static final Object[][] contents = { { "collation_rules", collation_rules }, - { "localPatternChars", "GyMdhHmsSEDFwWakKz" }, { "decimalSeparator", "," }, { "groupingSeparator", "." }, { "currenciesDisplayName", currenciesDisplayName }, diff --git a/java/text/DateFormat.java b/java/text/DateFormat.java index 78caad230..f79dd8bff 100644 --- a/java/text/DateFormat.java +++ b/java/text/DateFormat.java @@ -70,29 +70,221 @@ public abstract class DateFormat extends Format implements Cloneable /* These constants need to have these exact values. They * correspond to index positions within the localPatternChars - * string for a given locale. For example, the US locale uses - * the string "GyMdkHmsSEDFwWahKz", where 'G' is the character - * for era, 'y' for year, and so on down to 'z' for time zone. + * string for a given locale. Each locale may specify its + * own character for a particular field, but the position + * of these characters must correspond to an appropriate field + * number (as listed below), in order for their meaning to + * be determined. For example, the US locale uses + * the string "GyMdkHmsSEDFwWahKzYeugAZ", where 'G' is the character + * for era, 'y' for year, and so on down to 'Z' for time zone. */ + /** + * Represents the position of the era + * pattern character in the array of + * localized pattern characters. + * For example, 'AD' is an era used + * in the Gregorian calendar system. + * In the U.S. locale, this is 'G'. + */ public static final int ERA_FIELD = 0; + /** + * Represents the position of the year + * pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'y'. + */ public static final int YEAR_FIELD = 1; + /** + * Represents the position of the month + * pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'M'. + */ public static final int MONTH_FIELD = 2; + /** + * Represents the position of the date + * or day of the month pattern character + * in the array of localized pattern + * characters. In the U.S. locale, + * this is 'd'. + */ public static final int DATE_FIELD = 3; + /** + * Represents the position of the 24 + * hour pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'k'. + * This field numbers hours from 1 to 24. + */ public static final int HOUR_OF_DAY1_FIELD = 4; + /** + * Represents the position of the 24 + * hour pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'H'. + * This field numbers hours from 0 to 23. + */ public static final int HOUR_OF_DAY0_FIELD = 5; + /** + * Represents the position of the minute + * pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'm'. + */ public static final int MINUTE_FIELD = 6; + /** + * Represents the position of the second + * pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 's'. + */ public static final int SECOND_FIELD = 7; + /** + * Represents the position of the millisecond + * pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'S'. + */ public static final int MILLISECOND_FIELD = 8; + /** + * Represents the position of the day of the + * week pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'E'. + */ public static final int DAY_OF_WEEK_FIELD = 9; + /** + * Represents the position of the day of the + * year pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'D'. + */ public static final int DAY_OF_YEAR_FIELD = 10; + /** + * Represents the position of the day of the + * week in the month pattern character in the + * array of localized pattern characters. + * In the U.S. locale, this is 'F'. + */ public static final int DAY_OF_WEEK_IN_MONTH_FIELD = 11; + /** + * Represents the position of the week of the + * year pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'w'. + */ public static final int WEEK_OF_YEAR_FIELD = 12; + /** + * Represents the position of the week of the + * month pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'W'. + */ public static final int WEEK_OF_MONTH_FIELD = 13; + /** + * Represents the position of the am/pm + * pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'a'. + */ public static final int AM_PM_FIELD = 14; + /** + * Represents the position of the 12 + * hour pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'h'. + * This field numbers hours from 1 to 12. + */ public static final int HOUR1_FIELD = 15; + /** + * Represents the position of the 12 + * hour pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'K'. + * This field numbers hours from 0 to 11. + */ public static final int HOUR0_FIELD = 16; + /** + * Represents the position of the generic + * timezone pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'z'. + */ public static final int TIMEZONE_FIELD = 17; - + /** + * Represents the position of the ISO year + * pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'Y'. + * This is a GNU extension in accordance with + * the CLDR data used. This value may + * differ from the normal year value. + */ + public static final int ISO_YEAR_FIELD = 18; + /** + * Represents the position of the localized + * day of the week pattern character in the + * array of localized pattern characters. + * In the U.S. locale, this is 'e'. + * This is a GNU extension in accordance with + * the CLDR data used. This value only + * differs from the day of the week with + * numeric formatting, in which case the + * locale's first day of the week is used. + */ + public static final int LOCALIZED_DAY_OF_WEEK_FIELD = 19; + /** + * Represents the position of the extended year + * pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'u'. + * This is a GNU extension in accordance with + * the CLDR data used. This value modifies + * the year value, so as to incorporate the era. + * For example, in the Gregorian calendar system, + * the extended year is negative instead of being + * marked as BC. + */ + public static final int EXTENDED_YEAR_FIELD = 20; + /** + * Represents the position of the modified Julian + * day pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'g'. + * This is a GNU extension in accordance with + * the CLDR data used. This value differs + * from the standard Julian day in that days + * are marked from midnight onwards rather than + * noon, and the local time zone affects the value. + * In simple terms, it can be thought of as all + * the date fields represented as a single number. + */ + public static final int MODIFIED_JULIAN_DAY_FIELD = 21; + /** + * Represents the position of the millisecond + * in the day pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'A'. + * This is a GNU extension in accordance with + * the CLDR data used. This value represents + * all the time fields (excluding the time zone) + * numerically, giving the number of milliseconds + * into the day (e.g. 10 in the morning would + * be 10 * 60 * 60 * 1000). Any daylight savings + * offset also affects this value. + */ + public static final int MILLISECOND_IN_DAY_FIELD = 22; + /** + * Represents the position of the RFC822 + * timezone pattern character in the array of + * localized pattern characters. + * In the U.S. locale, this is 'Z'. + * This is a GNU extension in accordance with + * the CLDR data used. The value is the offset + * of the current time from GMT e.g. -0500 would + * be five hours prior to GMT. + */ + public static final int RFC822_TIMEZONE_FIELD = 23; public static class Field extends Format.Field { @@ -136,14 +328,28 @@ public abstract class DateFormat extends Format implements Cloneable = new Field("hour0", Calendar.HOUR); public static final DateFormat.Field TIME_ZONE = new Field("timezone", Calendar.ZONE_OFFSET); - + public static final DateFormat.Field ISO_YEAR + = new Field("iso year", Calendar.YEAR); + public static final DateFormat.Field LOCALIZED_DAY_OF_WEEK + = new Field("localized day of week", Calendar.DAY_OF_WEEK); + public static final DateFormat.Field EXTENDED_YEAR + = new Field("extended year", Calendar.YEAR); + public static final DateFormat.Field MODIFIED_JULIAN_DAY + = new Field("julian day", -1); + public static final DateFormat.Field MILLISECOND_IN_DAY + = new Field("millisecond in day", -1); + public static final DateFormat.Field RFC822_TIME_ZONE + = new Field("rfc822 timezone", Calendar.ZONE_OFFSET); + static final DateFormat.Field[] allFields = { ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY1, HOUR_OF_DAY0, MINUTE, SECOND, MILLISECOND, DAY_OF_WEEK, DAY_OF_YEAR, DAY_OF_WEEK_IN_MONTH, WEEK_OF_YEAR, WEEK_OF_MONTH, AM_PM, HOUR1, HOUR0, - TIME_ZONE + TIME_ZONE, ISO_YEAR, LOCALIZED_DAY_OF_WEEK, + EXTENDED_YEAR, MODIFIED_JULIAN_DAY, MILLISECOND_IN_DAY, + RFC822_TIME_ZONE }; // For deserialization diff --git a/java/text/SimpleDateFormat.java b/java/text/SimpleDateFormat.java index 29d620533..568eeaae8 100644 --- a/java/text/SimpleDateFormat.java +++ b/java/text/SimpleDateFormat.java @@ -64,18 +64,93 @@ import java.util.regex.Pattern; */ public class SimpleDateFormat extends DateFormat { - /** A pair class used by SimpleDateFormat as a compiled representation - * of a format string. + /** + * 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. */ - private class FieldSizePair + private class CompiledField { - public int field; - public int size; + /** + * The ID of the field within the local pattern characters, + * or -1 if the sequence is invalid. + */ + private int field; + + /** + * The size of the character sequence. + */ + private int size; + + /** + * The character used. + */ + private char character; - /** Constructs a pair with the given field and size values */ - public FieldSizePair(int f, int s) { + /** + * Constructs a compiled field using the + * the given field ID, size and character + * values. + * + * @param f the field ID. + * @param s the size of the field. + * @param c the character used. + */ + public CompiledField(int f, int s, char c) { field = f; size = s; + character = c; + } + + /** + * Retrieves the ID of the field relative to + * the local pattern characters, or -1 if + * the sequence is invalid. + */ + public int getField() + { + return field; + } + + /** + * Retrieves the size of the character sequence. + */ + public int getSize() + { + return size; + } + + /** + * Retrieves the character used in the sequence. + */ + public char getCharacter() + { + return character; + } + + /** + * Returns a <code>String</code> representation + * of the compiled field, primarily for debugging + * purposes. + * + * @return a <code>String</code> representation. + */ + public String toString() + { + StringBuilder builder; + + builder = new StringBuilder(getClass().getName()); + builder.append("[field="); + builder.append(field); + builder.append(", size="); + builder.append(size); + builder.append(", character="); + builder.append(character); + builder.append("]"); + + return builder.toString(); } } @@ -87,10 +162,10 @@ public class SimpleDateFormat extends DateFormat private int serialVersionOnStream = 1; // 0 indicates JDK1.1.3 or earlier private static final long serialVersionUID = 4774881970558875024L; - // This string is specified in the JCL. We set it here rather than - // do a DateFormatSymbols(Locale.US).getLocalPatternChars() since - // someone could theoretically change those values (though unlikely). - private static final String standardChars = "GyMdkHmsSEDFwWahKzZ"; + // This string is specified in the root of the CLDR. We set it here + // rather than doing a DateFormatSymbols(Locale.US).getLocalPatternChars() + // since someone could theoretically change those values (though unlikely). + private static final String standardChars = "GyMdkHmsSEDFwWahKzYeugAZ"; private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException @@ -118,7 +193,7 @@ public class SimpleDateFormat extends DateFormat char thisChar; int pos; int field; - FieldSizePair current = null; + CompiledField current = null; for (int i=0; i<pattern.length(); i++) { thisChar = pattern.charAt(i); @@ -128,14 +203,14 @@ public class SimpleDateFormat extends DateFormat if ((thisChar >= 'A' && thisChar <= 'Z') || (thisChar >= 'a' && thisChar <= 'z')) { // Not a valid letter - tokens.add(new FieldSizePair(-1,0)); + tokens.add(new CompiledField(-1,0,thisChar)); } 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 FieldSizePair(-1,0)); + tokens.add(new CompiledField(-1,0,thisChar)); } if ((pos+1 < pattern.length()) && (pattern.charAt(pos+1) == '\'')) { tokens.add(pattern.substring(i+1,pos+1)); @@ -152,7 +227,7 @@ public class SimpleDateFormat extends DateFormat if ((current != null) && (field == current.field)) { current.size++; } else { - current = new FieldSizePair(field,1); + current = new CompiledField(field,1,thisChar); tokens.add(current); } } @@ -439,12 +514,12 @@ public class SimpleDateFormat extends DateFormat while (iter.hasNext()) { Object o = iter.next(); - if (o instanceof FieldSizePair) + if (o instanceof CompiledField) { - FieldSizePair p = (FieldSizePair) o; + CompiledField cf = (CompiledField) o; int beginIndex = buffer.length(); - switch (p.field) + switch (cf.getField()) { case ERA_FIELD: buffer.append (formatData.eras[calendar.get (Calendar.ERA)], DateFormat.Field.ERA); @@ -453,75 +528,75 @@ public class SimpleDateFormat extends DateFormat // If we have two digits, then we truncate. Otherwise, we // use the size of the pattern, and zero pad. buffer.setDefaultAttribute (DateFormat.Field.YEAR); - if (p.size == 2) + if (cf.getSize() == 2) { temp = String.valueOf (calendar.get (Calendar.YEAR)); buffer.append (temp.substring (temp.length() - 2)); } else - withLeadingZeros (calendar.get (Calendar.YEAR), p.size, buffer); + withLeadingZeros (calendar.get (Calendar.YEAR), cf.getSize(), buffer); break; case MONTH_FIELD: buffer.setDefaultAttribute (DateFormat.Field.MONTH); - if (p.size < 3) - withLeadingZeros (calendar.get (Calendar.MONTH) + 1, p.size, buffer); - else if (p.size < 4) + if (cf.getSize() < 3) + withLeadingZeros (calendar.get (Calendar.MONTH) + 1, cf.getSize(), buffer); + else if (cf.getSize() < 4) buffer.append (formatData.shortMonths[calendar.get (Calendar.MONTH)]); else buffer.append (formatData.months[calendar.get (Calendar.MONTH)]); break; case DATE_FIELD: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_MONTH); - withLeadingZeros (calendar.get (Calendar.DATE), p.size, buffer); + withLeadingZeros (calendar.get (Calendar.DATE), cf.getSize(), buffer); break; case HOUR_OF_DAY1_FIELD: // 1-24 buffer.setDefaultAttribute(DateFormat.Field.HOUR_OF_DAY1); withLeadingZeros ( ((calendar.get (Calendar.HOUR_OF_DAY) + 23) % 24) + 1, - p.size, buffer); + cf.getSize(), buffer); break; case HOUR_OF_DAY0_FIELD: // 0-23 buffer.setDefaultAttribute (DateFormat.Field.HOUR_OF_DAY0); - withLeadingZeros (calendar.get (Calendar.HOUR_OF_DAY), p.size, buffer); + withLeadingZeros (calendar.get (Calendar.HOUR_OF_DAY), cf.getSize(), buffer); break; case MINUTE_FIELD: buffer.setDefaultAttribute (DateFormat.Field.MINUTE); withLeadingZeros (calendar.get (Calendar.MINUTE), - p.size, buffer); + cf.getSize(), buffer); break; case SECOND_FIELD: buffer.setDefaultAttribute (DateFormat.Field.SECOND); withLeadingZeros(calendar.get (Calendar.SECOND), - p.size, buffer); + cf.getSize(), buffer); break; case MILLISECOND_FIELD: buffer.setDefaultAttribute (DateFormat.Field.MILLISECOND); - withLeadingZeros (calendar.get (Calendar.MILLISECOND), p.size, buffer); + withLeadingZeros (calendar.get (Calendar.MILLISECOND), cf.getSize(), buffer); break; case DAY_OF_WEEK_FIELD: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK); - if (p.size < 4) + if (cf.getSize() < 4) buffer.append (formatData.shortWeekdays[calendar.get (Calendar.DAY_OF_WEEK)]); else buffer.append (formatData.weekdays[calendar.get (Calendar.DAY_OF_WEEK)]); break; case DAY_OF_YEAR_FIELD: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_YEAR); - withLeadingZeros (calendar.get (Calendar.DAY_OF_YEAR), p.size, buffer); + withLeadingZeros (calendar.get (Calendar.DAY_OF_YEAR), cf.getSize(), buffer); break; case DAY_OF_WEEK_IN_MONTH_FIELD: buffer.setDefaultAttribute (DateFormat.Field.DAY_OF_WEEK_IN_MONTH); withLeadingZeros (calendar.get (Calendar.DAY_OF_WEEK_IN_MONTH), - p.size, buffer); + cf.getSize(), buffer); break; case WEEK_OF_YEAR_FIELD: buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_YEAR); withLeadingZeros (calendar.get (Calendar.WEEK_OF_YEAR), - p.size, buffer); + cf.getSize(), buffer); break; case WEEK_OF_MONTH_FIELD: buffer.setDefaultAttribute (DateFormat.Field.WEEK_OF_MONTH); withLeadingZeros (calendar.get (Calendar.WEEK_OF_MONTH), - p.size, buffer); + cf.getSize(), buffer); break; case AM_PM_FIELD: buffer.setDefaultAttribute (DateFormat.Field.AM_PM); @@ -529,25 +604,39 @@ public class SimpleDateFormat extends DateFormat break; case HOUR1_FIELD: // 1-12 buffer.setDefaultAttribute (DateFormat.Field.HOUR1); - withLeadingZeros (((calendar.get (Calendar.HOUR) + 11) % 12) + 1, p.size, buffer); + withLeadingZeros (((calendar.get (Calendar.HOUR) + 11) % 12) + 1, + cf.getSize(), buffer); break; case HOUR0_FIELD: // 0-11 buffer.setDefaultAttribute (DateFormat.Field.HOUR0); - withLeadingZeros (calendar.get (Calendar.HOUR), p.size, buffer); + withLeadingZeros (calendar.get (Calendar.HOUR), cf.getSize(), buffer); break; case TIMEZONE_FIELD: buffer.setDefaultAttribute (DateFormat.Field.TIME_ZONE); TimeZone zone = calendar.getTimeZone(); boolean isDST = calendar.get (Calendar.DST_OFFSET) != 0; // FIXME: XXX: This should be a localized time zone. - String zoneID = zone.getDisplayName (isDST, p.size > 3 ? TimeZone.LONG : TimeZone.SHORT); + String zoneID = zone.getDisplayName + (isDST, cf.getSize() > 3 ? TimeZone.LONG : TimeZone.SHORT); buffer.append (zoneID); break; + case RFC822_TIMEZONE_FIELD: + buffer.setDefaultAttribute(DateFormat.Field.RFC822_TIME_ZONE); + int pureMinutes = (calendar.get(Calendar.ZONE_OFFSET) + + calendar.get(Calendar.DST_OFFSET)) / (1000 * 60); + String sign = (pureMinutes < 0) ? "-" : "+"; + int hours = pureMinutes / 60; + int minutes = pureMinutes % 60; + buffer.append(sign); + withLeadingZeros(hours, 2, buffer); + withLeadingZeros(minutes, 2, buffer); + break; default: - throw new IllegalArgumentException ("Illegal pattern character " + p.field); + throw new IllegalArgumentException ("Illegal pattern character " + + cf.getCharacter()); } if (pos != null && (buffer.getDefaultAttribute() == pos.getFieldAttribute() - || p.field == pos.getField())) + || cf.getField() == pos.getField())) { pos.setBeginIndex(beginIndex); pos.setEndIndex(buffer.length()); |