There already exists question Java 8 DateTimeFormatter with optional part, but the answer for it won't work when optional part is only hours and minutes without seconds:
DateTimeFormatter patternWithOptional = new DateTimeFormatterBuilder()
    .appendPattern("M/d/yyyy[ h:mm]")
    .toFormatter();
TemporalAccessor tmp = patternWithOptional.parseBest("4/11/2020 1:20", LocalDateTime::from, LocalDate::from);
System.out.println(tmp);
System.out.println(tmp.getClass().getSimpleName());
// prints 2020-04-11, without time
// class is LocalDate in this case
This is because LocalDateTime.from(TemporalAccessor temporal) uses TemporalQueries.LOCAL_TIME to query the temporal.  TemporalQueries.LOCAL_TIME, in turn, requires ChronoField.NANO_OF_DAY to be available from temporal.
System.out.println(patternWithOptional.parse("4/11/2020 1:20"));
// prints:
{HourOfAmPm=1, MinuteOfHour=20},ISO resolved to 2020-04-11
Since HourOfAmPm and MinuteOfHour are available, the simplest way to achieve what I need, that I could come up with:
private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
    .appendPattern("M/d/yyyy[ h:mm]")
    .toFormatter();
public static void main(String[] args) {
    // demo
    System.out.println(parse("3/20/1995"));      // without time
    System.out.println(parse("4/11/2020 1:20")); // with time
}
private static LocalDateTime parse(String s) {
    TemporalAccessor parsed = FORMATTER.parse(s);
    return LocalDateTime.of(
        LocalDate.from(parsed),
        LocalTime.of(
            parsed.isSupported(ChronoField.HOUR_OF_AMPM)
                ? (int) ChronoField.HOUR_OF_AMPM.getFrom(parsed)
                : 0,
            parsed.isSupported(ChronoField.MINUTE_OF_HOUR)
                ? (int) ChronoField.MINUTE_OF_HOUR.getFrom(parsed)
                : 0
        ) // minor note: this part could also be used as a lambda argument for parseBest method.
    );
}
Is there a simpler way to do this without explicit isSupported checks?