I have a set of date strings currently in the format "dd-MM-yyyy" and I need to transform them into "yyyy/MM/dd" for a database migration. I am looking for a modern approach that doesn't involve the old, thread-unsafe SimpleDateFormat. How can I use the java.time package to parse the original string and then reformat it without running into common parsing exceptions?
3 answers
The most reliable way to do this in modern Java is using the DateTimeFormatter class from the java.time package. First, you define a formatter that matches your input pattern, then parse the string into a LocalDate object. After that, you create a second formatter for your desired output pattern and format the date object back into a string. Unlike the old SimpleDateFormat, DateTimeFormatter is immutable and thread-safe, making it ideal for multi-threaded applications or high-concurrency web servers. This approach also provides much better error messaging if the input string doesn't match the expected pattern, which helps a lot during the debugging process of large data migrations.
This approach works great for standard dates, but what if the input string contains an unexpected time component or an offset? Would I need to use LocalDateTime instead of LocalDate to avoid a DateTimeParseException?
You can achieve this in two lines: LocalDate date = LocalDate.parse(input, inputFormatter); followed by String output = date.format(outputFormatter);. It’s clean and very readable.
I agree with Barbara. Since I switched to the java.time API, I've had significantly fewer production bugs related to date parsing, especially when dealing with different time zones and leap years.
You hit the nail on the head, Matthew. If your string has a time element like "15-05-2024 10:30", LocalDate will throw an error because it can't find the time fields. In that case, you should parse it with LocalDateTime.parse(str, inputFormatter). If you only care about the date for the final output, you can then call .toLocalDate() on that object before formatting it back to your target string. This ensures your code is robust enough to handle varying levels of detail in your source data.