8145633: Adjacent value parsing not supported for Localized Patterns
Enhance the localized weekfields to take part in adjacent value parsing Reviewed-by: rriggs, scolebourne
This commit is contained in:
parent
f986518c51
commit
8f9235fc56
@ -1774,16 +1774,20 @@ public final class DateTimeFormatterBuilder {
|
||||
if (count > 1) {
|
||||
throw new IllegalArgumentException("Too many pattern letters: " + cur);
|
||||
}
|
||||
appendInternal(new WeekBasedFieldPrinterParser(cur, count));
|
||||
appendValue(new WeekBasedFieldPrinterParser(cur, count, count, count));
|
||||
} else if (cur == 'w') {
|
||||
// Fields defined by Locale
|
||||
if (count > 2) {
|
||||
throw new IllegalArgumentException("Too many pattern letters: " + cur);
|
||||
}
|
||||
appendInternal(new WeekBasedFieldPrinterParser(cur, count));
|
||||
appendValue(new WeekBasedFieldPrinterParser(cur, count, count, 2));
|
||||
} else if (cur == 'Y') {
|
||||
// Fields defined by Locale
|
||||
appendInternal(new WeekBasedFieldPrinterParser(cur, count));
|
||||
if (count == 2) {
|
||||
appendValue(new WeekBasedFieldPrinterParser(cur, count, count, 2));
|
||||
} else {
|
||||
appendValue(new WeekBasedFieldPrinterParser(cur, count, count, 19));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown pattern letter: " + cur);
|
||||
}
|
||||
@ -1843,7 +1847,10 @@ public final class DateTimeFormatterBuilder {
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (count == 2) {
|
||||
if (count == 1) {
|
||||
appendValue(new WeekBasedFieldPrinterParser(cur, count, count, count));
|
||||
break;
|
||||
} else if (count == 2) {
|
||||
throw new IllegalArgumentException("Invalid pattern \"cc\"");
|
||||
}
|
||||
/*fallthrough*/
|
||||
@ -1858,8 +1865,8 @@ public final class DateTimeFormatterBuilder {
|
||||
switch (count) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (cur == 'c' || cur == 'e') {
|
||||
appendInternal(new WeekBasedFieldPrinterParser(cur, count));
|
||||
if (cur == 'e') {
|
||||
appendValue(new WeekBasedFieldPrinterParser(cur, count, count, count));
|
||||
} else if (cur == 'E') {
|
||||
appendText(field, TextStyle.SHORT);
|
||||
} else {
|
||||
@ -4770,8 +4777,9 @@ public final class DateTimeFormatterBuilder {
|
||||
* the field is to be printed or parsed.
|
||||
* The locale is needed to select the proper WeekFields from which
|
||||
* the field for day-of-week, week-of-month, or week-of-year is selected.
|
||||
* Hence the inherited field NumberPrinterParser.field is unused.
|
||||
*/
|
||||
static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser {
|
||||
static final class WeekBasedFieldPrinterParser extends NumberPrinterParser {
|
||||
private char chr;
|
||||
private int count;
|
||||
|
||||
@ -4780,12 +4788,55 @@ public final class DateTimeFormatterBuilder {
|
||||
*
|
||||
* @param chr the pattern format letter that added this PrinterParser.
|
||||
* @param count the repeat count of the format letter
|
||||
* @param minWidth the minimum field width, from 1 to 19
|
||||
* @param maxWidth the maximum field width, from minWidth to 19
|
||||
*/
|
||||
WeekBasedFieldPrinterParser(char chr, int count) {
|
||||
WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth) {
|
||||
this(chr, count, minWidth, maxWidth, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param chr the pattern format letter that added this PrinterParser.
|
||||
* @param count the repeat count of the format letter
|
||||
* @param minWidth the minimum field width, from 1 to 19
|
||||
* @param maxWidth the maximum field width, from minWidth to 19
|
||||
* @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater,
|
||||
* -1 if fixed width due to active adjacent parsing
|
||||
*/
|
||||
WeekBasedFieldPrinterParser(char chr, int count, int minWidth, int maxWidth,
|
||||
int subsequentWidth) {
|
||||
super(null, minWidth, maxWidth, SignStyle.NOT_NEGATIVE, subsequentWidth);
|
||||
this.chr = chr;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance with fixed width flag set.
|
||||
*
|
||||
* @return a new updated printer-parser, not null
|
||||
*/
|
||||
@Override
|
||||
WeekBasedFieldPrinterParser withFixedWidth() {
|
||||
if (subsequentWidth == -1) {
|
||||
return this;
|
||||
}
|
||||
return new WeekBasedFieldPrinterParser(chr, count, minWidth, maxWidth, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance with an updated subsequent width.
|
||||
*
|
||||
* @param subsequentWidth the width of subsequent non-negative numbers, 0 or greater
|
||||
* @return a new updated printer-parser, not null
|
||||
*/
|
||||
@Override
|
||||
WeekBasedFieldPrinterParser withSubsequentWidth(int subsequentWidth) {
|
||||
return new WeekBasedFieldPrinterParser(chr, count, minWidth, maxWidth,
|
||||
this.subsequentWidth + subsequentWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean format(DateTimePrintContext context, StringBuilder buf) {
|
||||
return printerParser(context.getLocale()).format(context, buf);
|
||||
@ -4810,10 +4861,12 @@ public final class DateTimeFormatterBuilder {
|
||||
case 'Y':
|
||||
field = weekDef.weekBasedYear();
|
||||
if (count == 2) {
|
||||
return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE, 0);
|
||||
return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE,
|
||||
this.subsequentWidth);
|
||||
} else {
|
||||
return new NumberPrinterParser(field, count, 19,
|
||||
(count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, -1);
|
||||
(count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD,
|
||||
this.subsequentWidth);
|
||||
}
|
||||
case 'e':
|
||||
case 'c':
|
||||
@ -4828,7 +4881,8 @@ public final class DateTimeFormatterBuilder {
|
||||
default:
|
||||
throw new IllegalStateException("unreachable");
|
||||
}
|
||||
return new NumberPrinterParser(field, (count == 2 ? 2 : 1), 2, SignStyle.NOT_NEGATIVE);
|
||||
return new NumberPrinterParser(field, minWidth, maxWidth, SignStyle.NOT_NEGATIVE,
|
||||
this.subsequentWidth);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -66,9 +66,11 @@ import java.text.ParsePosition;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.time.temporal.TemporalField;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
@ -79,12 +81,17 @@ import test.java.time.format.AbstractTestPrinterParser;
|
||||
*/
|
||||
@Test
|
||||
public class TCKLocalizedFieldParser extends AbstractTestPrinterParser {
|
||||
|
||||
public static final WeekFields WEEKDEF = WeekFields.of(Locale.US);
|
||||
public static final TemporalField WEEK_BASED_YEAR = WEEKDEF.weekBasedYear();
|
||||
public static final TemporalField WEEK_OF_WEEK_BASED_YEAR = WEEKDEF.weekOfWeekBasedYear();
|
||||
public static final TemporalField DAY_OF_WEEK = WEEKDEF.dayOfWeek();
|
||||
//-----------------------------------------------------------------------
|
||||
@DataProvider(name="FieldPatterns")
|
||||
Object[][] provider_fieldPatterns() {
|
||||
return new Object[][] {
|
||||
{"e", "6", 0, 1, 6},
|
||||
{"e", "6", 0, 1, 6},
|
||||
{"ee", "06", 0, 2, 6},
|
||||
{"c", "6", 0, 1 , 6},
|
||||
{"W", "3", 0, 1, 3},
|
||||
{"w", "29", 0, 2, 29},
|
||||
{"ww", "29", 0, 2, 29},
|
||||
@ -99,6 +106,7 @@ public class TCKLocalizedFieldParser extends AbstractTestPrinterParser {
|
||||
WeekFields weekDef = WeekFields.of(locale);
|
||||
TemporalField field = null;
|
||||
switch(pattern.charAt(0)) {
|
||||
case 'c' :
|
||||
case 'e' :
|
||||
field = weekDef.dayOfWeek();
|
||||
break;
|
||||
@ -176,9 +184,9 @@ public class TCKLocalizedFieldParser extends AbstractTestPrinterParser {
|
||||
{"Y-w-e", "2008-01-1", 0, 9, LocalDate.of(2007, 12, 30)},
|
||||
{"Y-w-e", "2008-52-1", 0, 9, LocalDate.of(2008, 12, 21)},
|
||||
{"Y-w-e", "2008-52-7", 0, 9, LocalDate.of(2008, 12, 27)},
|
||||
{"Y-w-e", "2009-01-01", 0, 10, LocalDate.of(2008, 12, 28)},
|
||||
{"Y-w-e", "2009-01-04", 0, 10, LocalDate.of(2008, 12, 31)},
|
||||
{"Y-w-e", "2009-01-05", 0, 10, LocalDate.of(2009, 1, 1)},
|
||||
{"Y-w-e", "2009-01-1", 0, 9, LocalDate.of(2008, 12, 28)},
|
||||
{"Y-w-e", "2009-01-4", 0, 9, LocalDate.of(2008, 12, 31)},
|
||||
{"Y-w-e", "2009-01-5", 0, 9, LocalDate.of(2009, 1, 1)},
|
||||
};
|
||||
}
|
||||
|
||||
@ -202,4 +210,77 @@ public class TCKLocalizedFieldParser extends AbstractTestPrinterParser {
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@DataProvider(name = "adjacentValuePatterns1")
|
||||
Object[][] provider_adjacentValuePatterns1() {
|
||||
return new Object[][] {
|
||||
{"YYww", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, "1612", 2016, 12},
|
||||
{"YYYYww", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, "201612", 2016, 12},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "adjacentValuePatterns1")
|
||||
public void test_adjacentValuePatterns1(String pattern, TemporalField field1, TemporalField field2,
|
||||
String text, int expected1, int expected2) {
|
||||
DateTimeFormatter df = new DateTimeFormatterBuilder()
|
||||
.appendPattern(pattern).toFormatter(Locale.US);
|
||||
ParsePosition ppos = new ParsePosition(0);
|
||||
TemporalAccessor parsed = df.parseUnresolved(text, ppos);
|
||||
assertEquals(parsed.get(field1), expected1);
|
||||
assertEquals(parsed.get(field2), expected2);
|
||||
}
|
||||
|
||||
@DataProvider(name = "adjacentValuePatterns2")
|
||||
Object[][] provider_adjacentValuePatterns2() {
|
||||
return new Object[][] {
|
||||
{"YYYYwwc", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK,
|
||||
"2016121", 2016, 12, 1},
|
||||
{"YYYYwwee", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK,
|
||||
"20161201", 2016, 12, 1},
|
||||
{"YYYYwwe", WEEK_BASED_YEAR, WEEK_OF_WEEK_BASED_YEAR, DAY_OF_WEEK,
|
||||
"2016121", 2016, 12, 1},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "adjacentValuePatterns2")
|
||||
public void test_adjacentValuePatterns2(String pattern, TemporalField field1, TemporalField field2,
|
||||
TemporalField field3, String text, int expected1, int expected2, int expected3) {
|
||||
DateTimeFormatter df = new DateTimeFormatterBuilder()
|
||||
.appendPattern(pattern).toFormatter(Locale.US);
|
||||
ParsePosition ppos = new ParsePosition(0);
|
||||
TemporalAccessor parsed = df.parseUnresolved(text, ppos);
|
||||
assertEquals(parsed.get(field1), expected1);
|
||||
assertEquals(parsed.get(field2), expected2);
|
||||
assertEquals(parsed.get(field3), expected3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_adjacentValuePatterns3() {
|
||||
String pattern = "yyyyMMddwwc";
|
||||
String text = "20120720296";
|
||||
DateTimeFormatter df = new DateTimeFormatterBuilder()
|
||||
.appendPattern(pattern).toFormatter(Locale.US);
|
||||
ParsePosition ppos = new ParsePosition(0);
|
||||
TemporalAccessor parsed = df.parseUnresolved(text, ppos);
|
||||
assertEquals(parsed.get(DAY_OF_WEEK), 6);
|
||||
assertEquals(parsed.get(WEEK_OF_WEEK_BASED_YEAR), 29);
|
||||
LocalDate result = LocalDate.parse(text, df);
|
||||
LocalDate expectedValue = LocalDate.of(2012, 07, 20);
|
||||
assertEquals(result, expectedValue, "LocalDate incorrect for " + pattern);
|
||||
}
|
||||
|
||||
@DataProvider(name = "invalidPatterns")
|
||||
Object[][] provider_invalidPatterns() {
|
||||
return new Object[][] {
|
||||
{"W", "01"},
|
||||
{"c", "01"},
|
||||
{"e", "01"},
|
||||
{"yyyyMMddwwc", "201207202906"}, // 1 extra digit in the input
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalidPatterns", expectedExceptions = DateTimeParseException.class)
|
||||
public void test_invalidPatterns(String pattern, String value) {
|
||||
DateTimeFormatter.ofPattern(pattern).parse(value);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user