Slackware This 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.
Are you new to LinuxQuestions.org? Visit the following links:
Site Howto |
Site FAQ |
Sitemap |
Register Now
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.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
|
|
|
11-28-2013, 11:33 AM
|
#1
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Rep:
|
A C program to find the difference between 2 dates,and a few of its applications
Hello!
I have developed a C program to find the difference between 2 dates.
https://github.com/aadityabagga/dur
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.
Quote:
1.)To find the last upgrade time with slackpkg.
A bash function for it-
function lastupt()
{
updated=`date --date=@$(cat /var/lib/slackpkg/LASTUPDATE) +%F`
today=`date +%F`
echo "Last update was`dur $updated $today` ago"
}
This can be added to ~/.bashrc and called with $ lastup
(dur, the compiled C program, has been copied to /usr/bin)
2.)As a reminder manager.
a)A script for it-
#!/bin/bash
#A script to act as a reminder
eventname="Exam"
eventdate="2013-12-08"
today=`date +%F`
echo "$eventname is`dur $today $eventdate` away"
read #To wait for the user to close it.
exit 0
The eventname and eventdate can be modified.
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.
But I didnt know about that when starting out
Screenshots below.
http://s1198.photobucket.com/user/ch...a/dur.png.html http://s1198.photobucket.com/user/ch...stupt.png.html
http://s1198.photobucket.com/user/ch...mind.png.html] http://s1198.photobucket.com/user/ch...conky.png.html
Last edited by aaditya; 11-28-2013 at 02:56 PM.
|
|
|
11-28-2013, 12:21 PM
|
#2
|
LQ Veteran
Registered: May 2008
Posts: 7,099
|
Quote:
Originally Posted by aaditya
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.
|
|
|
11-28-2013, 01:31 PM
|
#3
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Quote:
Originally Posted by GazL
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.
|
Ah
I learnt many things also.
Indeed I had seen that thread http://www.linuxquestions.org/questi...on-4175482477/, but somehow missed your program.
Now I checked it.
Thanks
|
|
|
11-28-2013, 01:42 PM
|
#4
|
LQ Veteran
Registered: May 2008
Posts: 7,099
|
Quote:
Originally Posted by aaditya
|
Yep, I did a couple of revisions after that trying alternate approaches to see which I liked the best.
|
|
|
11-28-2013, 01:45 PM
|
#5
|
Member
Registered: Oct 2011
Location: Texas, USA
Distribution: LFS-SVN, Gentoo~amd64, CentOS-7, Slackware64-current, FreeBSD-11.1, Arch
Posts: 229
Rep:
|
Quote:
Originally Posted by aaditya
|
I have two suggestions to improve you code:
1). Use int main() rather than void main(). See this article:
http://c-faq.com/~scs/readings/voidmain.960823.html
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.
Last edited by re_nelson; 11-28-2013 at 01:49 PM.
|
|
1 members found this post helpful.
|
11-28-2013, 02:20 PM
|
#6
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Quote:
Originally Posted by re_nelson
I have two suggestions to improve you code:
1). Use int main() rather than void main(). See this article:
http://c-faq.com/~scs/readings/voidmain.960823.html
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
Code:
gcc -o dur dur.c
/tmp/cc1dOfR2.o: In function `to_int':
dur.c:(.text+0xa8): undefined reference to `pow'
collect2: error: ld returned 1 exit status
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'
Last edited by aaditya; 11-28-2013 at 02:29 PM.
|
|
|
11-28-2013, 02:46 PM
|
#7
|
Senior Member
Registered: Oct 2003
Location: Northeastern Michigan, where Carhartt is a Designer Label
Distribution: Slackware 32- & 64-bit Stable
Posts: 3,541
|
There is nothing wrong with declaring
Code:
void main (int argc, char *argv [])
if you use the exit() function:
Code:
/* exit on a failure */
exit (EXIT_FAILURE);
/* exit successfully */
exit (EXIT_SUCCESS);
An example might be attempting to open a file that does not exist or is not readable:
Code:
/* open the input file */
if ((in = fopen (argv [optind], "r")) == (FILE *) NULL) {
(void) fprintf (stderr,
"%s:\tcan't open %s\n",
argv [0], argv [optind]);
exit (EXIT_FAILURE);
}
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.
Hope this helps some.
Last edited by tronayne; 11-29-2013 at 07:50 AM.
|
|
|
11-28-2013, 03:05 PM
|
#8
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Thanks for the insight tronayne
|
|
|
11-28-2013, 03:07 PM
|
#9
|
Senior Member
Registered: Oct 2003
Location: Northeastern Michigan, where Carhartt is a Designer Label
Distribution: Slackware 32- & 64-bit Stable
Posts: 3,541
|
Nice job with the program.
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.
|
|
1 members found this post helpful.
|
11-28-2013, 03:19 PM
|
#10
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Quote:
Originally Posted by tronayne
Nice job with the program.
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 )
|
|
|
11-28-2013, 03:24 PM
|
#11
|
LQ Veteran
Registered: May 2008
Posts: 7,099
|
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.
|
|
|
11-28-2013, 03:41 PM
|
#12
|
Senior Member
Registered: Oct 2003
Location: Northeastern Michigan, where Carhartt is a Designer Label
Distribution: Slackware 32- & 64-bit Stable
Posts: 3,541
|
OK, the Julian Day Number is described in a Wikipedia article at http://en.wikipedia.org/wiki/Julian_day
plus the Modified Julian Date is discussed in a US Naval Observatory article at http://tycho.usno.navy.mil/mjd.html.
All of my stuff is Julian Day number (I do use Modified Julian Date for other purposes as describe in the Naval Observatory article).
Here is the code for ndays.c:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
static time_t julday (int, int, int);
void main (void)
{
int ldd, lmm, lyy;
int udd, umm, uyy;
(void) fprintf (stdout, "Enter Lower Date (MM/DD/YYYY): ");
(void) scanf ("%d/%d/%d", &lmm, &ldd, &lyy);
(void) fprintf (stdout, "Enter Upper Date (MM/DD/YYYY): ");
(void) scanf ("%d/%d/%d", &umm, &udd, &uyy);
(void) fprintf (stdout, "Number of Days: %ld\n",
julday (umm, udd, uyy) - julday (lmm, ldd, lyy));
}
/* Gregorian Calendar adopted 15 Oct 1582 */
#define IGREG (15+31L*(10+12L*1582))
static time_t julday (int mm, int id, int iyyy)
{
time_t jul;
int ja, jy, jm;
if (iyyy == 0) {
(void) fprintf (stderr, "julday:\tthere is no year zero\n");
exit (1);
}
if (iyyy < 0)
++iyyy;
if (mm > 2) {
jy = iyyy;
jm = mm + 1;
} else {
jy = iyyy - 1;
jm = mm + 13;
}
jul = (time_t) (floor (365.25 * jy) +
floor (30.6001 * jm) + id + 1720995);
if (id + 31L * (mm + 12L * iyyy) >= IGREG) {
ja = 0.01 * jy;
jul += 2 - ja + (int) (0.25 * ja);
}
return (jul);
}
#undef IGREG
You compile it with
Code:
cc -o ndays ndays.c -lm
You execute it
Code:
ndays
Enter Lower Date (MM/DD/YYYY): 01/01/1901
Enter Upper Date (MM/DD/YYYY): 11/28/2013
Number of Days: 41239
Which is the number of days since the beginning of the 20th century until "today" (2013-11-28).
There's a lot of fiddling you can do with Julian day numbers (if you need a converter to go from Julian Day to Gregorian date, let me know and I'll post it for you).
Hope this helps some.
|
|
1 members found this post helpful.
|
11-28-2013, 03:50 PM
|
#13
|
Member
Registered: Oct 2011
Location: Texas, USA
Distribution: LFS-SVN, Gentoo~amd64, CentOS-7, Slackware64-current, FreeBSD-11.1, Arch
Posts: 229
Rep:
|
Quote:
Originally Posted by aaditya
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.
I enjoyed the program and found that I'm now 22126 day(s) old!
|
|
1 members found this post helpful.
|
11-29-2013, 01:20 AM
|
#14
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Quote:
Originally Posted by re_nelson
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 [...]
|
Ah, I understand. I will use it now onwards
Quote:
I enjoyed the program and found that I'm now 22126 day(s) old!
|
Hehe, that made me smile widely
Thank You
|
|
|
11-29-2013, 02:19 AM
|
#15
|
Member
Registered: Oct 2013
Location: India
Distribution: Slackware
Posts: 272
Original Poster
Rep:
|
Quote:
Originally Posted by tronayne
OK, the Julian Day Number is described in a Wikipedia article at http://en.wikipedia.org/wiki/Julian_day
plus the Modified Julian Date is discussed in a US Naval Observatory article at http://tycho.usno.navy.mil/mjd.html.
All of my stuff is Julian Day number (I do use Modified Julian Date for other purposes as describe in the Naval Observatory article).
You execute it
Code:
ndays
Enter Lower Date (MM/DD/YYYY): 01/01/1901
Enter Upper Date (MM/DD/YYYY): 11/28/2013
Number of Days: 41239
Which is the number of days since the beginning of the 20th century until "today" (2013-11-28).
There's a lot of fiddling you can do with Julian day numbers (if you need a converter to go from Julian Day to Gregorian date, let me know and I'll post it for you).
Hope this helps some.
|
I had a look at the Wikipedia article. Although I dont think I have need to use the precision myself, but I thought about using your program to verify if my program gives the correct difference or not
The output of the program is the difference in Julian day numbers, right?
Ah, yes I think thats it
Code:
./ndays
Enter Lower Date (MM/DD/YYYY): 01/01/2013
Enter Upper Date (MM/DD/YYYY): 29/11/2013
Number of Days: 865
Oops, I got it wrong!
Code:
./ndays
Enter Lower Date (MM/DD/YYYY): 01/01/2013
Enter Upper Date (MM/DD/YYYY): 11/29/2013
Number of Days: 332
and
Code:
dur 1901-01-01 `date +%F`
41241 day(s)
So there just seems to be a difference of 2 days or 0.005% error approx
Thanks
Last edited by aaditya; 11-29-2013 at 03:00 AM.
|
|
|
All times are GMT -5. The time now is 08:41 PM.
|
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.
|
Latest Threads
LQ News
|
|