• Status: Solved
• Priority: Medium
• Security: Public
• Views: 268

# Using time.h

Hi there, I mentioned before that I'm doing a C course online & Im having  a problem with one of the exercises.

What the exercise is, is to take 2 dates and work out the difference.  The fuction follows:

void ageCalculator()
{
char birth_Date[11];
char test_Date[11];

printf("Age Calculator\n");
printf("Date of Birth = ");
scanf("%s", birth_Date);

printf("\nTest Date = ");
scanf("%s", test_Date);

struct tm *dob,*td;
time_t now;//date_of_birth, test_date;

//Initialize time structures
now = time(NULL);
dob = localtime(&now);
td = localtime(&now);

char p[3];
int day = atoi(birth_Date);

dob->tm_mday = day;

char *sub_string;

//Use strtok to look for the '/' delmiter
printf("%s\n\n", strtok(birth_Date,"/"));

//Loop through the remaining date string for month & year
//and assign to the time structure.
//If the token is greter than 2 digits long its the year
while ((sub_string = strtok(NULL, "/")) != NULL)
{
if(strlen(sub_string) > 2)
{
int year = atoi(sub_string);
dob->tm_year = year;
}
else
{
int month = atoi(sub_string);
dob->tm_mon = month;
}
}

//Populate the test date structure
char q[3];
int day2 = atoi(test_Date);

td->tm_mday = day2;

char *sub_string2;

//Use strtok to look for the '/' delimiter
printf("%s\n\n", strtok(test_Date,"/"));

//Loop through the remaining date string for month & year
//and assign to the time structure.
//If the token is greater than 2 digits long its the year
while ((sub_string2 = strtok(NULL, "/")) != NULL)
{
if(strlen(sub_string2) > 2)
{
int year = atoi(sub_string2);
td->tm_year = year;
}
else
{
int month = atoi(sub_string2);
td->tm_mon = month;
}
}

time_t y = mktime(dob);
if (y == -1)
{
printf("BUGGER");
}

}

Now, I get all the bits of the date properly ie  day month, & assign them to the time struct dob....

But the output I get is still "Bugger" meaning the time y hasnt been initialized properly.

Any ideas?
Thanks
0
Benjamin_Barrett
• 2
1 Solution

Commented:
There are 2 problems with your code :

1) the tm_year part of a tm struct should be the number of years since 1900, and tm_mon starts counting from 0 (ie. january is 0)

2) you do two localtime's in a row this way :

dob = localtime(&now);
td = localtime(&now);

The result is that dob and td point to the same memory block !! (the pointer returned is pointing to a statically allocated tm structure, and is overwritten on each call of gmtime, localtime and ctime). For more information, check this reference page :

http://www.cplusplus.com/ref/ctime/localtime.html

To fix 1), just adjust the values read in with scanf :

dob->tm_year = year - 1900;
dob->tm_mon = month - 1;

To fix 2) don't use a pointer returned by localtime(), but do it this way :

struct tm dob, td;

and acces them like this :

dob.tm_year

etc.
0

Commented:
A few more tips to clean up your code :

1) re-use your local (temporary) variables, or better, don't use an extra variable when you don't need one. A good example of this is that you use integers day and day2, while you could have just used one, day for example. A better solution would be that you drop the extra variable completely, ie. :

int day = atoi(birth_Date);
dob->tm_mday = day;

becomes :

dob->tm_mday = atoi(birth_Date);

Check the rest of the code for similar optimisations yourself ...

2) I suppose that :

char p[3];

and :

char q[3];

are leftovers from previous code ? They're not used any more, so you can leave them out.

3) This :

scanf("%s", birth_Date);

is very dangerous for buffer overflows : if a user enters a string longer than 10 characters, the memory just after the character array birth_Date will be overwritten !! Limit the number of characters a user can input, by either using :

scanf("%10s", birth_Date)

or :

fgets(birth_Date, 11, stdin);

4) your code now allows this date format :

dd/yyyy/mm

or even :

dddddd/yyy/mm

or :

dd//

The first is a design choice ... if you want the year to be in the second place too, then that's ok.
The second is a bit more dangerous, as the day can be bigger than 31, and the year smaller than 1900. Both will result in an invalid tm structure.
The fourth will set month and year to 0 ...

An elegant way of extracting data from a string is this :

int day, month, year;
char dat[11] = "01/02/2003";
sscanf(dat, "%02d/%02d/%04d", &day, &month, &year);
fprintf(stdout, "%d %d %d\n", day, month, year);

Don't forget to check the return value of sscanf() !!
0

Author Commented:
Cool, thanks heap Infinity. Especially for the coding tips. Im new to C & programming in general, so that stuff is gold to me

Benjamin
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.