Qbasicnews.com
September 21, 2019, 08:50:33 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: Back to Qbasicnews.com | QB Online Help | FAQ | Chat | All Basic Code | QB Knowledge Base
 
   Home   Help Search Login Register  
Pages: [1] 2 3
  Print  
Author Topic: Compute a person's age today based on his date of birth.  (Read 17842 times)
Moneo
Na_th_an
*****
Posts: 1971


« on: June 08, 2005, 08:50:20 PM »

INPUT: The person's date of birth as YYYYMMDD.

LOGIC:
- Validate the input date of birth. Abort if invalid.
- Get today's date using the DATE$ function.
- Compute the person's age in years using a calculation method, or if you prefer perform some sort of loop to get to it.

OUTPUT: The person's age in years. Note: If his birthday happens to be today, he will be one year older (obviously).
*****
Logged
Neo
Na_th_an
*****
Posts: 2150



« Reply #1 on: June 09, 2005, 05:55:46 PM »

Sorry for the wait... I was quite busy lately.

I hope this produces some answers that are correct. I tested it a few times and it returned right ages for all my family members Smiley

Code:
Option Static
Option Explicit


Declare Function isValidDate (Year As Integer, Month As Integer, Day As Integer) As Byte
Declare Function isLeapYear (Year As Integer) As Byte
Declare Function getPersonAge (Year As Integer, Month As Integer, Day As Integer, _
                               NowYear As Integer, NowMonth As Integer, NowDay As Integer) As Integer

Dim Year As Integer, Month As Integer, Day As Integer

'@ Ask the user for input YYYYMMDD and check if it's valid
Dim Datum As String, isOk As Byte = Not( 0 ), i As Integer
Dim NumberStr As String
NumberStr = "0123456789"
Do
    isOk = Not( 0 )
    Input "Enter a valid birthday in format YYYYMMDD: ", Datum
   
    If Len(Datum) <> 8 Then
        isOk = 0
    Else
        For i = 0 To 7
            If Instr(NumberStr, Mid$(Datum, i + 1, 1)) = 0 Then isOk = 0
        Next i        
       
        If isOk Then
            Year = Val(Left$(Datum, 4))
            Month = Val(Mid$(Datum, 5, 2))
            Day = Val(Right$(Datum, 2))
           
            isOk = isValidDate(Year, Month, Day)
        End If        
    End If  
   
    If Not( isOk ) Then Print "Invalid entry"
Loop Until isOk


'@ Get the current Date (format MM-DD-YYYY)
Dim CurrDate As String, CurrYear As Integer, CurrMonth As Integer, CurrDay As Integer
CurrDate = Date$
CurrYear = Val(Right$(CurrDate, 4))
CurrMonth = Val(Left$(CurrDate, 2))
CurrDay = Val(Mid$(CurrDate, 4, 2))

Print getPersonAge(Year, Month, Day, CurrYear, CurrMonth, CurrDay)

Sleep
End



Private Function getPersonAge (Year As Integer, Month As Integer, Day As Integer, _
                               NowYear As Integer, NowMonth As Integer, NowDay As Integer) As Integer
                               
    Dim printed As integer = 0

    '@ Very simple loop to calculate the age
    Dim lYear As Integer, lMonth As Integer, lDay As Integer, rAge As Integer = 0
    For lYear = Year To NowYear
       
        Dim MinMonth As Integer, MaxMonth As Integer
        If lYear = Year Then MinMonth = Month Else MinMonth = 1
        If lYear = NowYear Then MaxMonth = NowMonth Else MaxMonth = 12
       
        For lMonth = MinMonth To MaxMonth
           
            Dim MaxDay As Integer, MinDay As Integer
            Select Case lMonth
            Case 1, 3, 5, 7, 8, 10, 12 : MaxDay = 31
            Case 4, 6, 9, 11: MaxDay = 30        
            Case 2: MaxDay = 28 + Abs(isLeapYear(lYear))        
            End Select    
               
            If lYear = Year And lMonth = Month Then MinDay = Day + 1 Else MinDay = 1
            If lYear = NowYear And lMonth = NowMonth Then MaxDay = NowDay
           
            For lDay = MinDay To MaxDay
               
                If lMonth = Month And lDay = Day Then rAge += 1
               
            Next lDay            
               
        Next lMonth        
    Next lYear    
   
    getPersonAge = rAge
End Function

Private Function isValidDate (Year As Integer, Month As Integer, Day As Integer) As Byte
    '@ Checks if a year is a valid year
    If Year < 0 Then isValidDate = 0: Exit Function
    If Month < 1 Then isValidDate = 0: Exit Function
    If Day < 1 Then isValidDate = 0: Exit Function
   
    If Month > 12 Then isValidDate = 0: Exit Function
   
    Dim MaxDay As Integer
    Select Case Month
        Case 1, 3, 5, 7, 8, 10, 12 : MaxDay = 31
        Case 4, 6, 9, 11: MaxDay = 30        
        Case 2: MaxDay = 28 + Abs(isLeapYear(Year))        
    End Select    
   
    If Day > MaxDay Then isValidDate = 0: Exit Function
   
    isValidDate = -1
End Function

Private Function isLeapYear (Year As Integer) As Byte
    isLeapYear = ((Year MOD 4 = 0) AND (Year MOD 100 <> 0)) OR (Year MOD 400 = 0)
End Function



NOTE: FreeBasic code

Smiley I hope it works and suits your challenge objectives.
Logged
ThaMariuZ
Forum Regular
**
Posts: 105



WWW
« Reply #2 on: June 09, 2005, 06:20:52 PM »

woah, the code is very long...

i don`t have any time at the moment, but 'm gonna code a qb prog as soon as i get to.

cheers
Logged

'm so lazy... no really.... i am the laziest programmer ever ... ever.
Neo
Na_th_an
*****
Posts: 2150



« Reply #3 on: June 09, 2005, 06:55:47 PM »

It's not very long... half the code is actually checking if the input birthday is a valid date (note that people who are yet to be born have age 0).

The actual "calculation"... it's more a loop, happens in the getPersonAge function, which isn't very long Smiley
Logged
Moneo
Na_th_an
*****
Posts: 1971


« Reply #4 on: June 09, 2005, 07:44:19 PM »

Neo,

I get the following FB compile error:
error 64: Too many expressions, found: 'Not'
On Line:  13
which is: Dim Datum As String, isOk As Byte = Not( 0 ), i As Integer

Reviewing your code, I too feel that it is too long. The long function "getpersonAge" can be done in about 5 instructions without any loop.

If the person is less than a year old, like a 6 month old baby, his age is zero years. If the person was not born yet, then he has no date of birth.

You did a nice job of validating the input date of birth.

Fix the compile error and I'll do some testing of this version.
*****
Logged
Neo
Na_th_an
*****
Posts: 2150



« Reply #5 on: June 09, 2005, 08:02:38 PM »

The problem is there is no compile error Smiley

Maybe download the latest FB version? I have no compiler error at all with the latest FB IDE and FB version.


And yes, I just did the loop because it's easier, else you'd have to do all checks with date shiftings.

NOTE: My code treats a leapling as a leapling, which means, he'll only get a birthday every leapyear! (officially this is the case).
Logged
Moneo
Na_th_an
*****
Posts: 1971


« Reply #6 on: June 09, 2005, 08:33:16 PM »

Quote from: "Neo"
The problem is there is no compile error Smiley
Maybe download the latest FB version? I have no compiler error at all with the latest FB IDE and FB version.

And yes, I just did the loop because it's easier, else you'd have to do all checks with date shiftings.

NOTE: My code treats a leapling as a leapling, which means, he'll only get a birthday every leapyear! (officially this is the case).

Sorry, Neo, I was using the previous version of FB. I have problems with the lastest version of FBIDE. It issues an error saying it can't find "\ide\spash.png". I ignored the error and continued to compile your program. It works fine. Cheesy

I don't know what you mean by: "... else you'd have to do all checks with date shiftings." But let's leave this subject until after I post my solution, or someone else does it the same way. Ok?

About the leapling. I assume you mean a person born on a leap year on February 29th. You say that "officially" he has a birthday every leapyear. That may be aesthetically true, but the goverment of most any nation will consider his age as a multiple of years, just like anybody else, for reasons of having to sign up for military service, registering to vote, paying taxes, getting a drivers license, etc.
*****
Logged
Deleter
Na_th_an
*****
Posts: 1292



WWW
« Reply #7 on: June 09, 2005, 08:39:08 PM »

well, its just about as elementary as you can get, but hey w/e. this was coded in fb (hence the sleep at the end):
Code:
birth$ = "20040101"
cyear = val(mid$(date$, 7, 4))
cmonth = val(mid$(date$,1,2))
cday = val(mid$(date$, 4, 2))
byear = val(mid$(birth$, 1, 4))
bmonth = val(mid$(birth$, 5,2))
bday = val(mid$(birth$,7,2))
age = (cyear - byear) - 1
if bmonth <= cmonth then
    if bday <= cday or bmonth < cmonth then
        age = age + 1
    end if
end if
if age < 0 then
    print "invalid birthdate"
elseif age < 1 then
    print cmonth-bmonth; " months old"
elseif age = 1 then
    print age; " year old"
elseif age > 1 then
    print age; " years old"
end if
sleep
Logged

Moneo
Na_th_an
*****
Posts: 1971


« Reply #8 on: June 09, 2005, 09:10:19 PM »

Deleter,

I compiled your solution and ran a few tests using valid data, and it ran ok.

I have the following comments which I hope you take in a constructive manner:

1) Minor point: You did not input the date of birth, you inserted one into a variable.

2) You did not perform any validation on the input date of birth. No wonder the problem became elementary.

3) In obtaining the current date using DATE$, you invoked the DATE$ function three separate times. This could rarely happen, but if you were running the program just at midnight, then you could get two different dates, before midnight and after midnight, which would affect your final year, month, day.

If you'd like, you can fix up your program and submit it again.
*****
Logged
Neo
Na_th_an
*****
Posts: 2150



« Reply #9 on: June 09, 2005, 09:23:51 PM »

Moneo, in an attempt to shorten the getPersonAge function I came up with the following, bizarre result.

I know it shouldn't be working fully but I haven't found a current date / birth date yet for which it doesn't work... and I tried around 400 times.

I hoped you could test the functionality of both my submitted functions Smiley

Code:
Private Function getPersonAge (Year As Integer, Month As Integer, Day As Integer, _
                               NowYear As Integer, NowMonth As Integer, NowDay As Integer) As Integer
       
    getPersonAge = ((NowYear * 366 + NowMonth * 31 + NowDay) - (Year * 366 + Month * 31 + Day)) \ 366
End Function


Note, to test this function you replace the old getPersonAge function by this 3-line new function.

Hmmm... 600 tests... no difference yet...
Logged
Deleter
Na_th_an
*****
Posts: 1292



WWW
« Reply #10 on: June 10, 2005, 12:22:40 AM »

Quote from: "Moneo"
Deleter,

I compiled your solution and ran a few tests using valid data, and it ran ok.

I have the following comments which I hope you take in a constructive manner:

1) Minor point: You did not input the date of birth, you inserted one into a variable.

2) You did not perform any validation on the input date of birth. No wonder the problem became elementary.

3) In obtaining the current date using DATE$, you invoked the DATE$ function three separate times. This could rarely happen, but if you were running the program just at midnight, then you could get two different dates, before midnight and after midnight, which would affect your final year, month, day.

If you'd like, you can fix up your program and submit it again.
*****

cool. I am not ignorant enough to take critism as an insult, seeing as most of the time, its the opposite. Thanks for pointing these things out, I'm glad you did. I am not aware of one tenth of all the nuances there are, the date$ thing being one of them. Since I was rewriting it, I decided to make it able to tell you how many days until your next birthday as well. This will probably contain more bugs/things to fix, so, tell me all of them, I would prefer it.  Cheesy

Code:
declare function maxday(month as integer, year as integer)
declare function daystillbday(cmonth as integer, bmonth as integer, cday as integer, bday as integer, cyear as integer)
print "Type 'X' to exit"
do
    input$ "Birthdate (YYYYMMDD)", birth$
    if ucase$(left$(birth$, 1)) = "X" then exit do
    cdate$ = date$
    cyear = val(mid$(cdate$, 7, 4))
    cmonth = val(mid$(cdate$,1,2))
    cday = val(mid$(cdate$, 4, 2))
    byear = val(mid$(birth$, 1, 4))
    bmonth = val(mid$(birth$, 5,2))
    if bmonth < 1 or bmonth > 12 then byear = cyear+1
    bday = val(mid$(birth$,7,2))
    if bday < 1 or bday > maxday(bmonth, byear) then byear = cyear+1
    age = (cyear - byear) - 1
    if bmonth <= cmonth then
        if bday <= cday or bmonth < cmonth then
            age = age + 1
        end if
    end if
    if age < 0 then
        print "Invalid birthdate"
    elseif age < 1 then
        print cmonth-bmonth; " months old for "; daystillbday(cmonth,bmonth,cday,bday,cyear); " more days"
    elseif age = 1 then
        print age; " year old for "; daystillbday(cmonth,bmonth,cday,bday,cyear); " more days"
    elseif age > 1 then
        print age; " years old for "; daystillbday(cmonth,bmonth,cday,bday,cyear); " more days"
    end if    
loop
end

function maxday(month as integer, year as integer)
    '1-31, 2-28, 3-31, 4-30, 5-31, 6-30, 7-31, 8-31, 9-30, 10-31, 11-30, 12-31
    maxday = 30
    if month/2 <> int(month/2) and month < 8 then maxday=31
    if month=2 and (year mod 4) <> 0 then maxday=28
    if month=2 and (year mod 4) = 0 then maxday = 29
    if month>7 and month/2 = int(month/2) then maxday = 31
end function

function daystillbday(cmonth as integer, bmonth as integer, cday as integer, bday as integer, cyear as integer)
    if cmonth < bmonth or (cmonth = bmonth and cday < bday) then
        for x = cmonth to bmonth-1
            tdaystillbday = tdaystillbday + maxday(x, cyear)
        next x
        tdaystillbday = tdaystillbday+bday-cday
    elseif (cmonth > bmonth) or (cmonth=bmonth and cday >= bday) then
        for x = cmonth to 12
            tdaystillbday = tdaystillbday +maxday(x, cyear)
        next x
        tdaystillbday=tdaystillbday-cday
        for x = 1 to bmonth-1
            tdaystillbday = tdaystillbday+maxday(x, cyear+1)
        next x
        tdaystillbday=tdaystillbday+bday
    end if
    daystillbday=tdaystillbday
end function
Logged

Neo
Na_th_an
*****
Posts: 2150



« Reply #11 on: June 10, 2005, 06:28:48 AM »

It looks good, I only have one remark though:
Quote
The Gregorian calendar adds an extra day to February, making it 29 days long, in years where the quotient has no remainder when divided by 4, excluding years where the quotient has no remainder when divided by 100, but including years where the quotient has no remainder when divided by 400.

I'm sure Moneo would have said something about this, so I post it here too Smiley
Logged
Moneo
Na_th_an
*****
Posts: 1971


« Reply #12 on: June 10, 2005, 02:28:30 PM »

Neo,

I'll test you new function/formula as soon as possible.

I'm going to have to write a test program which loops to generate the age for say the last 100 years, day by day, using a known accurate algorithm. Given this, I can plug in submittted solutions like yours and verify their performance. Give me some time.

By the way, your date of birth validation checks for a valid date. However, in the case of the given problem, it should also check that the date of birth is not in the future. Do you agree?
*****
Logged
Moneo
Na_th_an
*****
Posts: 1971


« Reply #13 on: June 10, 2005, 02:41:02 PM »

Deleter,

Like I just told Neo, I'll test your new solution as soon as possible.

I see you're in a good mood, so do me a favor. Please don't add any additional goodies to the specifications. What this does is make my testing more complicated.

Neo's comment regarding your leapyear calculation is true. The logic is incomplete. See the function called IsLeapYear in Neo's code. We both share this function and it has been actively running for years. You are welcome to use it.

Since you have to make a change, take this opportunity to remove any extra goodies that you added. Thanks.

I also told Neo the following:
I'm going to have to write a test program which loops to generate the age for say the last 100 years, day by day, using a known accurate algorithm. Given this, I can plug in submittted solutions like yours and verify their performance. Give me some time.
*****
Logged
Neo
Na_th_an
*****
Posts: 2150



« Reply #14 on: June 10, 2005, 03:47:58 PM »

Moneo,

I hoped you could test both functions, as I did myself. The first one should return correct answers (if you disregard leaplings), and I tested the second one, which returned an invalid age (always +1) after 20 thousand random dates (with checks).

Quote from: "Moneo"
By the way, your date of birth validation checks for a valid date. However, in the case of the given problem, it should also check that the date of birth is not in the future. Do you agree?

Yes actually I should have implemented it.


I'll update you soon with something new.
Logged
Pages: [1] 2 3
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!