Qbasicnews.com

Full Version: Write a bulletproof date validation routine.
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3 4 5 6
Quote:
Code:
IF year / 4 = INT(year / 4) THEN
Dark Ninja, your code for testing whether a year is a leap year is incorrect. The definition of a leap year (they added something to it, but I can't remember what) is:
Leapyear
#1. Factor of 4
#2. Not a factor of 100
#3. Rule 2 drops if year is factor of 400

So, the proper code would be:
Code:
LeapYear = ((Year MOD 4 = 0 AND Year MOD 100 <> 0) OR (Year MOD 400 = 0))
IF LeapYear THEN blablabla

Hope you can do something with it Wink

EDIT:
Oh and:
Code:
IF day < 28 OR
Why are days lower than 28 invalid? :lol: That means your program will output 20000101 (1st Jan. 2000) as an invalid date.
Thanks, easily fixed.
Code:
SUB DateVerify(FullDate$)
IF LEN(FullDate$) <> 8 THEN PRINT "Invalid": END
year$ = LEFT$(FullDate$, 4)
month$ = MID$(FullDate$, 5, 2)
day$ = RIGHT$(FullDate$, 2)
year = VAL(year$)
month = VAL(month$)
day = VAL(day$)
IF year <> INT(year) OR month <> INT(month) OR day <> INT(day) THEN PRINT "Invalid": END

IF year > 3999 OR year < 1600 THEN PRINT "Invalid": END
IF month < 1 OR month > 12 THEN PRINT "Invalid": END
IF day > 31 THEN PRINT "Invalid": END
IF month = 2 THEN
  IF year / 4 = INT(year / 4)  THEN
     Leap$ = "yes"
     IF year / 100 = INT(year / 100) THEN
       Leap$ = "no"
       IF year / 400 = INT(year/400) THEN Leap$ = "yes"
     END IF
  END IF
  IF (day > 28 AND leap$ = "no") OR (day > 29 AND leap$ = "yes")   THEN
    PRINT "Invalid": END
  END IF
END IF
      
IF month = 4 OR month = 6 OR month = 9 OR month = 11 THEN
  IF day > 30 THEN PRINT "Invalid": END
END IF
PRINT "Valid": END
END SUB
Erm... the code looks functional, but there are still some things that could be improved Wink

#1. I don't like my program to quit when I run your function (d'oh Big Grin)

#2. It can be made much faster if you use integers.

Moneo, Meg, add comments if you wish Smile
Quote:Erm... the code looks functional, but there are still some things that could be improved Wink

#1. I don't like my program to quit when I run your function (d'oh Big Grin)

#2. It can be made much faster if you use integers.

Moneo, Meg, add comments if you wish Smile
Neo,
"... the code looks functional" --- you're being so kind.

About #2 above: Speed is really not an issue, but it is nice to write the speediest code you can, just as a matter of habit.

The same applies to writing tight, straight-line code with as few if's as possible. The more code your program has, and especially the more if's, then the more chances of bugs. Just like our friend DarkNinja's code; his enhanced leap year logic has so many if's, that I don't even want to bother checking it.
*****
Quote:Neo,
"... the code looks functional" --- you're being so kind.
I am always kind... Wink

Quote:About #2 above: Speed is really not an issue, but it is nice to write the speediest code you can, just as a matter of habit.
Yeah, that is true, but I implicitly referred to Dark Ninja using strings as temporary storage (leapyear$ = "yes", leapyear$ = "no"). It's much less efficient than just leapyear = 0 or leapyear = -1.
It doesn't need to be ultrafast, just clean code with an acceptable algorithm.

Quote:The same applies to writing tight, straight-line code with as few if's as possible. The more code your program has, and especially the more if's, then the more chances of bugs. Just like our friend DarkNinja's code; his enhanced leap year logic has so many if's, that I don't even want to bother checking it.
I had the same thoughts.
Wow, almost a year and half has gone by and I never posted my own solution to this challenge.

This is very old code that I've been using for years. Try it, you'll' like it.
Code:
DEFINT A-Z

DECLARE FUNCTION   NumStrict    (Z$)
DECLARE FUNCTION   IsLeapYear%  (Z)

rem Setup days-per-month table.
DIM ZMO(1 TO 12)
DATA 31,28,31,30,31,30,31,31,30,31,30,31
FOR ZMM=1 TO 12:READ ZMO(ZMM):NEXT ZMM

REM ***********************************************************************

input "Enter date to be validated as YYYYMMDD ",z$
gosub date.check
if date.ok=0 then print "Invalid Date" else print "Date ok"
SYSTEM

REM ****************  DATE.CHECK SUBROUTINE  **************************
REM *
REM *** VALIDATE A DATE IN YYYYMMDD FORMAT.
REM *
REM *  INPUT: Z$       = Given date in format YYYYMMDD.
REM *
REM * OUTPUT: DATE.OK = -1 if input date is VALID.   (true)
REM *                    0 if input date is INVALID. (false)                  
REM *
DATE.CHECK:
  DATE.OK = 0                          'preset to false
  IF LEN(Z$)<>8 THEN RETURN
  IF NOT NUMSTRICT(Z$) THEN RETURN
  ZDD=VAL(RIGHT$(Z$,2))                'Set day              
  ZMM=VAL(MID$(Z$,5,2))                'Set month.
  ZYY=VAL(LEFT$(Z$,4))                 'Set year.
  IF ZMM<1 OR ZMM>12 OR ZDD<1 OR ZDD>31 THEN RETURN
  IF ZMO(ZMM)+1*(-(ZMM=2 AND ISLEAPYEAR(ZYY))) < ZDD THEN RETURN
  '      If expression (month=2 and is leapyear) is TRUE which is -1, then
  '      taking the negative of this issues a plus 1. Conversely, FALSE    
  '      always gives a zero. Multiplying the +1 by this result of 1 or 0
  '      will either add 1 or not to the number of days in the month.
  '      The logic wants to add 1 only when it is February and leap year.
  DATE.OK = -1        '-1=valid (true)
RETURN    

END

' ====================== ISLEAPYEAR ==========================
'         Determines if a year is a leap year or not.
' ============================================================
'
FUNCTION IsLeapYear (Z) STATIC
   ' If the year is evenly divisible by 4 and not divisible
   ' by 100, or if the year is evenly divisible by 400, then
   ' it's a leap year:
   IsLeapYear = (Z MOD 4 = 0 AND Z MOD 100 <> 0) OR (Z MOD 400 = 0)
END FUNCTION

' =================================================================

FUNCTION NumStrict (Z$)
  '
  ' *** CHECK FOR STRICTLY NUMERIC (NO NULL, NO NEGATIVE, NO DECIMAL)
  '
  NumStrict=0         'Init to False

  IF Z$="" THEN EXIT FUNCTION

  FOR X = 1 TO LEN(Z$)
      A=ASC(MID$(Z$,X,1))
      IF A<48 OR A>57 THEN EXIT FUNCTION
  NEXT X

  NumStrict = -1          'True

END FUNCTION
Looks good... a year later.

I'd dearly suggest though to reform it in the more "modern" style of coding Smile

Also, hi! *hides into lonely darkness again*
Sorry for being off topic, but I wonder if you are able to check your email Moneo? I sent you some mail about a topic I thought you may be interested in.
Quote:Looks good... a year later.

I'd dearly suggest though to reform it in the more "modern" style of coding Smile
Ok, give me a rundown on what is considered modern style code.

Hope you don't ask for colors 'cause I don't have that kind of editor, nor do I use any IDE.

Hi, back at you,
Moneo
Quote:Sorry for being off topic, but I wonder if you are able to check your email Moneo? I sent you some mail about a topic I thought you may be interested in.
Sorry, got my email on another machine. Will check it tomorrow, and get back to you.

*****
Pages: 1 2 3 4 5 6