diff --git a/src/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/share/classes/java/time/format/DateTimeFormatterBuilder.java index 29792b8bf796704ddab942a67068b99fe67339d5..9b9d9637a6cd6f1cd5c073fd11c33fb936456bb2 100644 --- a/src/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -557,12 +557,13 @@ public final class DateTimeFormatterBuilder { * a two digit year parse will be in the range 1950-01-01 to 2049-12-31. * Only the year would be extracted from the date, thus a base date of * 1950-08-25 would also parse to the range 1950-01-01 to 2049-12-31. - * This behaviour is necessary to support fields such as week-based-year + * This behavior is necessary to support fields such as week-based-year * or other calendar systems where the parsed value does not align with * standard ISO years. *
* The exact behavior is as follows. Parse the full set of fields and
- * determine the effective chronology. Then convert the base date to the
+ * determine the effective chronology using the last chronology if
+ * it appears more than once. Then convert the base date to the
* effective chronology. Then extract the specified field from the
* chronology-specific base date and use it to determine the
* {@code baseValue} used below.
@@ -2809,9 +2810,19 @@ public final class DateTimeFormatterBuilder {
int setValue(DateTimeParseContext context, long value, int errorPos, int successPos) {
int baseValue = this.baseValue;
if (baseDate != null) {
- // TODO: effective chrono is inaccurate at this point
Chronology chrono = context.getEffectiveChronology();
baseValue = chrono.date(baseDate).get(field);
+
+ // In case the Chronology is changed later, add a callback when/if it changes
+ final long initialValue = value;
+ context.addChronoChangedListener(
+ (_unused) -> {
+ /* Repeat the set of the field using the current Chronology
+ * The success/error position is ignored because the value is
+ * intentionally being overwritten.
+ */
+ setValue(context, initialValue, errorPos, successPos);
+ });
}
int parseLen = successPos - errorPos;
if (parseLen == minWidth && value >= 0) {
diff --git a/src/share/classes/java/time/format/DateTimeParseContext.java b/src/share/classes/java/time/format/DateTimeParseContext.java
index f72ef7b77c9fe75e8d4bd937bb3208ebe4e4dbaa..3157747a6f712967af0342de098ce9be8e40720c 100644
--- a/src/share/classes/java/time/format/DateTimeParseContext.java
+++ b/src/share/classes/java/time/format/DateTimeParseContext.java
@@ -61,7 +61,6 @@
*/
package java.time.format;
-import java.time.Duration;
import java.time.ZoneId;
import java.time.chrono.Chronology;
import java.time.chrono.IsoChronology;
@@ -69,6 +68,7 @@ import java.time.temporal.TemporalField;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Objects;
+import java.util.function.Consumer;
/**
* Context object used during date and time parsing.
@@ -105,6 +105,10 @@ final class DateTimeParseContext {
* The list of parsed data.
*/
private final ArrayList
* This stores the chronology that has been parsed.
* No validation is performed other than ensuring it is not null.
+ *
+ * The list of listeners is copied and cleared so that each
+ * listener is called only once. A listener can add itself again
+ * if it needs to be notified of future changes.
*
* @param chrono the parsed chronology, not null
*/
void setParsed(Chronology chrono) {
Objects.requireNonNull(chrono, "chrono");
currentParsed().chrono = chrono;
+ if (chronoListeners != null && !chronoListeners.isEmpty()) {
+ Consumer[] tmp = new Consumer[1];
+ Consumer