/*
Compare two dates in Groovy
---------------------------
This program demonstrates how to compare two dates using Groovy's
built‑in java.time API. It uses a modular design, clear comments,
and a full test suite.
Concepts:
- Parsing dates safely
- Comparing LocalDate objects
- Handling invalid formats
- Edge‑case testing
Architecture notes:
- A dedicated function handles parsing.
- Another function performs comparison.
- Main runs multiple predefined test cases.
- No external dependencies; only standard library.
Performance notes:
- LocalDate comparisons are O(1).
- Parsing is fast and predictable.
- Memory usage is minimal.
Pitfalls:
- Invalid date strings must be handled.
- Comparing raw strings is unsafe; always convert to LocalDate.
- Timezones are not used here; LocalDate is date‑only.
*/
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException
/**
* Safely parse a date string into a LocalDate.
*
* Supported format: YYYY-MM-DD
*
* Error handling:
* - Returns null if the date is invalid.
*/
LocalDate parseDate(String dateStr) {
try {
return LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE)
} catch (DateTimeParseException ignored) {
return null
}
}
/**
* Compare two LocalDate objects.
*
* Returns:
* - "earlier"
* - "later"
* - "equal"
*/
String compareDates(LocalDate d1, LocalDate d2) {
if (d1 < d2) return "earlier"
if (d1 > d2) return "later"
return "equal"
}
/**
* Run a single test case:
* - Parse both dates
* - Handle invalid input
* - Compare if valid
*/
Map runTestCase(String date1, String date2) {
def d1 = parseDate(date1)
def d2 = parseDate(date2)
if (!d1 || !d2) {
return [date1: date1, date2: date2, result: "invalid date format"]
}
return [date1: date1, date2: date2, result: compareDates(d1, d2)]
}
/**
* Main test suite:
* - Multiple test cases
* - Includes edge cases
* - Prints results cleanly
*/
void main() {
def tests = [
["2024-01-01", "2024-01-02"], // earlier
["2024-01-02", "2024-01-01"], // later
["2024-01-01", "2024-01-01"], // equal
["1999-12-31", "2000-01-01"], // millennium boundary
["2024-02-29", "2024-03-01"], // leap year
["2024-02-29", "2023-02-28"], // leap vs non-leap
["2024-13-01", "2024-01-01"], // invalid month
["2024-00-10", "2024-01-01"], // invalid month
["2024-01-32", "2024-01-01"], // invalid day
["abcd-ef-gh", "2024-01-01"], // invalid format
["2024-01-01", "abcd-ef-gh"], // invalid format
]
println "Date comparison tests:\n"
tests.each { t ->
def result = runTestCase(t[0], t[1])
println "Compare '${result.date1}' vs '${result.date2}' → ${result.result}"
}
}
main()
/*
run:
Date comparison tests:
Compare '2024-01-01' vs '2024-01-02' → earlier
Compare '2024-01-02' vs '2024-01-01' → later
Compare '2024-01-01' vs '2024-01-01' → equal
Compare '1999-12-31' vs '2000-01-01' → earlier
Compare '2024-02-29' vs '2024-03-01' → earlier
Compare '2024-02-29' vs '2023-02-28' → later
Compare '2024-13-01' vs '2024-01-01' → invalid date format
Compare '2024-00-10' vs '2024-01-01' → invalid date format
Compare '2024-01-32' vs '2024-01-01' → invalid date format
Compare 'abcd-ef-gh' vs '2024-01-01' → invalid date format
Compare '2024-01-01' vs 'abcd-ef-gh' → invalid date format
*/