[SOLVED] A C program to find the difference between 2 dates,and a few of its applications

User Name

Remember Me?

Password

SlackwareThis Forum is for the discussion of Slackware Linux.

Notices

Welcome to LinuxQuestions.org, a friendly and active Linux Community.

You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!

Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.

If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.

Having a problem logging in? Please visit this page to clear all LQ-related cookies.

Introduction to Linux - A Hands on Guide

This guide was created as an overview of the Linux Operating System, geared toward new users as an exploration tour and getting started guide, with exercises at the end of each chapter.
For more advanced trainees it can be a desktop reference, and a collection of the base knowledge needed to proceed with system and network administration. This book contains many real life examples derived from the author's experience as a Linux system and network administrator, trainer and consultant. They hope these examples will help you to get a better understanding of the Linux system and that you feel encouraged to try out things on your own.

It took some time and effort (its 200 lines of code + testing for different cases!(also available)), but finally I made it!

Code:

//A program to calculate the no of days between 2 dates in format yyyy-mm-dd
//Takes 2 command line args- initial date and final date
//Copyright (C) 2013 Aaditya Bagga aaditya_gnulinux@zoho.com
/*This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed WITHOUT ANY WARRANTY;
without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "to_int.h"
int d=0; //to store the output,ie, difference in days
//Make a structure for the date
struct date
{
int year;
int month;
int day;
}d1,d2;
//Make a macro for checking leap year
#define is_leap(year) (((year%4==0)&&((year%100)!=0)) || ((year%400)==0))
//Make a macro for checking elapsed days
#define check_elapsed_days(days) (days)
//Protoypes for functions
void check_months(int,int,int,int,int);
void diff_years(int,int);
int main(int argc, char* argv[])
{
if(argc != 3 ) {
printf("Invalid number of arguments\n");
exit(1);
}
//Extract the year,month,day components from the date
char yi[5],yf[5],mi[3],mf[3],di[3],df[3]; //size+1 for null character at the end
strncpy (yi, argv[1], 4);
strncpy (mi, argv[1]+5, 2);
strncpy (di, argv[1]+8, 3);
strncpy (yf, argv[2], 4);
strncpy (mf, argv[2]+5, 2);
strncpy (df, argv[2]+8, 3);
yi[4]='\0'; //insert null character at the end
mi[2]='\0';
yf[4]='\0'; //insert null character at the end
mf[2]='\0';
//Convert the string date components to int and assign them to the structure elements
d1.year=to_int(yi);
d1.month=to_int(mi);
d1.day=to_int(di);
d2.year=to_int(yf);
d2.month=to_int(mf);
d2.day=to_int(df);
//store difference b/w the date elements
int dy=d2.year-d1.year;
int dm=d2.month-d1.month;
int dd=d2.day-d1.day;
//*Now the date part
//int flag=0; //to check for wrong dates: currently the program is non-interactive so its not being implemented yet
//Procedure:find diff in year -> find diff in month -> find diff in days
//diff in year: find diff in year -> diff in month -> diff in days
//diff in months -> find diff in months -> diff in days
if(dy==0) //Year same
{
//Check difference in months
if(dm==0) //Month same
{
d=dd; //output=diff in days
//done
}
else
{
check_months(d1.year,d1.month,d2.month,d1.day,d2.day);
}
}
else //There is Difference in Years
{
//Check if there is diff in years = 1 year, or more
if(dy==1)
{
//Only diff in months need to be checked
check_months(d1.year,d1.month,12,d1.day,31);
check_months(d2.year,1,d2.month,0,d2.day); //0 is used as initial day to compensate for the day being lost due to 2 function calls to check_months
}
else
{
diff_years(d1.year,d2.year); //Check diff in years
}
}
//Print the output
printf(" %d day(s)\n",d);
exit(0);
}
int check_days(int year,int month) //find the no of days in a month
{
int leap=is_leap(year); //check if its leap year
switch(month)
{
case 1:case 3: case 5:case 7: case 8: case 10: case 12:
return 31;
case 4: case 6: case 9:case 11:
return 30;
case 2:
if(leap)
return 29;
else
return 28;
default: return 0;
}
}
int check_remaining_days(int year,int month,int day)
{
int days_in_month=check_days(year,month);
return(days_in_month-day);
}
void check_months(int yr,int mi,int mf,int di,int df)
{
//This function has been made in such a way that mf>=mi, if the opposite is true, display a message to the effect.
if(mi>mf)
{
printf("Did you enter the date correctly? Its like first earlier date, then later date.\n");
exit(1);
}
if(mf==1)
{
//if mf=1,ie,final month is january, then the days calculated as days in current month which is done at the end
}
else
{
d=d+check_remaining_days(yr,mi,di); //Add the days in current month
}
//Days in current month added, move on to the next months
mi=mi+1; //Increment the month as days in current month have been added
while(mi<mf)
{
d=d+check_days(yr,mi); //add the days of the month
mi=mi+1; //now increment to check for next month
}
//Days in in-between months added; now add days in final month
if(mi==13)
{
//In this case initial month was 12,ie,december,and the days are calculated at the top as remaining days
}
else
{
d=d+check_elapsed_days(df); //add the days from the final month
}
}
void diff_years(int yi,int yf)
{
int dy=yf-yi; //Difference in years
while(dy>1)
{
if (is_leap((yi+1))) //Check if next year is leap or not
d=d+366; //Add the no of days in the year
else
d=d+365; //Add the no of days in the year
yi=yi+1; //Increment the year to check for next year
dy=yf-yi; //Recalculate the difference
}
//done with the difference in years
//now need to check the difference b/w months
check_months(yi,d1.month,12,d1.day,31);
check_months(yf,1,d2.month,0,d2.day); //0 is used as initial day to compensate for the day being lost due to 2 function calls to check_months
}

You can download the binary from the link above (dur for x86_64, dur32 for x86), or you can compile it on your own machine as (after saving it as dur.c)-

Code:

gcc -lm -o dur dur.c

(you will also need to have the to_int.h file obtained from the repo link given above, to be present in the same directory as dur.c)

Then to use it-dur yyyy-mm-dd yyyy-mm-dd
where the first date is the earlier date and the 2nd date is the later date.
for eg,

Code:

./dur 2013-11-28 2013-11-29
1 day(s)

Applications-
I thought of a few ways to use this
This quotes from the use-cases.txt file that is present in the source.

This can be saved as a file named "remind" inside a folder named "scripts" in your home directory, and made executable as chmod +x ~/scripts/remind

The above script can be added to autostart, so that the reminder is displayed at every boot.

for eg, I have added this the following in my autostart
xterm -e "/home/aaditya/scripts/remind"

b)To be displayed as a Conky element

I have the following in my ~/.conkyrc
${font Cantarell:size=12}Exam: $alignr ${execi 3600 dur `date +%F` 2013-12-08}

Here Exam is the name of the event, and 2013-12-08 is the date of the event, ie exam.
This updates itself every hour, or 3600 seconds.
(I have copied the compiled file dur to /usr/bin so that I can call it with conky)

(Perhaps the former is not very relevant for slackware users)

It has been to my attention that there exits the standard C time library in which difftime returns the difference between two times.

It has been to my attention that there exits the standard C time library in which difftime returns the difference between two times.

But I didnt know about that when starting out

Well as long as you had fun writing it, that's the main thing.

Few weeks back I ended up writing some code to convert to and from roman numerals after we got chatting about it on this forum: I have absolutely no use for it whatsoever, but it was an interesting exercise, and it was more satisfying than a Crossword.

Few weeks back I ended up writing some code to convert to and from roman numerals after we got chatting about it on this forum: I have absolutely no use for it whatsoever, but it was an interesting exercise, and it was more satisfying than a Crossword.

2). Add #include <math.h> to haul in the declaration for the math functions.

I'll add that I applaud your efforts for doing this in C. It would be just a few lines of code in a higher level language such as Perl or Python but I think it's a good exercise of programming skills to do so in C.

2). Add #include <math.h> to haul in the declaration for the math functions.

I'll add that I applaud your efforts for doing this in C. It would be just a few lines of code in a higher level language such as Perl or Python but I think it's a good exercise of programming skills to do so in C.

Changed void main() to int main() [I didnt know/realise it was error-prone, thx for the link]

I include to_int.h ,which itself includes math.h and string.h
Do I need to include it again?
If you mean the following

I checked including math.h doesnt make a difference.
When I faced that error I searched and found this which states that gcc optimises the pow() call if a constant is used, and to use -lm option in such a case.

Thanks for the help

P.S. I dont know perl or python

Edit-
Additionaly added exit_status' after reading your link and seeing GazL's program with the exit_status'

Calling the exit() function invokes fclose() for any open files. Production programs should invoke exit(), ferror(), possibly feof() and the like as well; that's probably a little overkill, but at least exit() should be called with a status argument (EXIT_SUCCESS or EXIT_FAILURE), that value is available to the calling process (as would a return() at the end of an int main() function. Including the error message at least gives and indication of what occurred.

I've been doing it for decades, since the advent of ANSI C (The C Programming Language (2nd ed.) on various Unix, Solaris and Linux systems with no problems (and on large production systems). I realize that it's gotten to be a dogma thing, but I really believe it's six of one, half dozen of the other -- do what you're comfortable with as long as it works; you need to invoke exit() and it's cousins in any event to cover all the bases.

Something you may want to think about if you're interested in long-term days, dates and calendars are Julian Day Numbers; today (2013-11-28) is Julian day 2456625. Julian day 0 is -4713-01-01 (that's 4713 BCE, a long, long time ago).

If you are interested, I'll post ndays.c which does quick conversion from Gregorian date to Julian day numbers and returns the number of days since the lower date. Let me know.

Something you may want to think about if you're interested in long-term days, dates and calendars are Julian Day Numbers; today (2013-11-28) is Julian day 2456625. Julian day 0 is -4713-01-01 (that's 4713 BCE, a long, long time ago).

If you are interested, I'll post ndays.c which does quick conversion from Gregorian date to Julian day numbers and returns the number of days since the lower date. Let me know.

Nice work.

Hope this helps some.

Thank You

I didnt know about Julian days, but the concept interests me, as I had initially tried to convert the date into a days only format, so that I could easily subtract the days, but I couldnt come up with a way to do it
(off to sleep now )

I'm still making my mind up about exit(). I tend to use it if I need a program to bail out mid-run, but for normal termination more often than not I tend to let the return at the end of main deal with it rather than stick an exit(EXIT_SUCCESS) at the end of main(). At the moment I'm very inconsistent about this. As an old mainframe guy it takes all my effort just to suppress the urge to return 4 for warnings and 16 on failure.

Changed void main() to int main() [I didnt know/realise it was error-prone, thx for the link]

It's a violation of the C standard to use the void main() signature. The fact that it "works" on most implementations is not relevant in terms of standard conformance. It comes at no cost and is the right thing to do. My personal preference is to always invoke the compiler with these flags:

Code:

gcc -ansi -pedantic [...]

Quote:

I include to_int.h ,which itself includes math.h and string.h

Sorry...I overlooked that since I simply clipped the code for the to_int function and hoisted it into the C source rather than using the include mechanism.

It's a violation of the C standard to use the void main() signature. The fact that it "works" on most implementations is not relevant in terms of standard conformance. It comes at no cost and is the right thing to do. My personal preference is to always invoke the compiler with these flags: