kamil
kamil

Reputation: 3522

Is DateTimeFormatter more strict than SimpleDateFormat? Parsing date with milliseconds

I have simple test case:

public static void main(String[] args) {
  String pattern = "yyyy-MM-dd HH:mm:ss.SSS";
  String date = "2017-01-15 15:15:15.5";

  SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
  DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
  FastDateFormat fastDateFormat = FastDateFormat.getInstance(pattern);
  try {
    System.out.println("SFD: " + simpleDateFormat.parse(date));
  }catch (Exception e) {
    System.err.println("SDF failed");
  }
  try {
    System.out.println("DTF: " + dateTimeFormatter.parse(date));
  }catch (Exception e) {
    System.err.println("DTF failed");
  }
  try {
    System.out.println("FDF: " + fastDateFormat.parse(date));
  }catch (Exception e) {
    System.err.println("FDF failed");
  }
}

Output is like this:

SFD: Thu Jan 15 15:15:15 CET 1970
DTF failed
FDF: Thu Jan 15 15:15:15 CET 1970

According to the results, Java's 8 DateTimeFormatter is more strict then SimpleDateFormat. My question is why and in that case, what would be best approach to accept both dates with .S as millis or .SSS, like parsing multiple times with try/catch ?

Upvotes: 3

Views: 1452

Answers (2)

Stephen C
Stephen C

Reputation: 719436

You are basically asking why SimpleDateFormat accepts one digit millisecond values when the pattern says ".SSS".

The reason is in the javadoc for SimpleDateFormat:

Pattern letters are usually repeated, as their number determines the exact presentation:

...

Number: For formatting, the number of pattern letters is the minimum number of digits, and shorter numbers are zero-padded to this amount. For parsing, the number of pattern letters is ignored unless it's needed to separate two adjacent fields.

Apparently, you can change this by calling setLenient(false). However, the javadocs don't specify what the actual effect of leniency is.

By contrast, the javadoc for DateTimeFormatter simply says "the count of pattern letters determines the format", making no distinction between formatting and parsing.


Why are they different? You would need to ask the people who designed the DateTimeFormatter API, but I imagine it was that the designers considered the ad hoc and unspecified nature of SimpleDateFormat (default) lenient parsing mode to be harmful.


How do you simply get DateTimeFormatter to accept dates with one or 3 digits millisecond values?

One approach would be to create the formatter using a DateTimeFormatterBuilder. This allows you to specify a minimum and maximum width for any field in the format.

Upvotes: 2

René Link
René Link

Reputation: 51463

SimpleDateFormat's is not strict per default, because the property lenient is true per default. But you can set the property lenient to false to make it strict.

SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
simpleDateFormat.setLenient(false);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
try {
    System.out.println("SFD: " + simpleDateFormat.parse(date));
} catch (Exception e) {
    System.err.println("SDF failed");
}
try {
    System.out.println("DTF: " + dateTimeFormatter.parse(date));
} catch (Exception e) {
    System.err.println("DTF failed");
}

The result will be then

SDF failed
DTF failed

See DateFormat.parse(String, ParsePosition)

By default, parsing is lenient: If the input is not in the form used by this object's format method but can still be parsed as a date, then the parse succeeds. Clients may insist on strict adherence to the format by calling setLenient(false).

Upvotes: 4

Related Questions