Created
February 19, 2013 16:17
-
-
Save jodastephen/4987319 to your computer and use it in GitHub Desktop.
APPLIED: yyyy/uuuu change. Patch for #138
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User scolebourne | |
# Date 1361280934 0 | |
# Node ID d89b0d612e3c4e44e31934f24b972bb0ae22edca | |
# Parent 8abd40f9e8efb0aa295935698b3505ffdfcb7820 | |
Fix tests which test implementation, not spec | |
diff --git a/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java b/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java | |
--- a/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java | |
+++ b/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java | |
@@ -77,6 +77,7 @@ | |
import java.time.DateTimeException; | |
import java.time.LocalDate; | |
import java.time.LocalDateTime; | |
+import java.time.Month; | |
import java.time.Year; | |
import java.time.YearMonth; | |
import java.time.ZoneId; | |
@@ -85,6 +86,7 @@ | |
import java.time.chrono.Chronology; | |
import java.time.format.DateTimeFormatter; | |
import java.time.format.DateTimeParseException; | |
+import java.time.format.TextStyle; | |
import java.time.temporal.IsoFields; | |
import java.time.temporal.Queries; | |
import java.time.temporal.TemporalAccessor; | |
@@ -111,7 +113,7 @@ | |
//----------------------------------------------------------------------- | |
@Test(expectedExceptions=NullPointerException.class, groups={"tck"}) | |
- public void test_print_nullCalendrical() { | |
+ public void test_format_nullTemporalAccessor() { | |
DateTimeFormatter.ISO_DATE.format((TemporalAccessor) null); | |
} | |
@@ -121,7 +123,8 @@ | |
@Test(groups={"tck"}) | |
public void test_pattern_String() { | |
DateTimeFormatter test = DateTimeFormatter.ofPattern("d MMM yyyy"); | |
- assertEquals(test.toString(), "Value(DayOfMonth)' 'Text(MonthOfYear,SHORT)' 'Value(Year,4,19,EXCEEDS_PAD)"); | |
+ assertEquals(test.format(LocalDate.of(2012, 6, 30)), "30 " + | |
+ Month.JUNE.getDisplayName(TextStyle.SHORT, Locale.getDefault()) + " 2012"); | |
assertEquals(test.getLocale(), Locale.getDefault()); | |
} | |
@@ -141,7 +144,7 @@ | |
@Test(groups={"tck"}) | |
public void test_pattern_StringLocale() { | |
DateTimeFormatter test = DateTimeFormatter.ofPattern("d MMM yyyy", Locale.UK); | |
- assertEquals(test.toString(), "Value(DayOfMonth)' 'Text(MonthOfYear,SHORT)' 'Value(Year,4,19,EXCEEDS_PAD)"); | |
+ assertEquals(test.format(LocalDate.of(2012, 6, 30)), "30 Jun 2012"); | |
assertEquals(test.getLocale(), Locale.UK); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User scolebourne | |
# Date 1361281148 0 | |
# Node ID 88c32995f0018599d77b2f5d588687f22ffa0259 | |
# Parent d89b0d612e3c4e44e31934f24b972bb0ae22edca | |
Update internal formatting notes | |
diff --git a/src/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/share/classes/java/time/format/DateTimeFormatterBuilder.java | |
--- a/src/share/classes/java/time/format/DateTimeFormatterBuilder.java | |
+++ b/src/share/classes/java/time/format/DateTimeFormatterBuilder.java | |
@@ -1448,28 +1448,29 @@ | |
/** Map of letters to fields. */ | |
private static final Map<Character, TemporalField> FIELD_MAP = new HashMap<>(); | |
static { | |
- FIELD_MAP.put('G', ChronoField.ERA); // Java, LDML (different to both for 1/2 chars) | |
+ // SDF = SimpleDateFormat | |
+ FIELD_MAP.put('G', ChronoField.ERA); // SDF, LDML (different to both for 1/2 chars) | |
FIELD_MAP.put('y', ChronoField.YEAR); // LDML | |
- // FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA); // Java, LDML // TODO redefine from above | |
- // FIELD_MAP.put('u', ChronoField.YEAR); // LDML // TODO | |
- // FIELD_MAP.put('Y', IsoFields.WEEK_BASED_YEAR); // Java7, LDML (needs localized week number) // TODO | |
+ // FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA); // SDF, LDML // TODO redefine from above | |
+ // FIELD_MAP.put('u', ChronoField.YEAR); // LDML (different in SDF) // TODO | |
+ // FIELD_MAP.put('Y', IsoFields.WEEK_BASED_YEAR); // SDF7, LDML (needs localized week number) // TODO | |
FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR); // LDML (removed quarter from 310) | |
- FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR); // Java, LDML | |
- // FIELD_MAP.put('w', WeekFields.weekOfYear()); // Java, LDML (needs localized week number) | |
- // FIELD_MAP.put('W', WeekFields.weekOfMonth()); // Java, LDML (needs localized week number) | |
- FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR); // Java, LDML | |
- FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH); // Java, LDML | |
- FIELD_MAP.put('F', ChronoField.ALIGNED_WEEK_OF_MONTH); // Java, LDML | |
- FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK); // Java, LDML (different to both for 1/2 chars) | |
+ FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR); // SDF, LDML | |
+ // FIELD_MAP.put('w', WeekFields.weekOfYear()); // SDF, LDML (needs localized week number) | |
+ // FIELD_MAP.put('W', WeekFields.weekOfMonth()); // SDF, LDML (needs localized week number) | |
+ FIELD_MAP.put('D', ChronoField.DAY_OF_YEAR); // SDF, LDML | |
+ FIELD_MAP.put('d', ChronoField.DAY_OF_MONTH); // SDF, LDML | |
+ FIELD_MAP.put('F', ChronoField.ALIGNED_WEEK_OF_MONTH); // SDF, LDML | |
+ FIELD_MAP.put('E', ChronoField.DAY_OF_WEEK); // SDF, LDML (different to both for 1/2 chars) | |
// FIELD_MAP.put('e', WeekFields.dayOfWeek()); // LDML (needs localized week number) | |
- FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY); // Java, LDML | |
- FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY); // Java, LDML | |
- FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY); // Java, LDML | |
- FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM); // Java, LDML | |
- FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM); // Java, LDML | |
- FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR); // Java, LDML | |
- FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE); // Java, LDML | |
- FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND); // LDML (Java uses milli-of-second number) | |
+ FIELD_MAP.put('a', ChronoField.AMPM_OF_DAY); // SDF, LDML | |
+ FIELD_MAP.put('H', ChronoField.HOUR_OF_DAY); // SDF, LDML | |
+ FIELD_MAP.put('k', ChronoField.CLOCK_HOUR_OF_DAY); // SDF, LDML | |
+ FIELD_MAP.put('K', ChronoField.HOUR_OF_AMPM); // SDF, LDML | |
+ FIELD_MAP.put('h', ChronoField.CLOCK_HOUR_OF_AMPM); // SDF, LDML | |
+ FIELD_MAP.put('m', ChronoField.MINUTE_OF_HOUR); // SDF, LDML | |
+ FIELD_MAP.put('s', ChronoField.SECOND_OF_MINUTE); // SDF, LDML | |
+ FIELD_MAP.put('S', ChronoField.NANO_OF_SECOND); // LDML (SDF uses milli-of-second number) | |
FIELD_MAP.put('A', ChronoField.MILLI_OF_DAY); // LDML | |
FIELD_MAP.put('n', ChronoField.NANO_OF_SECOND); // 310 (proposed for LDML) | |
FIELD_MAP.put('N', ChronoField.NANO_OF_DAY); // 310 (proposed for LDML) | |
@@ -1477,9 +1478,8 @@ | |
// 310 - Z - matches SimpleDateFormat and LDML | |
// 310 - V - time-zone id, matches proposed LDML | |
// 310 - p - prefix for padding | |
- // 310 - X - matches proposed LDML, almost matches JavaSDF for 1, exact match 2&3, extended 4&5 | |
+ // 310 - X - matches proposed LDML, almost matches SDF for 1, exact match 2&3, extended 4&5 | |
// 310 - x - matches proposed LDML | |
- // Java - u - clashes with LDML, go with LDML (year-proleptic) here | |
// LDML - U - cycle year name, not supported by 310 yet | |
// LDML - l - deprecated | |
// LDML - j - not relevant |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User scolebourne | |
# Date 1361287315 0 | |
# Node ID 82829bf8208219ee0709d94ea7f9d0a7f38f00ec | |
# Parent 88c32995f0018599d77b2f5d588687f22ffa0259 | |
Move resolve of year-of-era earlier and into Chronology | |
Needs to be before non-ChronoField processing, so that WeekFields works | |
Needs to be in Chronology to allow selection of default era | |
IsoChronology also gets to have a performance boost | |
Fixed JapaneseChronology.prolepticYear to be stricter wrt year-of-era | |
diff --git a/src/share/classes/java/time/chrono/Chronology.java b/src/share/classes/java/time/chrono/Chronology.java | |
--- a/src/share/classes/java/time/chrono/Chronology.java | |
+++ b/src/share/classes/java/time/chrono/Chronology.java | |
@@ -61,6 +61,8 @@ | |
*/ | |
package java.time.chrono; | |
+import static java.time.temporal.ChronoField.YEAR_OF_ERA; | |
+ | |
import java.io.DataInput; | |
import java.io.DataOutput; | |
import java.io.IOException; | |
@@ -72,10 +74,6 @@ | |
import java.time.LocalDate; | |
import java.time.LocalTime; | |
import java.time.ZoneId; | |
-import java.time.chrono.HijrahChronology; | |
-import java.time.chrono.JapaneseChronology; | |
-import java.time.chrono.MinguoChronology; | |
-import java.time.chrono.ThaiBuddhistChronology; | |
import java.time.format.DateTimeFormatterBuilder; | |
import java.time.format.TextStyle; | |
import java.time.temporal.ChronoField; | |
@@ -379,7 +377,7 @@ | |
*/ | |
public static Set<Chronology> getAvailableChronologies() { | |
initCache(); // force initialization | |
- HashSet<Chronology> chronos = new HashSet(CHRONOS_BY_ID.values()); | |
+ HashSet<Chronology> chronos = new HashSet<>(CHRONOS_BY_ID.values()); | |
/// Add in Chronologies from the ServiceLoader configuration | |
@SuppressWarnings("rawtypes") | |
@@ -703,11 +701,16 @@ | |
* Calculates the proleptic-year given the era and year-of-era. | |
* <p> | |
* This combines the era and year-of-era into the single proleptic-year field. | |
+ * <p> | |
+ * If the chronology makes active use of eras, such as {@code JapaneseChronology} | |
+ * then the year-of-era will be validated against the era. | |
+ * For other chronologies, validation is optional. | |
* | |
* @param era the era of the correct type for the chronology, not null | |
* @param yearOfEra the chronology year-of-era | |
* @return the proleptic-year | |
- * @throws DateTimeException if unable to convert | |
+ * @throws DateTimeException if unable to convert to a proleptic-year, | |
+ * such as if the year is invalid for the era | |
*/ | |
public abstract int prolepticYear(Era era, int yearOfEra); | |
@@ -797,6 +800,38 @@ | |
//----------------------------------------------------------------------- | |
/** | |
+ * Resolves the year-of-era and era during parsing. | |
+ * <p> | |
+ * This combines the era and year-of-era into the single proleptic-year field. | |
+ * A suitable default value for the era must be used if the era is not provided. | |
+ * <p> | |
+ * The default implementation defaults using the last era in the list | |
+ * returned by {@link #eras()}. | |
+ * | |
+ * @param yearOfEra the chronology year-of-era | |
+ * @param era the era of the correct type for the chronology, null if | |
+ * the era must be defaulted by this method | |
+ * @return the proleptic-year | |
+ * @throws DateTimeException if unable to resolve the year | |
+ */ | |
+ public long resolveYearOfEra(long yearOfEra, Long era) { | |
+ int yoe = range(YEAR_OF_ERA).checkValidIntValue(yearOfEra, YEAR_OF_ERA); | |
+ Era eraObj; | |
+ if (era != null) { | |
+ eraObj = eraOf(Math.toIntExact(era)); | |
+ } else { | |
+ List<Era> eras = eras(); | |
+ if (eras.isEmpty()) { | |
+ return yoe; | |
+ } else { | |
+ eraObj = eras.get(eras.size() - 1); | |
+ } | |
+ } | |
+ return prolepticYear(eraObj, yoe); | |
+ } | |
+ | |
+ //----------------------------------------------------------------------- | |
+ /** | |
* Compares this chronology to another chronology. | |
* <p> | |
* The comparison order first by the chronology ID string, then by any | |
diff --git a/src/share/classes/java/time/chrono/IsoChronology.java b/src/share/classes/java/time/chrono/IsoChronology.java | |
--- a/src/share/classes/java/time/chrono/IsoChronology.java | |
+++ b/src/share/classes/java/time/chrono/IsoChronology.java | |
@@ -394,6 +394,17 @@ | |
return Arrays.<Era>asList(IsoEra.values()); | |
} | |
+ @Override // override for performance | |
+ public long resolveYearOfEra(long yearOfEra, Long era) { | |
+ if (era == null || era.longValue() == 1L) { | |
+ return yearOfEra; | |
+ } else if (era.longValue() == 0L) { | |
+ return Math.subtractExact(1, yearOfEra); | |
+ } else { | |
+ throw new DateTimeException("Invalid value for era: " + era); | |
+ } | |
+ } | |
+ | |
//----------------------------------------------------------------------- | |
@Override | |
public ValueRange range(ChronoField field) { | |
diff --git a/src/share/classes/java/time/chrono/JapaneseChronology.java b/src/share/classes/java/time/chrono/JapaneseChronology.java | |
--- a/src/share/classes/java/time/chrono/JapaneseChronology.java | |
+++ b/src/share/classes/java/time/chrono/JapaneseChronology.java | |
@@ -273,6 +273,9 @@ | |
} | |
LocalGregorianCalendar.Date jdate = JCAL.newCalendarDate(null); | |
jdate.setEra(jera.getPrivateEra()).setDate(yearOfEra, 1, 1); | |
+ if (!JapaneseChronology.JCAL.validate(jdate)) { | |
+ throw new DateTimeException("invalid yearOfEra value"); | |
+ } | |
JCAL.normalize(jdate); | |
if (jdate.getNormalizedYear() == gregorianYear) { | |
return gregorianYear; | |
diff --git a/src/share/classes/java/time/format/DateTimeBuilder.java b/src/share/classes/java/time/format/DateTimeBuilder.java | |
--- a/src/share/classes/java/time/format/DateTimeBuilder.java | |
+++ b/src/share/classes/java/time/format/DateTimeBuilder.java | |
@@ -254,7 +254,6 @@ | |
return; | |
} | |
- Era era = null; | |
if (chrono == IsoChronology.INSTANCE) { | |
// normalize fields | |
if (standardFields.containsKey(EPOCH_MONTH)) { | |
@@ -273,20 +272,6 @@ | |
checkDate(date); | |
return; | |
} | |
- List<Era> eras = chrono.eras(); | |
- if (!eras.isEmpty()) { | |
- if (standardFields.containsKey(ERA)) { | |
- long index = standardFields.remove(ERA); | |
- era = chrono.eraOf((int) index); | |
- } else { | |
- era = eras.get(eras.size() - 1); // current Era | |
- } | |
- if (standardFields.containsKey(YEAR_OF_ERA)) { | |
- Long y = standardFields.remove(YEAR_OF_ERA); | |
- putFieldValue0(YEAR, y); | |
- } | |
- } | |
- | |
} | |
// build date | |
@@ -301,11 +286,7 @@ | |
date = LocalDate.of(y, moy, dom); | |
} else { | |
ChronoLocalDate<?> chronoDate; | |
- if (era == null) { | |
- chronoDate = chrono.date(y, moy, dom); | |
- } else { | |
- chronoDate = era.date(y, moy, dom); | |
- } | |
+ chronoDate = chrono.date(y, moy, dom); | |
date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); | |
} | |
checkDate(date); | |
@@ -322,11 +303,7 @@ | |
date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7 + (ad - 1)); | |
} else { | |
ChronoLocalDate<?> chronoDate; | |
- if (era == null) { | |
- chronoDate = chrono.date(y, moy, 1); | |
- } else { | |
- chronoDate = era.date(y, moy, 1); | |
- } | |
+ chronoDate = chrono.date(y, moy, 1); | |
chronoDate = chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); | |
date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); | |
} | |
@@ -343,11 +320,7 @@ | |
date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))); | |
} else { | |
ChronoLocalDate<?> chronoDate; | |
- if (era == null) { | |
- chronoDate = chrono.date(y, moy, 1); | |
- } else { | |
- chronoDate = era.date(y, moy, 1); | |
- } | |
+ chronoDate = chrono.date(y, moy, 1); | |
chronoDate = chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); | |
date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); | |
} | |
@@ -364,11 +337,7 @@ | |
date = LocalDate.ofYearDay(y, doy); | |
} else { | |
ChronoLocalDate<?> chronoDate; | |
- if (era == null) { | |
- chronoDate = chrono.dateYearDay(y, doy); | |
- } else { | |
- chronoDate = era.dateYearDay(y, doy); | |
- } | |
+ chronoDate = chrono.dateYearDay(y, doy); | |
date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); | |
} | |
checkDate(date); | |
@@ -384,11 +353,7 @@ | |
date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7 + (ad - 1)); | |
} else { | |
ChronoLocalDate<?> chronoDate; | |
- if (era == null) { | |
- chronoDate = chrono.dateYearDay(y, 1); | |
- } else { | |
- chronoDate = era.dateYearDay(y, 1); | |
- } | |
+ chronoDate = chrono.dateYearDay(y, 1); | |
chronoDate = chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); | |
date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); | |
} | |
@@ -404,11 +369,7 @@ | |
date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow))); | |
} else { | |
ChronoLocalDate<?> chronoDate; | |
- if (era == null) { | |
- chronoDate = chrono.dateYearDay(y, 1); | |
- } else { | |
- chronoDate = era.dateYearDay(y, 1); | |
- } | |
+ chronoDate = chrono.dateYearDay(y, 1); | |
chronoDate = chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); | |
date = LocalDate.ofEpochDay(chronoDate.toEpochDay()); | |
} | |
diff --git a/src/share/classes/java/time/format/DateTimeParseContext.java b/src/share/classes/java/time/format/DateTimeParseContext.java | |
--- a/src/share/classes/java/time/format/DateTimeParseContext.java | |
+++ b/src/share/classes/java/time/format/DateTimeParseContext.java | |
@@ -61,9 +61,14 @@ | |
*/ | |
package java.time.format; | |
+import static java.time.temporal.ChronoField.ERA; | |
+import static java.time.temporal.ChronoField.YEAR; | |
+import static java.time.temporal.ChronoField.YEAR_OF_ERA; | |
+ | |
import java.time.DateTimeException; | |
import java.time.ZoneId; | |
import java.time.chrono.Chronology; | |
+import java.time.chrono.Era; | |
import java.time.chrono.IsoChronology; | |
import java.time.temporal.ChronoField; | |
import java.time.temporal.Queries; | |
@@ -72,6 +77,7 @@ | |
import java.time.temporal.TemporalQuery; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
+import java.util.List; | |
import java.util.Locale; | |
import java.util.Map; | |
import java.util.Objects; | |
@@ -401,6 +407,7 @@ | |
*/ | |
DateTimeParseContext resolveFields() { | |
Parsed data = currentParsed(); | |
+ resolveChronoField(data); | |
outer: | |
while (true) { | |
for (Map.Entry<TemporalField, Long> entry : data.fieldValues.entrySet()) { | |
@@ -423,18 +430,31 @@ | |
Long changeValue = change.getValue(); | |
Objects.requireNonNull(changeField, "changeField"); | |
if (changeValue != null) { | |
- Long old = currentParsed().fieldValues.put(changeField, changeValue); | |
- if (old != null && old.longValue() != changeValue.longValue()) { | |
- throw new DateTimeException("Conflict found: " + changeField + " " + old + | |
- " differs from " + changeField + " " + changeValue + | |
- " while resolving " + targetField); | |
- } | |
+ updateCheckConflict(data, targetField, changeField, changeValue); | |
} else { | |
data.fieldValues.remove(changeField); | |
} | |
} | |
} | |
+ private void updateCheckConflict(Parsed data, TemporalField targetField, TemporalField changeField, Long changeValue) { | |
+ Long old = data.fieldValues.put(changeField, changeValue); | |
+ if (old != null && old.longValue() != changeValue.longValue()) { | |
+ throw new DateTimeException("Conflict found: " + changeField + " " + old + | |
+ " differs from " + changeField + " " + changeValue + | |
+ " while resolving " + targetField); | |
+ } | |
+ } | |
+ | |
+ private void resolveChronoField(Parsed data) { | |
+ Long yoeVal = data.fieldValues.remove(YEAR_OF_ERA); | |
+ if (yoeVal != null) { | |
+ Long eraVal = data.fieldValues.remove(ERA); | |
+ long year = getEffectiveChronology().resolveYearOfEra(yoeVal, eraVal); | |
+ updateCheckConflict(data, YEAR_OF_ERA, YEAR, year); | |
+ } | |
+ } | |
+ | |
//----------------------------------------------------------------------- | |
// TemporalAccessor methods | |
// should only to be used once parsing is complete | |
diff --git a/src/share/classes/java/time/temporal/ChronoField.java b/src/share/classes/java/time/temporal/ChronoField.java | |
--- a/src/share/classes/java/time/temporal/ChronoField.java | |
+++ b/src/share/classes/java/time/temporal/ChronoField.java | |
@@ -76,6 +76,7 @@ | |
import java.time.ZoneOffset; | |
import java.time.chrono.ChronoLocalDate; | |
import java.time.chrono.Chronology; | |
+import java.util.Map; | |
/** | |
* A standard set of fields. | |
diff --git a/test/java/time/tck/java/time/chrono/TestJapaneseChronology.java b/test/java/time/tck/java/time/chrono/TestJapaneseChronology.java | |
--- a/test/java/time/tck/java/time/chrono/TestJapaneseChronology.java | |
+++ b/test/java/time/tck/java/time/chrono/TestJapaneseChronology.java | |
@@ -220,30 +220,23 @@ | |
@DataProvider(name="prolepticYear") | |
Object[][] data_prolepticYear() { | |
return new Object[][] { | |
- {2, JapaneseChronology.ERA_HEISEI, 1, 1 + YDIFF_HEISEI, false}, | |
- {2, JapaneseChronology.ERA_HEISEI, 100, 100 + YDIFF_HEISEI, true}, | |
- {2, JapaneseChronology.ERA_HEISEI, 0, YDIFF_HEISEI, true}, | |
- {2, JapaneseChronology.ERA_HEISEI, -10, -10 + YDIFF_HEISEI, false}, | |
+ {2, JapaneseChronology.ERA_HEISEI, 1, 1 + YDIFF_HEISEI, false}, | |
+ {2, JapaneseChronology.ERA_HEISEI, 100, 100 + YDIFF_HEISEI, true}, | |
+ {2, JapaneseChronology.ERA_HEISEI, 0, YDIFF_HEISEI, true}, | |
+ {2, JapaneseChronology.ERA_HEISEI, -10, -10 + YDIFF_HEISEI, false}, | |
- {-1, JapaneseChronology.ERA_MEIJI, 1, 1 + YDIFF_MEIJI, true}, | |
- {-1, JapaneseChronology.ERA_MEIJI, 100, 100 + YDIFF_MEIJI, false}, | |
- {-1, JapaneseChronology.ERA_MEIJI, 0, YDIFF_MEIJI, false}, | |
- {-1, JapaneseChronology.ERA_MEIJI, -10, -10 + YDIFF_MEIJI, false}, | |
+ {-1, JapaneseChronology.ERA_MEIJI, 1, 1 + YDIFF_MEIJI, true}, | |
+ {-1, JapaneseChronology.ERA_MEIJI, 4, 4 + YDIFF_MEIJI, false}, | |
- {1, JapaneseChronology.ERA_SHOWA, 1, 1 + YDIFF_SHOWA, false}, | |
- {1, JapaneseChronology.ERA_SHOWA, 100, 100 + YDIFF_SHOWA, false}, | |
- {1, JapaneseChronology.ERA_SHOWA, 0, YDIFF_SHOWA, false}, | |
- {1, JapaneseChronology.ERA_SHOWA, -5, -5 + YDIFF_SHOWA, true}, | |
+ {1, JapaneseChronology.ERA_SHOWA, 1, 1 + YDIFF_SHOWA, false}, | |
+ {1, JapaneseChronology.ERA_SHOWA, 7, 7 + YDIFF_SHOWA, true}, | |
- {0, JapaneseChronology.ERA_TAISHO, 1, 1 + YDIFF_TAISHO, true}, | |
- {0, JapaneseChronology.ERA_TAISHO, 100, 100 + YDIFF_TAISHO, false}, | |
- {0, JapaneseChronology.ERA_TAISHO, 0, YDIFF_TAISHO, false}, | |
- {0, JapaneseChronology.ERA_TAISHO, -10, -10 + YDIFF_TAISHO, false}, | |
- | |
+ {0, JapaneseChronology.ERA_TAISHO, 1, 1 + YDIFF_TAISHO, true}, | |
+ {0, JapaneseChronology.ERA_TAISHO, 4, 4 + YDIFF_TAISHO, false}, | |
}; | |
} | |
- @Test(dataProvider="prolepticYear", groups={"tck"}) | |
+ @Test(dataProvider="prolepticYear") | |
public void test_prolepticYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { | |
Era eraObj = JapaneseChronology.INSTANCE.eraOf(eraValue) ; | |
assertTrue(JapaneseChronology.INSTANCE.eras().contains(eraObj)); | |
@@ -253,6 +246,28 @@ | |
assertEquals(JapaneseChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear).isLeap()) ; | |
} | |
+ @DataProvider(name="prolepticYearError") | |
+ Object[][] data_prolepticYearError() { | |
+ return new Object[][] { | |
+ {JapaneseChronology.ERA_MEIJI, 100}, | |
+ {JapaneseChronology.ERA_MEIJI, 0}, | |
+ {JapaneseChronology.ERA_MEIJI, -10}, | |
+ | |
+ {JapaneseChronology.ERA_SHOWA, 100}, | |
+ {JapaneseChronology.ERA_SHOWA, 0}, | |
+ {JapaneseChronology.ERA_SHOWA, -10}, | |
+ | |
+ {JapaneseChronology.ERA_TAISHO, 100}, | |
+ {JapaneseChronology.ERA_TAISHO, 0}, | |
+ {JapaneseChronology.ERA_TAISHO, -10}, | |
+ }; | |
+ } | |
+ | |
+ @Test(dataProvider="prolepticYearError", expectedExceptions=DateTimeException.class) | |
+ public void test_prolepticYearError(Era era, int yearOfEra) { | |
+ JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra); | |
+ } | |
+ | |
//----------------------------------------------------------------------- | |
// with(WithAdjuster) | |
//----------------------------------------------------------------------- | |
diff --git a/test/java/time/test/java/time/format/TestNonIsoFormatter.java b/test/java/time/test/java/time/format/TestNonIsoFormatter.java | |
--- a/test/java/time/test/java/time/format/TestNonIsoFormatter.java | |
+++ b/test/java/time/test/java/time/format/TestNonIsoFormatter.java | |
@@ -79,7 +79,9 @@ | |
Object[][] invalidText() { | |
return new Object[][] { | |
// TODO: currently fixed Chronology and Locale. | |
- { "\u662d\u548c64\u5e741\u67089\u65e5\u6708\u66dc\u65e5" }, // S64.01.09 (Mon) | |
+ // line commented out, as S64.01.09 seems like a reasonable thing to parse | |
+ // (era "S" ended on S64.01.07, but a little leniency is a good thing | |
+// { "\u662d\u548c64\u5e741\u67089\u65e5\u6708\u66dc\u65e5" }, // S64.01.09 (Mon) | |
{ "\u662d\u548c65\u5e741\u67081\u65e5\u6708\u66dc\u65e5" }, // S65.01.01 (Mon) | |
}; | |
} | |
@@ -105,6 +107,6 @@ | |
public void test_parseInvalidText(String text) { | |
DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) | |
.withChronology(JAPANESE).withLocale(Locale.JAPANESE); | |
- TemporalAccessor temporal = dtf.parse(text); | |
+ dtf.parse(text); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User scolebourne | |
# Date 1361289103 0 | |
# Node ID d468d92a8986851ad83330bafa0f440a53216a6e | |
# Parent 82829bf8208219ee0709d94ea7f9d0a7f38f00ec | |
Swap pattern letters y and u | |
See #138 | |
diff --git a/src/share/classes/java/time/LocalDate.java b/src/share/classes/java/time/LocalDate.java | |
--- a/src/share/classes/java/time/LocalDate.java | |
+++ b/src/share/classes/java/time/LocalDate.java | |
@@ -1912,7 +1912,7 @@ | |
/** | |
* Outputs this date as a {@code String}, such as {@code 2007-12-03}. | |
* <p> | |
- * The output will be in the ISO-8601 format {@code yyyy-MM-dd}. | |
+ * The output will be in the ISO-8601 format {@code uuuu-MM-dd}. | |
* | |
* @return a string representation of this date, not null | |
*/ | |
diff --git a/src/share/classes/java/time/LocalDateTime.java b/src/share/classes/java/time/LocalDateTime.java | |
--- a/src/share/classes/java/time/LocalDateTime.java | |
+++ b/src/share/classes/java/time/LocalDateTime.java | |
@@ -1834,11 +1834,11 @@ | |
* <p> | |
* The output will be one of the following ISO-8601 formats: | |
* <p><ul> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm}</li> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm:ss}</li> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSS}</li> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSS}</li> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm:ss}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSS}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSS}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS}</li> | |
* </ul><p> | |
* The format used will be the shortest that outputs the full value of | |
* the time where the omitted parts are implied to be zero. | |
diff --git a/src/share/classes/java/time/OffsetDateTime.java b/src/share/classes/java/time/OffsetDateTime.java | |
--- a/src/share/classes/java/time/OffsetDateTime.java | |
+++ b/src/share/classes/java/time/OffsetDateTime.java | |
@@ -1796,11 +1796,11 @@ | |
* <p> | |
* The output will be one of the following ISO-8601 formats: | |
* <p><ul> | |
- * <li>{@code yyyy-MM-dd'T'HH:mmXXXXX}</li> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm:ssXXXXX}</li> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX}</li> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXXXX}</li> | |
- * <li>{@code yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mmXXXXX}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm:ssXXXXX}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSXXXXX}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXXXX}</li> | |
+ * <li>{@code uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX}</li> | |
* </ul><p> | |
* The format used will be the shortest that outputs the full value of | |
* the time where the omitted parts are implied to be zero. | |
diff --git a/src/share/classes/java/time/YearMonth.java b/src/share/classes/java/time/YearMonth.java | |
--- a/src/share/classes/java/time/YearMonth.java | |
+++ b/src/share/classes/java/time/YearMonth.java | |
@@ -255,7 +255,7 @@ | |
* Obtains an instance of {@code YearMonth} from a text string such as {@code 2007-12}. | |
* <p> | |
* The string must represent a valid year-month. | |
- * The format must be {@code yyyy-MM}. | |
+ * The format must be {@code uuuu-MM}. | |
* Years outside the range 0000 to 9999 must be prefixed by the plus or minus symbol. | |
* | |
* @param text the text to parse such as "2007-12", not null | |
@@ -1115,7 +1115,7 @@ | |
/** | |
* Outputs this year-month as a {@code String}, such as {@code 2007-12}. | |
* <p> | |
- * The output will be in the format {@code yyyy-MM}: | |
+ * The output will be in the format {@code uuuu-MM}: | |
* | |
* @return a string representation of this year-month, not null | |
*/ | |
diff --git a/src/share/classes/java/time/format/DateTimeFormatter.java b/src/share/classes/java/time/format/DateTimeFormatter.java | |
--- a/src/share/classes/java/time/format/DateTimeFormatter.java | |
+++ b/src/share/classes/java/time/format/DateTimeFormatter.java | |
@@ -96,7 +96,7 @@ | |
* This class provides the main application entry point for printing and parsing | |
* and provides common implementations of {@code DateTimeFormatter}: | |
* <p><ul> | |
- * <li>Using pattern letters, such as {@code yyyy-MMM-dd} | |
+ * <li>Using pattern letters, such as {@code uuuu-MMM-dd} | |
* <li>Using localized styles, such as {@code long} or {@code medium} | |
* <li>Using predefined constants, such as {@code ISO_LOCAL_DATE} | |
* </ul></p> | |
@@ -152,7 +152,7 @@ | |
* Creates a formatter using the specified pattern. | |
* <p> | |
* This method will create a formatter based on a simple pattern of letters and symbols. | |
- * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. | |
+ * For example, {@code d MMM uuuu} will format 2011-12-03 as '3 Dec 2011'. | |
* <p> | |
* The returned formatter will use the default locale, but this can be changed | |
* using {@link DateTimeFormatter#withLocale(Locale)}. | |
@@ -163,7 +163,8 @@ | |
* Symbol Meaning Presentation Examples | |
* ------ ------- ------------ ------- | |
* G era text A; AD; Anno Domini | |
- * y year year 2004; 04 | |
+ * u year year 2004; 04 | |
+ * y year-of-era year 2004; 04 | |
* D day-of-year number 189 | |
* M month-of-year number/text 7; 07; Jul; July; J | |
* d day-of-month number 10 | |
@@ -288,7 +289,7 @@ | |
* Creates a formatter using the specified pattern. | |
* <p> | |
* This method will create a formatter based on a simple pattern of letters and symbols. | |
- * For example, {@code d MMM yyyy} will format 2011-12-03 as '3 Dec 2011'. | |
+ * For example, {@code d MMM uuuu} will format 2011-12-03 as '3 Dec 2011'. | |
* <p> | |
* See {@link #ofPattern(String)} for details of the pattern. | |
* <p> | |
@@ -1238,7 +1239,7 @@ | |
* Fully parses the text producing an object of one of the specified types. | |
* <p> | |
* This parse method is convenient for use when the parser can handle optional elements. | |
- * For example, a pattern of 'yyyy-MM-dd HH.mm[Z]]' can be fully parsed to a {@code ZonedDateTime}, | |
+ * For example, a pattern of 'uuuu-MM-dd HH.mm[ VV]' can be fully parsed to a {@code ZonedDateTime}, | |
* or partially parsed to a {@code LocalDateTime}. | |
* The queries must be specified in order, starting from the best matching full-parse option | |
* and ending with the worst matching minimal parse option. | |
diff --git a/src/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/share/classes/java/time/format/DateTimeFormatterBuilder.java | |
--- a/src/share/classes/java/time/format/DateTimeFormatterBuilder.java | |
+++ b/src/share/classes/java/time/format/DateTimeFormatterBuilder.java | |
@@ -83,7 +83,6 @@ | |
import java.time.ZoneOffset; | |
import java.time.chrono.Chronology; | |
import java.time.chrono.IsoChronology; | |
-import java.time.chrono.JapaneseChronology; | |
import java.time.format.DateTimeTextProvider.LocaleStore; | |
import java.time.temporal.ChronoField; | |
import java.time.temporal.IsoFields; | |
@@ -1007,7 +1006,7 @@ | |
* is used, with {@code IsoChronology} as the fallback. | |
* <p> | |
* Note that this method provides similar functionality to methods on | |
- * {@code DateFormat} such as {@link DateFormat#getDateTimeInstance(int, int)}. | |
+ * {@code DateFormat} such as {@link java.text.DateFormat#getDateTimeInstance(int, int)}. | |
* | |
* @param dateStyle the date style to use, null means no date required | |
* @param timeStyle the time style to use, null means no time required | |
@@ -1105,7 +1104,8 @@ | |
* Symbol Meaning Presentation Examples | |
* ------ ------- ------------ ------- | |
* G era text A; AD; Anno Domini | |
- * y year year 2004; 04 | |
+ * u year year 2004; 04 | |
+ * y year-of-era year 2004; 04 | |
* D day-of-year number 189 | |
* M month-of-year number/text 7; 07; Jul; July; J | |
* d day-of-month number 10 | |
@@ -1381,6 +1381,7 @@ | |
private void parseField(char cur, int count, TemporalField field) { | |
switch (cur) { | |
+ case 'u': | |
case 'y': | |
case 'Y': | |
if (count == 2) { | |
@@ -1450,9 +1451,8 @@ | |
static { | |
// SDF = SimpleDateFormat | |
FIELD_MAP.put('G', ChronoField.ERA); // SDF, LDML (different to both for 1/2 chars) | |
- FIELD_MAP.put('y', ChronoField.YEAR); // LDML | |
- // FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA); // SDF, LDML // TODO redefine from above | |
- // FIELD_MAP.put('u', ChronoField.YEAR); // LDML (different in SDF) // TODO | |
+ FIELD_MAP.put('y', ChronoField.YEAR_OF_ERA); // SDF, LDML | |
+ FIELD_MAP.put('u', ChronoField.YEAR); // LDML (different in SDF) | |
// FIELD_MAP.put('Y', IsoFields.WEEK_BASED_YEAR); // SDF7, LDML (needs localized week number) // TODO | |
FIELD_MAP.put('Q', IsoFields.QUARTER_OF_YEAR); // LDML (removed quarter from 310) | |
FIELD_MAP.put('M', ChronoField.MONTH_OF_YEAR); // SDF, LDML | |
@@ -2105,12 +2105,7 @@ | |
@Override | |
public boolean format(DateTimePrintContext context, StringBuilder buf) { | |
Chronology chrono = context.getTemporal().query(Queries.chronology()); | |
- Long valueLong; | |
- if (chrono == JapaneseChronology.INSTANCE && field == ChronoField.YEAR) { | |
- valueLong = context.getValue(ChronoField.YEAR_OF_ERA); | |
- } else { | |
- valueLong = context.getValue(field); | |
- } | |
+ Long valueLong = context.getValue(field); | |
if (valueLong == null) { | |
return false; | |
} | |
@@ -2281,14 +2276,7 @@ | |
* @return the new position | |
*/ | |
int setValue(DateTimeParseContext context, long value, int errorPos, int successPos) { | |
- TemporalField f = field; | |
- if (field == ChronoField.YEAR) { | |
- Chronology chrono = context.getEffectiveChronology(); | |
- if (chrono == JapaneseChronology.INSTANCE) { | |
- f = ChronoField.YEAR_OF_ERA; | |
- } | |
- } | |
- return context.setParsedField(f, value, errorPos, successPos); | |
+ return context.setParsedField(field, value, errorPos, successPos); | |
} | |
@Override | |
diff --git a/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java b/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java | |
--- a/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java | |
+++ b/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java | |
@@ -61,6 +61,7 @@ | |
import static java.time.temporal.ChronoField.MONTH_OF_YEAR; | |
import static java.time.temporal.ChronoField.YEAR; | |
+import static java.time.temporal.ChronoField.YEAR_OF_ERA; | |
import static org.testng.Assert.assertEquals; | |
import java.text.ParsePosition; | |
@@ -153,7 +154,7 @@ | |
assertEquals(ppos.getErrorIndex(), expectedPos); | |
} else { | |
assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position"); | |
- assertEquals(parsed.isSupported(YEAR), true); | |
+ assertEquals(parsed.isSupported(YEAR_OF_ERA), true); | |
assertEquals(parsed.isSupported(WeekFields.of(locale).dayOfWeek()), true); | |
assertEquals(parsed.isSupported(WeekFields.of(locale).weekOfMonth()) || | |
parsed.isSupported(WeekFields.of(locale).weekOfYear()), true); | |
diff --git a/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java b/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java | |
--- a/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java | |
+++ b/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java | |
@@ -645,11 +645,17 @@ | |
{"GGGG", "Text(Era)"}, | |
{"GGGGG", "Text(Era,NARROW)"}, | |
- {"y", "Value(Year)"}, | |
- {"yy", "ReducedValue(Year,2,2000)"}, | |
- {"yyy", "Value(Year,3,19,NORMAL)"}, | |
- {"yyyy", "Value(Year,4,19,EXCEEDS_PAD)"}, | |
- {"yyyyy", "Value(Year,5,19,EXCEEDS_PAD)"}, | |
+ {"u", "Value(Year)"}, | |
+ {"uu", "ReducedValue(Year,2,2000)"}, | |
+ {"uuu", "Value(Year,3,19,NORMAL)"}, | |
+ {"uuuu", "Value(Year,4,19,EXCEEDS_PAD)"}, | |
+ {"uuuuu", "Value(Year,5,19,EXCEEDS_PAD)"}, | |
+ | |
+ {"y", "Value(YearOfEra)"}, | |
+ {"yy", "ReducedValue(YearOfEra,2,2000)"}, | |
+ {"yyy", "Value(YearOfEra,3,19,NORMAL)"}, | |
+ {"yyyy", "Value(YearOfEra,4,19,EXCEEDS_PAD)"}, | |
+ {"yyyyy", "Value(YearOfEra,5,19,EXCEEDS_PAD)"}, | |
// {"Y", "Value(WeekBasedYear)"}, | |
// {"YY", "ReducedValue(WeekBasedYear,2,2000)"}, | |
@@ -760,11 +766,11 @@ | |
{"ppH", "Pad(Value(HourOfDay),2)"}, | |
{"pppDD", "Pad(Value(DayOfYear,2),3)"}, | |
- {"yyyy[-MM[-dd", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, | |
- {"yyyy[-MM[-dd]]", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, | |
- {"yyyy[-MM[]-dd]", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)]"}, | |
+ {"yyyy[-MM[-dd", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, | |
+ {"yyyy[-MM[-dd]]", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, | |
+ {"yyyy[-MM[]-dd]", "Value(YearOfEra,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)]"}, | |
- {"yyyy-MM-dd'T'HH:mm:ss.SSS", "Value(Year,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)" + | |
+ {"yyyy-MM-dd'T'HH:mm:ss.SSS", "Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)" + | |
"'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)'.'Fraction(NanoOfSecond,3,3)"}, | |
{"e", "WeekBased(e1)"}, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment