954,480 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Problem calculating days between 2 dates

Hi everyone!
I'm trying to learn C from my dad's old college textbooks, and I'm doing some of the problems he had to do. This problem is meant to calculate the number of days between two dates given by the user. I made a function to account for leap years, and to input the data. My program is running, but is coming up with numbers that are just a few days off. I already wrote this program in Pascal, and it works, but I'm trying to practice it in C.

Here's the source code.

/*This program counts the days between two dates input by the user*/
#include <stdio.h>

int yr1; /*global variables because all these need to be visible by multiple functions*/
int yr2; /*I don't know how to use pointers to return more than 1 variable from a function*/
int m1;
int m2;
int d1;
int d2;
int leap;

main()
{
      int numdays [13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /*13 members*/
      int totaldays; /*so that 1 would match up with January, fixing notation problems*/
      int year;
      int month;
      int day; 
      inputdata();
      for (year = (yr1 + 1); year < yr2; year ++) /*processes complete years*/
      {
          leapyr(year);
          if (leap == 1)
             totaldays += 366;
             else totaldays += 365;
      }
      year = yr1;
      for(month = m1 + 1; month <= 12; month++) /*processes incomplete year 1*/
      {
          leapyr (year);
          if (leap == 1)
             numdays[2] = 29;
             else numdays[2] = 28;
          totaldays = totaldays + numdays[month];
      }
      month = m1;
      for(day = d1; day <= numdays [month]; day++) /*processes incomplete month 1*/
      {   
          leapyr (year);
          if (leap == 1)
          numdays[2] = 29;
          totaldays += 1;
      }

      year = yr2;
      for(month = m2 - 1; month >= 1; month--) /*processes incomplete year 2*/
      {
          leapyr (year);
          if (leap == 1)
          numdays[2] = 29;
          totaldays += numdays[month];
      }
      month = m2;
      for(day = d2; day > 1; --day) /*processes incomplete month 2*/
      {
          totaldays += 1; /*no need for leapyr function here- don't need to know month max*/
      }
      printf("Total number of days between two given dates is: %d days", totaldays);
      getch();
          
          
}

int inputdata() /*function works as planned- already tested*/
{
     printf("This program calculates the number of days between two given dates\n");
     printf("Enter beginning date in form month/day/year: ");
     scanf( "%d/%d/%d", &m1, &d1, &yr1);
     printf("Enter ending date in form month/day/year: ");
     scanf("%d/%d/%d", &m2, &d2, &yr2);
}

int leapyr (year)
{
    int leap = 0;
    if (year % 4 == 0)
       leap = 1;
       else
       if (year % 100 == 0)
          leap = 0;
          else
          if (year % 400 == 0)
             leap = 1;
    printf("leap is: %d\n", leap);
    return leap;
}


Thanks for the help!

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 

here's one problem that immediately jumps out:

leapyr (year);
if (leap == 1)


you need to assign the variable leap to the return value of the function

leap = leapyr(year)


but, more importantly, you should really consider using the standard C library < time.h >

pay attention to the time_t and tm structures. it will reduce your code to a few lines to accomplish the same thing.


.

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 

IMO the easiest way is to convert both date strings into time_t integers, then just subtract the two integers. That will give you the difference in seconds. After that its just dividing up the seconds into minutes, hours, and days.

The instructions say nothing about calculating the number of years between two dates. so leap years are not relevant to the problem.

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

time_t tokenizedate(const char* datestr)
{
    struct tm tm;
    memset(&tm,0,sizeof(struct tm));
    tm.tm_mday = ((datestr[0] - '0') * 10) + (datestr[1] - '0');
    tm.tm_mon = ((datestr[2] - '0') * 10) + (datestr[3] - '0') - 1;
    tm.tm_year = atoi(&datestr[4]) - 1900;
    return mktime(&tm);
}

int main()
{
    time_t t1, t2;
    char date1[40], date2[40];
    time_t seconds = 0, minutes = 0, hours = 0, days = 0, months = 0;
    printf("Enter first date (DDMMYYYY format)\n");
    fgets(date1, sizeof(date1), stdin);
    printf("Enter second date (DDMMYYYY format)\n");
    fgets(date2, sizeof(date2), stdin);
    t1 = tokenizedate(date1);
    t2 = tokenizedate(date2);
    seconds = t2 - t1;
    minutes = seconds / 60;
    hours = seconds /(60 * 60);
    days = seconds / (60 * 60 * 24);


}
Ancient Dragon
Retired & Loving It
Team Colleague
30,049 posts since Aug 2005
Reputation Points: 5,662
Solved Threads: 2,343
 
you need to assign the variable leap to the return value of the function .

I may be showing my ignorance... I thought return leap; was assigning leap the the return value of the function. Or is that something different?

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 

I've never dealt with the library functions in this program... I've only been programming in C for a couple days actually... So how can I figure out the functions in the library? Right now some of this is just gibberish to me.... Maybe it's just because I haven't had much experience yet though.

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 

ahhh... i see what you're trying to do.... i wasnt really paying attention ... and no, what you're doing is not quite right.

think of this:

returnValue = myFunction(argument);


whatever the function *returns* is assigned via the assignment operator, in this case to the variable "returnValue".

the variable you pass in to the function, the "argument" can either be an input or an output or both.

in your case, leapyr(leap); you are passing the *value* of the argument, which in your example is "leap". leap, in your case is strictly undefined in the "main" routine, you have not given it a value. it may be zero, it may be negative eleventy-thousand, you dont know.

your function "leapyr" gets this undefined "leap" value and throws it around and changes it to something meaningful, then tries to *return* it back to the calling function (main), who ignores it, since the return value is unassigned.

meanwhile, "main" still has the original, locally-scoped variable "leap" which isstill unknown, and anything that the "leapyr" function did to it was just temporary within the "leapyr" function, and so is lost on "leapyr"'s memory stack.

so, the easiest fix is to redefine your function, leapyr, to look like this:

int leapyr(void)
{
    int leap;   // locally defined, not the same variable in "main"

    // do your stuff

    return leap;
}


and when you call leapyr, call it like so

leap = leapyr();


it's very important that you understand this concept: the variable "leap" that you declared (but did not define) that is local to the "main()" function, will NOT be the same variable as "leap" defined local to the "leapyr" function. they will be two totally independent and completely unrelated variables, just like a guy named "Joe Smith" in New York is unrelated to some other "Joe Smith" in Los Angeles.

the only way they are connected, is that the numeric *VALUE* that the one contains is *RETURNED* through the function and that value is assigned to the other. the variables may as well have two different names, there would be no difference.

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 

I understand that declaring leap in the main function and in the leapyr function are different, but that's why I declared leap globally, which I know is bad practice, but I did it anyway. I thought that made leap visible to all functions, and thus any changes applied by one function could be seen by other functions. Is this in concept wrong?

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 
I've never dealt with the library functions in this program... I've only been programming in C for a couple days actually... So how can I figure out the functions in the library? Right now some of this is just gibberish to me.... Maybe it's just because I haven't had much experience yet though.

well, you're doing fine then. good job programming your day calculator "the hard way" :)

library functions are very powerful. essentially, they're just routines someone else has written to do some operation that is commonly used.

like "printf" is a library function (found in the library) to print stuff to the terminal. is another such library. learn the rules to use the functions in that library and life gets much easier.

look at Ancient Dragon's example above. it's probably a bit complex to you right now, but its easy to understand if you spend some time on it.

teh best way to learn is to use a debugger and "step through" the code one line at a time and watch the variables as they change values.

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 
I understand that declaring leap in the main function and in the leapyr function are different, but that's why I declared leap globally

good lord, i really am not paying attention, am i?

i'm sorry.

let me re-look at this.

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 

When I compiled this and added a few printf lines to help with the debugging before I asked for help, the leapyr function seemed to be working as planned. The problem was located somewhere else.

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 
When I compiled this and added a few printf lines to help with the debugging before I asked for help, the leapyr function seemed to be working as planned. The problem was located somewhere else.

no actually the problem is there. and it's related to what i was talking about, 'local scope'

you have the variable 'leap' declared (but not defined) globally. there's no telling what this value may be

THEN you declare the variable 'leap' as an integer, local to the function "leapyr". this function calculates whether or not the year is a leap year (incorrectly, i might add... more on that later).

your print statement within "leapyr" prints out the value it calculates, and then attempts to return that value to the calling function (main)

however, "main" is not accepting the return value, as i mentioned previously, because you have no assignment. you probably think that the value "leap", defined globally, is modifed to whatever the "leapyr()" function changed it to.

But this is not the case.

because "leap" in the function "leapyr" is declared locally, it is modified local to the function's local runtime stack, only. the global variable "leap" is untouched. Like my analogy of the two "Joe Smiths" living 3000 miles away. here is the danger of using the same variable names, you confuse the programmer.

the quickest fix is to completely remove the "int leap;" declaration in your "leapyr" function, then it will use the global variable.

that said, globally-scoped variables, except in certain circumstances when properly used, are generally a very poor way to program. you see you have so much trouble with this trivial program, imagine 50,000 lines of code littered with globals!

you have other problems that may not be noticed on your compiler: you dont initialize variables such as "totaldays". some compilers automatically initialize to zero. many do not. this code will be broken in many environments.

you need to declare your functions prototypes before being called. your compiler doesnt care, but many (most!) will. functions that are typed with a return value, must return that type value. "int inputdata" must return an int, or better yet, be declared as "void inputdata"

finally your leap year calculation is wrong. the case "year % 4 == 0" will always return a leap = TRUE, and the other conditionals will therefore always be ignored. it should be

leap = 0;  //always define vars first!
if (year % 4 == 0)
    leap = 1;
if (year % 100 == 0)
    leap = 0;
if (year % 400 == 0)
    leap = 1;


or, preferably:

if (year % 400 == 0)
    leap = 1;
else if (year % 100 == 0)
    leap = 0;
else if (year % 4 == 0)
    leap = 1;
else 
    leap = 0; // or force default defines!!

.

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 

man difftime
[edit] This has similarities to the original topic.

Slight nitpick:
IMO the easiest way is to convert both date strings into time_t integers, then just subtract the two integers.A time_t is not necessarily an integer: time_t (and clock_t ) "are arithmetic types capable of representing times;" where "[i]nteger and floating types are collectively called arithmetic types." The oddball method that comes to mind as a possible example is Excel's floating point date handling. It may be unlikely, but I believe that's why the standard library provides functions so we don't have to worry about these specifics.

Dave Sinkula
long time no c
Team Colleague
5,058 posts since Apr 2004
Reputation Points: 2,780
Solved Threads: 314
 

So here is my new leapyr function

int leapyr (year)
{
     leap =0;
     if (year % 4 == 0)
     leap = 1;
     if (year % 100 == 0)
     leap = 0;
     if (year % 400 == 0)
     leap = 1;
     printf("leap is: %d\n", leap);
}


It seems to work correctly, but the program is still returning incorrect numbers. For example, it says that the number of days between 1/1/2001 and 1/1/2002 is 364.

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 

looks good.

still, you should get in the habit of

(1) defining declared variables
(2) declaring prototypes of functions.
(3) returning values from functions according to prototype.

otherwise a bunch of minor short terms gains that you get away with on your current compiler will, eventually, come back and bite you in the ass for some long term pain :)


Also, I really suggest that you learn how to use standard libraries, like . the code snippet that Dave linked, above, is a concise and easy to understand example.

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 
#include <stdio.h>
#include <time.h>

int days_diff(int y, int m, int d)
{
    time+t now, then;
    struct tm date = {0};
    
    date.tm_year = y - 1900;
    date.tm_mon = m - 1;
    date.tm_mday = d;
    
    if  (time (&now) != (time_t) (-1) )
    {
        then = mktime ( &date );
        if (then != (time_t) (-1) )
        {
                 fputs(ctime(&now), stdout);
                 fputs(ctime(&then), stdout);
                 return difftime(now, then) / (24 * 60 * 60);
        }
    }
    return 0;
}

int main(void)
{
    printf("days = %d\n", days_diff(1970, 3, 8) );
    return 0;
}

/* my output
Mon Aug 22 11:51:06 2005
Sun Mar 08 00:00:00 1970
days = 12951*/


Unfortunately, I have no idea what this does. There are functions I have never seen before. Can you direct me to somewhere where I can learn these functions to avoid doing things the hard way? The book I have doesn't teach this.

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 
There are functions I have never seen before. Can you direct me to somewhere where I can learn these functions to avoid doing things the hard way?

http://www.google.com/search?q=man%20difftime
http://www.google.com/search?q=man%20mtkime
http://www.google.com/search?q=man%20ctime
(Note the pattern.)

These man pages tend to be system-specific. You may find a C standard here .

As you work with the functions from <time.h> , if you have questions, post away.

Dave Sinkula
long time no c
Team Colleague
5,058 posts since Apr 2004
Reputation Points: 2,780
Solved Threads: 314
 

Thank you!

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 

>>difftime()

I see absolutely no value in that function because all it does is subtract the two parameter values and return the result as a double. When time_t is an (unsigned)integer then the double return value is just plain inconvenient because it would have to be typecast back to time_t. So the program might as well just subtract the two time_t objects and be done with it.

Ancient Dragon
Retired & Loving It
Team Colleague
30,049 posts since Aug 2005
Reputation Points: 5,662
Solved Threads: 2,343
 

My function or Dave's function? I'm confused with both.

patrick k
Light Poster
31 posts since Apr 2009
Reputation Points: 10
Solved Threads: 1
 
My function or Dave's function? I'm confused with both.


Here's a quick attempt at adding comments:

#include <stdio.h>
#include <time.h>

int days_diff(int y, int m, int d)
{
   time_t now, then;
   struct tm date = {0}; /** Zero out the structure for later mktime() use.*/
   /**
    * Populate the year, month, and day of the structure -- accounting for the
    * standard manner for ranges.
    */
   date.tm_year = y - 1900;
   date.tm_mon  = m - 1;
   date.tm_mday = d;
   /**
    * Call time() to get the current time from which to obtain a difference.
    */
   if ( time ( &now ) != (time_t)(-1) )
   {
      /**
       * Attempt to convert the structure (previously populated with the year,
       * month, and day) into a time_t for use with difftime().
       */
      then = mktime ( &date );
      if ( then != (time_t)(-1) )
      {
         fputs(ctime(&now),  stdout); /** Merely display time/date "a". */
         fputs(ctime(&then), stdout); /** Merely display time/date "b". */
         /**
          * Find the difference "a" - "b".
          * The result of difftime() is a difference in seconds (and its type is
          * double). Dividing by seconds in a day is done to get number of days.
          */
         return difftime(now, then) / (24 * 60 * 60);
      }
   }
   return 0;
}

int main(void)
{
   printf("days = %d\n", days_diff(1970, 3, 8));
   return 0;
}
Dave Sinkula
long time no c
Team Colleague
5,058 posts since Apr 2004
Reputation Points: 2,780
Solved Threads: 314
 

This article has been dead for over three months

Post: Markdown Syntax: Formatting Help
You