Start learning free

LESSON 165 OF 173 · BACKEND: BACKEND WITH AI

Dates the AI Got Wrong in Java

Practice

An AI assistant wrote GET /orders?since=… for the shop: the orders placed on or after a date. Customers type the date day first, like 18/04/2026. The database keeps each order's date year first, like 2026-04-18. The AI compared the two texts as they are:

@GetMapping("/orders")
Object ordersSince(@RequestParam(defaultValue = "") String since) {
    List<Map<String, Object>> rows = db.queryForList("SELECT * FROM orders");
    List<Map<String, Object>> result = new ArrayList<>();
    for (Map<String, Object> row : rows) {
        String ordered = (String) row.get("ordered");
        if (ordered.compareTo(since) >= 0) {
            result.add(row);
        }
    }
    return result;
}

compareTo compares strings character by character, and the first difference decides. "2026-03-02".compareTo("18/04/2026") is positive, because "2" comes after "1". So since=18/04/2026 answered all 7 orders and since=30/04/2026 answered none. The impossible 31/04/2026 got 200 and an empty list, and a request without since compared every date with "" and answered all 7.

The fix: turn each text into a real date with LocalDate.parse(text, formatter), then compare dates. The formatter DAY_MONTH_YEAR, already at the top of the class, uses the pattern "dd/MM/uuuu": dd is the day, MM the month (lowercase mm would be minutes) and uuuu the four-digit year. It reads strictly, so a text that doesn't fit, or a day that doesn't exist, throws a DateTimeParseException. A year-month-day text like 2026-04-18 needs no formatter at all:

LocalDate d = LocalDate.parse("07/05/2026", DAY_MONTH_YEAR);
System.out.println(d.getDayOfMonth() + " " + d.getMonthValue() + " " + d.getYear());   // 7 5 2026
LocalDate june = LocalDate.parse("2026-06-01");     // year-month-day: no formatter needed
System.out.println(d.isBefore(june));                // true
LocalDate.parse("30/02/2026", DAY_MONTH_YEAR);       // DateTimeParseException: there is no 30 February

The requests and the answers your route must give:

GET /orders?since=18/04/2026  →  200  [{"customer_id": 3, "id": 4, "ordered": "2026-04-18", "status": "shipped"}, …]   (orders 4 to 7)
GET /orders?since=30/04/2026  →  200  [{"customer_id": 4, "id": 5, "ordered": "2026-05-07", "status": "paid"}, …]   (orders 5 to 7)
GET /orders?since=01/06/2026  →  200  []
GET /orders?since=31/04/2026  →  400  {"error": "since must be a date like 18/04/2026"}
GET /orders  →  400  {"error": "since must be a date like 18/04/2026"}

Your task: rewrite ordersSince. Read since as a date with DAY_MONTH_YEAR, and answer 400 with the error when it isn't one. Read each order's ordered as a date, and answer the orders placed on or after since.


Assignment
Follow the Coding Tutorial to rewrite ordersSince so it compares real dates instead of texts.


Hint
Put LocalDate.parse inside try and catch DateTimeParseException; declare sinceDate above the try so the code below it can use the date. A missing since arrives as "" and lands in the same catch. Keep an order when it is not before sinceDate, so an order placed on that day itself is kept. Without the strict reading, Java would quietly turn 31/04/2026 into 30 April.


STEP 1 OF 12
    Ctrl + Enter to check

    Ai Timezone in Java

    Keep going with Java1,600+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free