ADDITIONAL SYSTEM INFORMATION :
Tested on
JDK1.8.0_181 on Windows 10
Java 11.0.3-ojdkbuild on Ubuntu Windows Subsystem for Linux
A DESCRIPTION OF THE PROBLEM :
When parsing using a DateTimeFormmatterBuilder and including both CLOCK_HOUR_OF_AMPM or HOUR_OF_AMPM and providing a date outside of their respective ranges, the parser will fail to throw an exception. According to the spec, both of these should throw a parse exception when the input is out of bounds.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Parse "2007-10-22 12:00 PM" with HOUR_OF_AMPM
2. Parse "2007-10-22 12:00 PM" with CLOCK_HOUR_OF_AMPM
1. Parse "2007-10-22 00:00 PM" with HOUR_OF_AMPM
2. Parse "2007-10-22 00:00 PM" with CLOCK_HOUR_OF_AMPM
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
1. DateTimeParseException
2. Noon
3. Noon
4. DateTimeParseException
ACTUAL -
1. Midnight of the Next Day
2. Noon
3. Noon
4. Noon
---------- BEGIN SOURCE ----------
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Expected DateTimeParse Error - Got Midnight of Next Day
String input = "2007-10-22 12:00 PM";
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder()
.parseStrict()
.appendValue(ChronoField.YEAR_OF_ERA)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH)
.appendLiteral(' ')
.appendValue(ChronoField.HOUR_OF_AMPM,2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR,2)
.appendLiteral(' ')
.appendText(ChronoField.AMPM_OF_DAY);
DateTimeFormatter formatter = builder.toFormatter(Locale.US);
TemporalAccessor accessor = formatter.parse(input);
LocalDateTime localDateTime = LocalDateTime.from(accessor);
System.out.println(localDateTime.toString());
// Expected Noon - Got Noon
input = "2007-10-22 12:00 PM";
builder = new DateTimeFormatterBuilder()
.parseStrict()
.appendValue(ChronoField.YEAR_OF_ERA)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH)
.appendLiteral(' ')
.appendValue(ChronoField.CLOCK_HOUR_OF_AMPM,2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR,2)
.appendLiteral(' ')
.appendText(ChronoField.AMPM_OF_DAY);
formatter = builder.toFormatter(Locale.US);
accessor = formatter.parse(input);
localDateTime = LocalDateTime.from(accessor);
System.out.println(localDateTime.toString());
// Expected Noon - Got Noon
input = "2007-10-22 00:00 PM";
builder = new DateTimeFormatterBuilder()
.parseStrict()
.appendValue(ChronoField.YEAR_OF_ERA)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH)
.appendLiteral(' ')
.appendValue(ChronoField.HOUR_OF_AMPM)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR)
.appendLiteral(' ')
.appendText(ChronoField.AMPM_OF_DAY);
formatter = builder.toFormatter(Locale.US);
accessor = formatter.parse(input);
localDateTime = LocalDateTime.from(accessor);
System.out.println(localDateTime.toString());
// Expected DateTimeParse Error - Got Noon
input = "2007-10-22 00:00 PM";
builder = new DateTimeFormatterBuilder()
.parseStrict()
.appendValue(ChronoField.YEAR_OF_ERA)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH)
.appendLiteral(' ')
.appendValue(ChronoField.CLOCK_HOUR_OF_AMPM)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR)
.appendLiteral(' ')
.appendText(ChronoField.AMPM_OF_DAY);
formatter = builder.toFormatter(Locale.US);
accessor = formatter.parse(input);
localDateTime = LocalDateTime.from(accessor);
System.out.println(localDateTime.toString());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use HOUR_OF_AMPM in place of both HOUR_OF_AMPM and CLOCK_HOUR_OF_AMPM for parsing.
FREQUENCY : always