I'm trying to parse the String FEBRUARY 2019
into a LocalDate
.
This is my approach:
LocalDate month = LocalDate.parse("FEBRUARY 2019", DateTimeFormatter.ofPattern("MMMM yyyy"));
Or alternatively setting the Locale.US
:
LocalDate month = LocalDate.parse("FEBRUARY 2019", DateTimeFormatter.ofPattern("MMMM yyyy", Locale.US));
But all I get is the following exception:
Exception in thread "main" java.time.format.DateTimeParseException: Text 'FEBRUARY 2019' could not be parsed at index 0
Firstly, I'd suggest that the input you've got isn't a date - it's a year and month. So parse to a YearMonth
, and then create a LocalDate
from that however you want. I find it simplest to make text handling code only deal with text handling, and perform any other conversions separately when you're in the date/time domain already.
To handle the case sensitivity issue, you can create a DateTimeFormatter
with case-insensitive parsing. Here's a complete example of that:
import java.time.*;
import java.time.format.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
// Note: this would probably be a field somewhere so you don't need
// to build it every time.
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("MMMM yyyy")
.toFormatter(Locale.US);
YearMonth month = YearMonth.parse("FEBRUARY 2019", formatter);
System.out.println(month);
}
}
As an alternative approach which could be of use if you have a different representation, you could build a map and pass that to DateTimeFormatterBuilder.appendText
. (I only found this when somehow bungling the code about.)
import java.time.*;
import java.time.format.*;
import java.time.temporal.*;
import java.util.*;
public class Test {
public static void main(String[] args) {
// TODO: Build this map up programmatically instead?
Map<Long, String> monthNames = new HashMap<>();
monthNames.put(1L, "JANUARY");
monthNames.put(2L, "FEBRUARY");
monthNames.put(3L, "MARCH");
monthNames.put(4L, "APRIL");
monthNames.put(5L, "MAY");
monthNames.put(6L, "JUNE");
monthNames.put(7L, "JULY");
monthNames.put(8L, "AUGUST");
monthNames.put(9L, "SEPTEMBER");
monthNames.put(10L, "OCTOBER");
monthNames.put(11L, "NOVEMBER");
monthNames.put(12L, "DECEMBER");
// Note: this would probably be a field somewhere so you don't need
// to build it every time.
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendText(ChronoField.MONTH_OF_YEAR, monthNames)
.appendLiteral(' ')
.appendPattern("yyyy")
.toFormatter(Locale.US);
YearMonth month = YearMonth.parse("FEBRUARY 2019", formatter);
System.out.println(month);
}
}
As Jon Skeet stated, you don't have a complete date to parse and can use YearMonth. An alternative is to specify a default day.
Instead of the approach to provide a map of months names, you could also simply use a library such as WordUtils to convert your input into the correct format, e.g. as such:
final LocalDate month = LocalDate.parse(
org.apache.commons.text.WordUtils.capitalizeFully("FEBRUARY 2019"),
new DateTimeFormatterBuilder()
.appendPattern("MMMM uuuu")
.parseCaseInsensitive()
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
.toFormatter(Locale.US));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With