How to compare two dates in Pascal

1 Answer

0 votes
program CompareDatesFP;

{$mode objfpc}{$H+}

{
    Compare two dates in Free Pascal
    --------------------------------
    This program demonstrates how to compare two dates using only the Free Pascal
    standard library. It uses a modular design, clear comments, and a full test suite.

    Concepts:
        - Parsing dates safely (YYYY-MM-DD)
        - Representing dates with a record
        - Comparing dates lexicographically (year → month → day)
        - Handling invalid formats
        - Edge‑case testing

    Architecture notes:
        - A dedicated function handles parsing.
        - Another function performs comparison.
        - Main runs multiple predefined test cases.
        - No dynamic memory allocation; everything is stack‑based.
        - No external dependencies.

    Performance notes:
        - 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 a structured type.
        - No timezone logic here; this is pure date comparison.
}

type
    TDate = record
        Year: Integer;
        Month: Integer;
        Day: Integer;
    end;

{
    Safely parse a date string in the format YYYY-MM-DD.

    Error handling:
        - Returns False if the date is invalid.
        - Writes parsed values into the TDate record when valid.
}
function ParseDate(const S: String; var D: TDate): Boolean;
var
    Y, M, Da: Integer;
    Dash1, Dash2: Char;
begin
    Result := False;

    if Length(S) < 10 then Exit;

    { Extract using Val and direct indexing }
    if (S[5] <> '-') or (S[8] <> '-') then Exit;

    Val(Copy(S, 1, 4), Y);
    Val(Copy(S, 6, 2), M);
    Val(Copy(S, 9, 2), Da);

    if (M < 1) or (M > 12) then Exit;
    if (Da < 1) or (Da > 31) then Exit;  { Simplified; not checking month lengths }

    D.Year := Y;
    D.Month := M;
    D.Day := Da;

    Result := True;
end;

{
    Compare two TDate objects.

    Returns:
        - 'earlier'
        - 'later'
        - 'equal'
}
function CompareDates(const A, B: TDate): String;
begin
    if A.Year < B.Year then Exit('earlier');
    if A.Year > B.Year then Exit('later');

    if A.Month < B.Month then Exit('earlier');
    if A.Month > B.Month then Exit('later');

    if A.Day < B.Day then Exit('earlier');
    if A.Day > B.Day then Exit('later');

    Result := 'equal';
end;

{
    Run a single test case:
        - Parse both dates
        - Handle invalid input
        - Compare if valid
}
procedure RunTestCase(const S1, S2: String);
var
    D1, D2: TDate;
    Ok1, Ok2: Boolean;
begin
    Ok1 := ParseDate(S1, D1);
    Ok2 := ParseDate(S2, D2);

    if (not Ok1) or (not Ok2) then
    begin
        WriteLn('Compare ''', S1, ''' vs ''', S2, ''' → invalid date format');
        Exit;
    end;

    WriteLn('Compare ''', S1, ''' vs ''', S2, ''' → ', CompareDates(D1, D2));
end;

{
    Main test suite:
        - Multiple test cases
        - Includes edge cases
        - Prints results cleanly
}
var
    Tests: array[1..11, 1..2] of String;
    I: Integer;
begin
    WriteLn('Date comparison tests:');
    WriteLn;

    Tests[1][1] := '2024-01-01'; Tests[1][2] := '2024-01-02';
    Tests[2][1] := '2024-01-02'; Tests[2][2] := '2024-01-01';
    Tests[3][1] := '2024-01-01'; Tests[3][2] := '2024-01-01';
    Tests[4][1] := '1999-12-31'; Tests[4][2] := '2000-01-01';
    Tests[5][1] := '2024-02-29'; Tests[5][2] := '2024-03-01';
    Tests[6][1] := '2024-02-29'; Tests[6][2] := '2023-02-28';
    Tests[7][1] := '2024-13-01'; Tests[7][2] := '2024-01-01';
    Tests[8][1] := '2024-00-10'; Tests[8][2] := '2024-01-01';
    Tests[9][1] := '2024-01-32'; Tests[9][2] := '2024-01-01';
    Tests[10][1] := 'abcd-ef-gh'; Tests[10][2] := '2024-01-01';
    Tests[11][1] := '2024-01-01'; Tests[11][2] := 'abcd-ef-gh';

    for I := 1 to 11 do
        RunTestCase(Tests[I][1], Tests[I][2]);
end.


{
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

}

 



answered Sep 20 by avibootz
...