To parse the time, you can do as explained in @Jon Skeet's answer:
String input = "5:45 PM";
DateTimeFormatter parser = DateTimeFormatter.ofPattern("h:mm a", Locale.ENGLISH);
LocalTime time = LocalTime.parse(input, parser);
Note that I also used a java.util.Locale
because if you don't specify it, it'll use the system's default locale - and some locales can use different symbols for AM/PM field. Using an explicit locale avoids this corner-case (and the default locale can also be changed, even at runtime, so it's better to use an explicit one).
To combine with the today's date, you'll need a java.time.LocalDate
(to get the date) and combine with the LocalTime
, to get a LocalDateTime
:
// combine with today's date
LocalDateTime combined = LocalDate.now().atTime(time);
Then you can format the LocalDateTime
using another formatter:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
System.out.println(combined.format(fmt));
The output is:
16/08/2017 17:45
If you want to convert the LocalDateTime
to a java.util.Date
, you must take care of some details.
A java.util.Date
represents the number of milliseconds since 1970-01-01T00:00Z
(aka Unix Epoch). It's an instant (a specific point in time). Check this article for more info.
So, the same Date
object can represent different dates or times, depending on where you are: think that, right now, at this moment, everybody in the world are in the same instant (the same number of milliseconds since 1970-01-01T00:00Z
), but the local date and time is different in each part of the world.
A LocalDateTime
represents this concept of "local": it's a date (day, month and year) and a time (hour, minute, second and nanosecond), but without any relation to a specific timezone.
The same LocalDateTime
object can represent different instants in time in different timezones. So, to convert it to a Date
, you must define in what timezone you want it.
One option is to use the system's default timezone:
// convert to system's default timezone
ZonedDateTime atDefaultTimezone = combined.atZone(ZoneId.systemDefault());
// convert to java.util.Date
Date date = Date.from(atDefaultTimezone.toInstant());
But the default can vary from system/environment, and can also be changed, even at runtime. To not depend on that and have more control over it, you can use an explicit zone:
// convert to a specific timezone
ZonedDateTime zdt = combined.atZone(ZoneId.of("Europe/London"));
// convert to java.util.Date
Date date = Date.from(zdt.toInstant());
Note that I used Europe/London
. The API uses IANA timezones names (always in the format Region/City
, like America/Sao_Paulo
or Europe/Berlin
).
Avoid using the 3-letter abbreviations (like CST
or PST
) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds()
.
And there's also the corner cases of Daylight Saving Time (when a LocalDateTime
can exist twice or can't exist due to overlaps and gaps). In this case, Jon's solution using ZonedDateTime
avoids this problem).