import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeParseException
/*
Compare two dates in Scala
--------------------------
This program demonstrates how to compare two dates using Scala and the
built‑in java.time API. It uses a modular design, clear comments, and a full test suite.
Concepts:
- Parsing dates safely (YYYY‑MM‑DD)
- 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.
- LocalDate is date‑only; no timezone concerns here.
*/
/** Safely parse a date string in the format YYYY-MM-DD.
* Returns None if the date is invalid.
*/
def parseDate(s: String): Option[LocalDate] = {
try {
Some(LocalDate.parse(s, DateTimeFormatter.ISO_LOCAL_DATE))
} catch {
case _: DateTimeParseException => None
}
}
/** Compare two LocalDate objects.
* Returns: "earlier", "later", or "equal".
*/
def compareDates(a: LocalDate, b: LocalDate): String = {
if (a.isBefore(b)) "earlier"
else if (a.isAfter(b)) "later"
else "equal"
}
/** Run a single test case:
* - Parse both dates
* - Handle invalid input
* - Compare if valid
*/
def runTestCase(d1: String, d2: String): Unit = {
(parseDate(d1), parseDate(d2)) match {
case (Some(a), Some(b)) =>
println(s"Compare '$d1' vs '$d2' → ${compareDates(a, b)}")
case _ =>
println(s"Compare '$d1' vs '$d2' → invalid date format")
}
}
/** Main test suite:
* - Multiple test cases
* - Includes edge cases
* - Prints results cleanly
*/
@main def main(): Unit = {
println("Date comparison tests:\n")
val tests = Seq(
("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
)
tests.foreach { case (d1, d2) => runTestCase(d1, d2) }
}
/*
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
*/