-3

I am trying to create a program that takes a users input and checks if its valid as a date (years 2000 - 2099). when I was bug testing the code I put in an enter as the input twice in a row, the first time I entered an enter, no error was thrown but the second time the console flashes a message and crashes. I took a screenshot as it crashed and this is the error it showed

An unhandled exception occured at $0040CDE1
EConvertError : "" is an invalid integer

My best guess is that the error was caused by one of my StrToInt due to the EConvertError but it unclear to me as to why it only throws it on the second run through and not the first. I suspect that the error occurs on either line, 85, 98, 111, or 195.

When I initially wrote this program a was a beginner to Pascal so I apologise in advance for any sloppy code.

below is all of the code if you would like to run it for yourselves.

program DateVerifierAssignment;

uses crt, sysutils;

var
    userInputArray: array[0..7] of string;  
    len, i, day, month, year: integer;
    date, userInput, stringDay, stringMonth, stringYear: string;
    errorCatch: boolean;

//DECLARING FUNCTIONS & PROCEDURES
procedure TitleScreen();
    begin
    //prints a coloured wall of text to give information like name and instructions
    WriteLn(' o-------------------------o');
    Write(' | ');TextColor(White);Write('Date Validation Program');TextColor(Cyan);WriteLn(' |');
    WriteLn(' o-------------------------o');
    WriteLn();
    WriteLn(' o-------------------------o');
    Write(' |      ');TextColor(White);Write('Instructions');TextColor(Cyan);WriteLn('       |');
    WriteLn(' o-------------------------o');
    Write(' |   ');TextColor(White);Write('Enter a date and the');TextColor(Cyan);WriteLn('  |');
    Write(' | ');TextColor(White);Write('program will verify it');TextColor(Cyan);WriteLn('  |');
    Write(' |  ');TextColor(White);Write('and convert it to its');TextColor(Cyan);WriteLn('  |');
    Write(' |        ');TextColor(White);Write('long form');TextColor(Cyan);WriteLn('        |');
    WriteLn(' o-------------------------o');
    WriteLn();
    TextColor(White);
    Write('   press any key to begin');
    
    //waits for user input then clears the screen and returns the text color to white
    ReadKey();
    ClrScr;
    end;
         
       
function DateVerification(var userInput: string): boolean;
    var
        errorLimit : boolean;
        bounds: integer;
    begin
    errorLimit := True;
    //stores the length of the string as a variable
    len := Length(userInput);
    
    //checks to see if entry is 8 chracters long and displays an error message and returns user to input screen if it doesn't fit
    if (len <> 8) and (errorLimit = True) then
        begin
        ClrScr();
        TextColor(Red);
        WriteLn('input was not the right length (8 characters)');
        TextColor(White);
        Write('make sure date fits format ');
        TextColor(LightGreen);
        WriteLn('dd/mm/yy');
        TextColor(White);
        Readkey();
        ClrScr();
        errorLimit := false;
        Dateverification := false;
        end;
    
    //spits each character into its own spot in an array
    for i := 1 to len do
          userInputArray[i - 1] := userInput[i];
            
    //tests if every slot in the array where a slash should be is a slash
    for i := 0 to len-1 do
        begin
        if (userInputArray[2] <> '/') or (userInputArray[5] <> '/') and (errorLimit = true) then
            begin
            ClrScr();
            TextColor(Red);
            WriteLn('input did not have slashes in correct locations ');
            TextColor(LightGreen);
            WriteLn('dd/mm/yy');
            TextColor(White);
            Readkey();
            ClrScr();
            errorLimit := false;
            Dateverification := false;
            end;
        end;
        
    year := ((StrToInt(userInputArray[6]))*10) + StrToInt(userInputArray[7]);
    if (year < 1) or (year > 99) and (errorLimit = true) then
        begin
        ClrScr();
        TextColor(Red);
        WriteLn('year was not from 0 to 99');
        TextColor(White);
        Readkey();
        ClrScr();
        errorLimit := false;
        Dateverification := false;
        end;
        
    month := ((StrToInt(userInputArray[3]))*10) + StrToInt(userInputArray[4]);
        if (month < 1) or (month > 12) and (errorLimit = true) then
        begin
        ClrScr();
        TextColor(Red);
        WriteLn('month was not from 1 to 12');
        TextColor(White);
        Readkey();
        ClrScr();
        errorLimit := false;
        Dateverification := false;
        end;
    
    day :=  ((StrToInt(userInputArray[0]))*10) + StrToInt(userInputArray[1]);
    if (month = 4) or (month = 6) or (month = 9) or (month = 11) then
        bounds := 30;
    
    if (month = 2) then
        begin
        if (IsLeapYear(year) = true) then
            bounds := 29
        else
            bounds := 28;
        end
    else
        bounds := 31;    
    
    if (day < 1) or (day > bounds) and (errorLimit = true) then
            begin
            ClrScr();
            TextColor(Red);
            WriteLn('day was not from 1 to days in month');
            TextColor(White);
            Readkey();
            ClrScr();
            errorLimit := false;
            Dateverification := false;
            end;
    
    if (errorLimit = true) then  
        DateVerification := True;   
    end;    


function IsLeapYear(var year: integer): boolean;
//simple function to determine if a year is a leap year on the gregorian calender
    begin
        if (year mod 4) = 0 then
            if (year mod 100 <> 0) then
                if (year mod 400 = 0) then
                    IsLeapYear := true
                else
                    IsLeapYear := false
            else
                IsLeapyear := false
        else
            IsLeapyear := false    
    end;


procedure DateToAlpha(var userInput: string);
    begin
    
    end;
    

//MAIN PROGRAM
begin
    //preparing for while loop later in code and changes text colour to cyan
    errorCatch := true;
    TextColor(Cyan);
    
    //Displays a title screen and instruction about how to use(stored in a procedure to help with readability)
    TitleScreen();
     
    //begins a loop so that if an error is to occur the program can easily ask for a new date and try again
    while (errorCatch = true) do
        begin
        //sets error catch to 0 so that if there a no errors the program will not loop
        errorCatch := false;
        
        //displays information on how to input a date as well as an example with different colours for better readability
        Write('Enter a date in the format');TextColor(LightGreen); WriteLn(' dd/mm/yy');TextColor(White);
        Write('e.g. ');TextColor(LightGreen);WriteLn(' 09/07/20'#13#10);TextColor(White);
        
        //takes date user inputs and stores it
        ReadLn(userInput); 
        
        //calls the date verification function to see if the date is valid        
        //(refer to dateVerification at the top of the program for more info and comments)
        if (DateVerification(userInput) = false) then
            errorCatch := true;
            
        len := Length(userInput);
        for i := 1 to len do
          userInputArray[i - 1] := userInput[i];
        
        year := ((StrToInt(userInputArray[6]))*10) + StrToInt(userInputArray[7]);
        readKey();
        end;   
end.
  • 1
    You might want to sit down with your teacher and discuss the program. It's their job to help you learn. – Andreas Rejbrand Aug 19 '20 at 14:59
  • The very first things you should do after ReadLn(userInput) is to check that userInput is the right length (6?) and signal an error if it isn't. A specific case of the wrong length is is the user just pressed [Enter], in which case userInput willl be empty and calling StrToIn on any part of it will raise the exception you mention. Btw you have too many variables - you shouldn't need all three or errorLimit, errorCatch and DateVerification. Simplify ... – MartynA Aug 19 '20 at 15:05
  • There is far too much code in this post. Please reduce it to a [mre] (note the word *Minimal*) that demonstrates the specific problem you're having. – Ken White Aug 19 '20 at 23:43

1 Answers1

3

Ordinarily on SO we don't provide fully-coded answers to qs which are obviously coursework.

In this case I thought I'd make an exception because it was obvious that you are making unnecessarily heavy weather of this, and the way you've coded it is likely to actually get in the way of debugging it and getting it working correctly.

So, the example below shows a very simple, clean way to validate a date in the 21st century supplied in dd/mm/yyyy format. It shows the correct order of processing and validation steps; if it detects an error in any step, it says what the problem is and halts. If execution drops through to the end, the supplied date string must be valid.

I have deliberately left out any loops or prettifying code, because the important thing to get right first is a clean and concise coding of the processing and validation steps. If you want to use loops, fine, but the way you've used e.g. errorCatch, I bet that if you come back to your code in 6 months, you won't remember how it's supposed to work. You don't need any complicated flags or loops for this task - the user simply has to be able to type exactly eight characters (followed by [Enter]) and the code will tell then whether it's valid or not.

Note I've used the standard Copy function to separate out the various parts of the date inputted. Btw, your declaration

userInputArray: array[0..7] of string;

is just plain wrong. If you want an array of a certain number of characters, fine, but that would just needlessly complicate handling and processing what the user types. It's far simpler, and therefore less error-prone to accept a single string of 8 characters and just deal with that. But in any case, to permit the string to include the / characters after the day and month digits, the length of the stringg should be 10, not eight, to allow for those and four year digits.

program DateVerification;

uses
  SysUtils;

var
  sUserInput,
  sDay,
  sMonth,
  sYear : String;
  iDay,
  iMonth,
  iYear,
  iDays: Integer;
  bIsLeapYear : Boolean;

function DaysInMonth(iMonth, iYear : Integer) : Integer;
begin
  Result := -1; //  you supply the code for this taking into account leap year for February
end;

begin
  writeln('Please enter a date between 01/01/2000 and 31/12/2099 in the format shown');
  readln(sUserInput);
  if Length(sUserInput) <> 10 then begin
    writeln('Input is wrong length.');
    Halt;
  end;
  if (sUserInput[3] <> '/') or (sUserInput[6] <> '/') then begin
    writeln('Input is incorrectly delimited.');
    Halt;
  end;

  sDay := Copy(sUserInput, 1, 2);
  sMonth := Copy(sUserInput, 4, 2);
  sYear := Copy(sUserInput, 7, 4);

  iYear := StrToInt(sYear);
  if (iYear < 2000) or (iYear > 2099) then begin
    writeln('Invalid year : ', sYear);
    Halt;
  end;

  bIsLeapYear := IsLeapYear(iYear); //  you supply the code for IsLeapYear

  iMonth := StrToInt(sMonth);
  if (iMonth < 1) or (iMonth > 12) then begin
    writeln('Invalid month : ', sMonth);
    Halt;
  end;

  iDay := StrToInt(sDay);

  if (iDay < 1) or (iDay > DaysInMonth(iMonth, iYear)) then begin
    //  You need to supply the DaysInMoth function, which of course
    //  needs to account for February in a leap year
    writeln('Invalid day of month: ', sMonth);
    Halt;
  end;

  writeln(sUserInput, ' is a valid date.');
  readln;

end.
MartynA
  • 30,454
  • 4
  • 32
  • 73
  • 2
    @AndreasRejbrand [sound of forehead-slapping] oops! You are of course quite right! How it happened was that my original code didn't account for the delimiters or four-digit years and then I changed my mind and decided to deal with them. I'll correct it in a moment. Many thanks! – MartynA Aug 21 '20 at 17:35