Skip to Content
Course content

177: Formatting and Parsing Dates

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've seen this bug more times than I can count, usually in a frantic Slack message from a junior dev at 4:00 PM on a Friday. They're trying to parse a date from a CSV file, and for some reason, every single record is coming back as January, regardless of what the actual month is. Here is the kind of code that causes it:

String dateString = "25-12-2023";
SimpleDateFormat sdf = new SimpleDateFormat("dd-mm-yyyy");
Date date = sdf.parse(dateString);
System.out.println(date); 
// Output: Mon Jan 25 00:45:00 EST 2023 (Wait, why January? And why 45 minutes?)

The Case of the Vanishing Month

If you look closely at the pattern string "dd-mm-yyyy", you'll see the culprit: mm. In the world of Java date formatting, case sensitivity is everything. Lowercase m represents minutes, while uppercase M represents months.

Because the input was "12", Java didn't see December; it saw 12 minutes past the hour. Since no month was specified in the pattern, it defaulted to January. It's a tiny typo that creates a massive headache. I always tell people: if your dates look "weird" but aren't throwing an exception, check your capitalization first.

Switching to the Modern java.time API

While SimpleDateFormat is still around, you should almost never use it in a modern project. It's not thread-safe, which means if you use it as a static variable in a web server, you'll eventually get random, inexplicable date corruption. Instead, we use DateTimeFormatter from the java.time package.

Here is how we fix that bug and modernize the code at the same time:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

String dateString = "25-12-2023";
// Use uppercase M for Month!
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
LocalDate date = LocalDate.parse(dateString, formatter);

System.out.println(date); // Output: 2023-12-25

Notice that LocalDate doesn't include time. If you need the time of day, you'd use LocalDateTime. The beauty of the new API is that it's immutable and thread-safe. You can define your formatter as a static final constant and reuse it everywhere without worrying about your app crashing under load.

Formatting vs. Parsing

It's easy to get these two terms swapped, but think of them as opposites:

  • Parsing: Taking a String (like "2023-12-25") and turning it into a date object the computer can actually understand and do math with.
  • Formatting: Taking a date object and turning it into a String so a human can read it (like "December 25th, 2023").

To format a date, you just call the format() method on your formatter object:

LocalDate today = LocalDate.now();
DateTimeFormatter prettyFormatter = DateTimeFormatter.ofPattern("EEEE, MMMM dd, yyyy");
String formattedDate = today.format(prettyFormatter);

System.out.println(formattedDate); // Output: Monday, October 14, 2024 (depending on today's date)

Handling Bad Input Without Crashing

In the real world, users provide terrible data. If you try to parse "31-02-2023" (February 31st), Java will throw a DateTimeParseException. If you don't catch this, your whole application crashes. I recommend wrapping your parsing logic in a try-catch block, especially when dealing with external API responses or user forms.

try {
    LocalDate date = LocalDate.parse(userInput, formatter);
} catch (DateTimeParseException e) {
    System.err.println("That's not a valid date! Please use the format dd-MM-yyyy.");
}



📋 Practical Task

Exercise: Building a Transaction Date Normalizer

In financial systems, you often receive data from different banks, and each bank uses a different date format. Your task is to create a "Normalizer" utility that converts various date strings into a standard ISO format (YYYY-MM-DD).

Requirements:

  • Create a class called DateNormalizer.
  • Implement a method public String normalize(String dateStr).
  • The method should be able to handle three different input formats:
    1. "dd/MM/yyyy" (e.g., "15/05/2022")
    2. "MM-dd-yyyy" (e.g., "05-15-2022")
    3. "yyyy.MM.dd" (e.g., "2022.05.15")
  • If the date matches any of these formats, return it as a LocalDate formatted as "yyyy-MM-dd".
  • If the date doesn't match any of the known formats, return the string "INVALID_DATE".

Pro Tip: Try creating an array of DateTimeFormatter objects and looping through them to see which one parses the input successfully without throwing an exception.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.