Skip to content

Instantly share code, notes, and snippets.

@jodastephen
Created February 19, 2013 16:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jodastephen/4987319 to your computer and use it in GitHub Desktop.
Save jodastephen/4987319 to your computer and use it in GitHub Desktop.
APPLIED: yyyy/uuuu change. Patch for #138
# 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);
}
# 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
# 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);
}
}
# 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