How to sort a list of string‑based dates in Swift

1 Answer

0 votes
import Foundation

/*
    Program goal:
    -------------
    Sort a list of date strings in the format "YYYY-MM-DD".

    Approach:
      1. Parse each string into Date using a strict DateFormatter.
      2. Sort using Swift’s built-in sorted(by:) (O(n log n)).
      3. Convert back to strings and print results.

    Architecture notes:
    -------------------
    - Parsing is isolated in a dedicated function for clarity and testability.
    - Sorting uses sorted(by:), which is efficient and stable.
    - Error handling: invalid formats are detected and reported.
    - Edge cases: malformed strings, invalid ranges, leap years.
    - Performance: Date parsing is fast; sorting is O(n log n).
    - Memory: minimal; only an array of small objects.
    - Security: avoids unsafe operations; uses immutable Date values.
*/

// Custom error type for date parsing
enum DateParseError: Error {
    case invalidDate(String)

    var message: String {
        switch self {
        case .invalidDate(let s):
            return "Invalid date: \(s)"
        }
    }
}

// Strict ISO 8601 formatter
let isoFormatter: DateFormatter = {
    let f = DateFormatter()
    f.dateFormat = "yyyy-MM-dd"
    f.locale = Locale(identifier: "en_US_POSIX") // stable parsing
    f.timeZone = TimeZone(secondsFromGMT: 0)     // avoid timezone shifts
    return f
}()

/*
    Parse a date string into Date.
    Returns Result<Date, DateParseError> for safe error handling.
*/
func parseDate(_ s: String) -> Result<Date, DateParseError> {
    if let dt = isoFormatter.date(from: s) {
        return .success(dt)
    } else {
        return .failure(.invalidDate(s))
    }
}

/*
    Sort a list of date strings.
    Returns Result<[String], DateParseError> to propagate errors.
*/
func sortDates(_ dates: [String]) -> Result<[String], DateParseError> {
    var parsed: [Date] = []

    // Parse all dates; fail fast on invalid input.
    for s in dates {
        switch parseDate(s) {
        case .success(let dt):
            parsed.append(dt)
        case .failure(let err):
            return .failure(err)
        }
    }

    // Sort using natural Date ordering.
    let sorted = parsed.sorted()

    // Convert back to strings.
    let result = sorted.map { isoFormatter.string(from: $0) }
    return .success(result)
}

/*
    Helper to print a list of strings.
*/
func printList(_ list: [String]) {
    for s in list {
        print("  \(s)")
    }
}

/*
    Helper to run a named test case.
*/
func runTest(_ name: String, _ dates: [String]) {
    print("\n=== \(name) ===")
    switch sortDates(dates) {
    case .success(let sorted):
        printList(sorted)
    case .failure(let err):
        print("Error: \(err.message)")
    }
}

/*
    Main program with multiple test cases.
*/
print("Swift Date Sorting Demo")

// Basic chronological order
runTest("Basic chronological order",
        ["2024-01-05", "2023-12-31", "2024-01-01", "2022-07-15"])

// Already sorted input
runTest("Already sorted input",
        ["2020-01-01", "2020-01-02", "2020-01-03"])

// Leap year edge cases
runTest("Leap year edge cases",
        ["2020-02-29", "2019-02-28", "2021-03-01"])

// Invalid date detection
runTest("Invalid date detection",
        ["2024-13-01", "2024-02-30", "not-a-date"])


/*
run:

Swift Date Sorting Demo

=== Basic chronological order ===
  2022-07-15
  2023-12-31
  2024-01-01
  2024-01-05

=== Already sorted input ===
  2020-01-01
  2020-01-02
  2020-01-03

=== Leap year edge cases ===
  2019-02-28
  2020-02-29
  2021-03-01

=== Invalid date detection ===
ERROR!
Error: Invalid date: 2024-13-01

*/

 



answered Sep 23 by avibootz
...