How to sort a list of string-based dates in PHP

1 Answer

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

    Approach:
      1. Parse each string into DateTime using DateTime::createFromFormat.
      2. Sort using usort() with a comparator that compares DateTime objects.
      3. Print results.

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

/*
    Parse a date string into a DateTime object.
    Returns the DateTime or throws an exception with a clear message.
*/
function parseDate(string $s): DateTime {
    $dt = DateTime::createFromFormat('Y-m-d', $s);
    $errors = DateTime::getLastErrors();

    // If parsing failed OR errors array exists and contains warnings/errors
    if ($dt === false ||
        (is_array($errors) &&
         ($errors['warning_count'] > 0 || $errors['error_count'] > 0))) {

        throw new InvalidArgumentException("Invalid date: $s");
    }

    return $dt;
}


/*
    Sort a list of date strings.
    Returns a new sorted array; does not mutate the input.
*/
function sortDates(array $dates): array {
    $parsed = [];

    // Parse all dates; fail fast on invalid input.
    foreach ($dates as $s) {
        $parsed[] = parseDate($s);
    }

    // Sort using natural DateTime ordering.
    usort($parsed, function(DateTime $a, DateTime $b) {
        return $a <=> $b;
    });

    // Convert back to strings.
    $result = [];
    foreach ($parsed as $d) {
        $result[] = $d->format('Y-m-d');
    }

    return $result;
}

/*
    Helper to print a list of strings.
*/
function printList(array $list): void {
    foreach ($list as $s) {
        echo "  $s\n";
    }
}

/*
    Helper to run a named test case.
*/
function runTest(string $name, array $dates): void {
    echo "\n=== $name ===\n";

    try {
        $sorted = sortDates($dates);
        printList($sorted);
    } catch (Exception $e) {
        echo "Error: {$e->getMessage()}\n";
    }
}


/*
    Main program with multiple test cases.
*/
echo "PHP Date Sorting Demo\n";

/* 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",   // invalid month
    "2024-02-30",   // invalid day
    "not-a-date"    // malformed
]);



/*
run:

ERROR!
PHP 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: Invalid date: 2024-13-01

*/

 



answered Sep 23 by avibootz
...