Sign in to follow this  

Calculating number of days between two dates.

This topic is 4708 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Does anybody knows a good way to calculate the number of days between two given dates that takes into account leap years? (not using any already existing library, just plain c++) mm/dd/yyyy 12/09/2004 - 02/29/1246 = ?(days) Or better yet, a good way of calculating the correct day of month of a resulting difference between a date and a given number of days. 02/29/1246 - 4936(days) = mm/??/yyyy I'm bored so I'm making a c++ class to handle date operations/parsing as easily as possible, using overloaded operators, etc. I'm not worried about speed/memory performance so I'm planning to store years, months, days, ..., seconds as integers. I was thinking about storing the data as an array of bytes but different processor architectures could be an issue here. I'm planning on releasing it to the public domain if I ever finish it. Any constructive suggestions will be appreciated. [Edited by - owl on January 17, 2005 12:31:37 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by owl
Does anybody knows a good way to calculate the number of days between two given dates that takes into account leap years? (not using any already existing library, just plain c++)

mm/dd/yyyy
12/09/2004 - 02/29/1246 = ?(days)


Couldn't you just do 12/09/2004 - 02/29/1246 + (2004 - 1246) / 4
?

It's late so if the above text makes no sense, sorry :P

Share this post


Link to post
Share on other sites
@load_bitmap_file: Yes that could do the trick, but there is more about leap years than a period of 4 years between each one.

I've been reading some docs, and it seems to be a whole issue with date calculation. Smart people trough centuries have stated the following rules to calculate leap years:

- Most years divisible by 4 are Leap Years (i.e. 1996 was)
- However, most years divisible by 100 are NOT! (1900 was not)
- Unless they are also divisible by 400 (2000 will be)
- Every year which is divisible by 4000 is not a leap year.
source

So I was wondering how am I going to put all this together...

Share this post


Link to post
Share on other sites
From Wikipedia:

"The Gregorian calendar adds an extra day to February, making it 29 days long, in years divisible by 4, excluding years divisible by 100, but including years divisible by 400."

That would translate to this in code I believe:

bool IsLeapYear(const int& year)
{
return ((year % 400) == 0) || ((year % 4) == 0) && !((year % 100) == 0);
}

Share this post


Link to post
Share on other sites
Heres a nice way.

count += (int)(year * 365.256 + 0.5)
count += daysinmonth[month]
count += Days

Scount += (int)(Syear * 365.256 + 0.5)
Scount += daysinmonth[smonth]
Scount += Sdays

Daysdif = Scount - Count.

Easy
Fast
Affordible.
Even calculates that extra day every 6000 years!

Buy it now, for just the low low price of $0.00 (+ a +6 rating).

Edit: Silly mistake. Sorry.

From,
Nice coder

[Edited by - Nice Coder on January 17, 2005 3:18:35 AM]

Share this post


Link to post
Share on other sites
Its the first thing i thought of. Great minds think alike, eh?


//In init
month[0] = 31
month[1] = 28
month[2] = 30
month[3] = 31
month[4] = 30
month[5] = 31
month[6] = 30
month[7] = 31
month[8] = 30
month[9] = 31
month[10] = 30
month[11] = 31

//in routine

//Days = Paramiter, 16bit int
//Sdays = Same, just for the other date
// m = month number, 0-11
//sm = same, for the other date
Const double dy = 365.256363051 // A sidereal year, which should be what you want. I'm not sure if a double is accurite enough, tho. But it probably won't be a problem, if you arn't going to use it in the year 10Billion.

days += (int)(year * dy + 0.5);
days += month[m];

Sdays += (int)(Syear * dy + 0.5);
Sdays += month[sm];

Return (int16abs(Days - Sdays))


This should be right. (i'm typing it strait into the box, so there might be a few errors).

// Made it more accurite
From,
Nice coder

[Edited by - Nice Coder on January 17, 2005 4:52:32 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Nice Coder
Heres a nice way.

count += (int)(year * 365.256)
count += daysinmonth[month]
count += Days

Scount += (int)(Syear * 365.256)
Scount += daysinmonth[smonth]
Scount += Sdays

Daysdif = Scount - Count.

Easy
Fast
Affordible.
Even calculates that extra day every 6000 years!

Buy it now, for just the low low price of $0.00 (+ a +6 rating).

From,
Nice coder


Thanks everyone for posting in.

I guess "days" and "sdays" are the day number of date and sdate. Your code seems to work amazingly well, but looks like the leap years come 1 year later. I tried the values 2004,31,01 and 2005,31,01 (year, daysinmonth, days) and it returns 365, while 2003,31,01 and 2004,31,01 returns 366. But the leap year was 2004 and not 2003. Should I add 1 to the years passed or am I doing something wrong?

Share this post


Link to post
Share on other sites
Quote:
Original post by owl
Should I add 1 to the years passed or am I doing something wrong?

Just a shot in the dark, but you could try a nearest rounding instead of truncation when converting years to days.

(int)(year * 365.256 + 0.5)

instead of

(int)(year * 365.256)

I'm not entirely sure how my code does it (I'm converting dates to UNIX time), but I think it's using nearest rounding, and my times are off by just a second or so (just a rough implementation so far, so it works quite good in my oppinion) so it seems to handle leap years fine.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Shouldn't the 'daysinmonth' be cumulative? o_O


What you mean? daysinmont is an array[12] that holds how many days each month of a year has according to Gregory Peck. ;)

@Bob: If i round the calculation, the whole leap year thing will be gone. It will always return 365. If I substract 1 to each year passed then it works perfect.

Share this post


Link to post
Share on other sites
All I have to figure now is how to calculate the correct date that is the result of substracting n days from some other date taking leap years into account too.

01/01/0001 - n(days) = ??/??/????

I'm considering handling BC dates as negative years...

Advice on this will be appreciated too :D

Share this post


Link to post
Share on other sites
Quote:
Original post by Kylotan
I don't mean to rain on your parade, but I'm curious as to why you're duplicating the efforts in the Boost library?


I dunno, for fun I guess. I don't want to make a huge complex library as Date_Time, just a simple/intuitive class (for dummies) that can perform the most common operations on any *Gregorian* kind of date (BC/AD).

Share this post


Link to post
Share on other sites
Surely there's no reason to do time/date math by hand (a sure way to lose one's mind in the long run) when there are standard facilities in the <time.h> / <ctime> header just for that purpose!

I *strongly* recommend representing your dates as the standard type time_t (UNIX timestamp, number of seconds since 00:00:00 1970/01/01; a simple integer type on most systems). It's a *lot* easier, shorter, faster, less bug-prone and takes less memory than storing the parts separately as integers.

EDIT: Oh well, this approach won't do much good if you want to have dates outside the size_t's range...

Share this post


Link to post
Share on other sites
Quote:
Original post by Sharlin
(UNIX timestamp, number of seconds since 00:00:00 1970/01/01; a simple integer type on most systems). It's a *lot* easier, shorter, faster, less bug-prone and takes less memory than storing the parts separately as integers.


But what would be of the poor historian-programmers then? :(

Or old programmers that want to remember the good ol' 50-60's?

Share this post


Link to post
Share on other sites
Yeah, I realised that almost as I hit "reply", re-reading your original message and seeing the dates you used as an example... Edited my message to reflect that. Still, I'd say that a third-party library is better than doing all the dirty stuff yourself. If not boost, then something else.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nice Coder
Its the first thing i thought of. Great minds think alike, eh?


//In init
month[0] = 31
month[1] = 28
month[2] = 30
month[3] = 31
month[4] = 30
month[5] = 31
month[6] = 30
month[7] = 31
month[8] = 30
month[9] = 31
month[10] = 30
month[11] = 31

// ...


This should be right. (i'm typing it strait into the box, so there might be a few errors).

// Made it more accurite
From,
Nice coder


Oups.... I believe this should be

month[0] = 31;
month[1] = 28;
month[2] = 31; // march is 31 days
month[3] = 30;
month[4] = 31;
month[5] = 30;
month[6] = 31; // july is 31 days
month[7] = 31; // august is 31 days too
month[8] = 30;
month[9] = 31;
month[10] = 30;
month[11] = 31;


Regards,

Share this post


Link to post
Share on other sites
You should use cumulative months and you should use different month-array for leap years [1]. You should base the year length on the rules of computing leap years instead of sidereal year [2]. You should do pure integer math instead of float math to make sure you won't get errors due to lack of accuracy [3]. Ugh.

[1] Think about it, if just for a second. The way you're doing it now, the difference between January 1st and December 1st of same year will be 0 days.

[2] I'll go easy on you: 365 + 1/4 - 1/100 + 1/400 - 1/4000

[3] Just multiply the above summation by "year" without using floats. I know you can do it!

Share this post


Link to post
Share on other sites
Quote:
Original post by Nemesis2k2
That would translate to this in code I believe:

*** Source Snippet Removed ***
This kind of exception chain screams for XOR.

Share this post


Link to post
Share on other sites
Quote:
Original post by civguy
You should use cumulative months


Yes I became aware of this right after I replied Zahlman. :)

Quote:
Original post by civguy
and you should use different month-array for leap years


I didn't think of this tough... tnx :) EDIT: Maybe incrementing the first array values by one (after january) on leap years could work too?

Quote:
Original post by civguy
[1]. You should base the year length on the rules of computing leap years instead of sidereal year [2]. You should do pure integer math instead of float math to make sure you won't get errors due to lack of accuracy [3]. Ugh.

[1] Think about it, if just for a second. The way you're doing it now, the difference between January 1st and December 1st of same year will be 0 days.

[2] I'll go easy on you: 365 + 1/4 - 1/100 + 1/400 - 1/4000

[3] Just multiply the above summation by "year" without using floats. I know you can do it!


Yes, this is what I was planning to do, but Nice Coder's code looked quite nice, at least until 1500+- BC. Anyway your advice feels sane, I think I'll follow it. :)

How about date dec/incrementation by a given amount of days? Should I calculate the amount of years a certain number of days represent, add that number to the original date's year value and then increment months and days with the reminding days? (always, somehow, taking leap days into account?)

Thanks for your help. You're being rated.

Share this post


Link to post
Share on other sites
Quote:
Original post by civguy
Quote:
Original post by Nemesis2k2
That would translate to this in code I believe:

*** Source Snippet Removed ***
This kind of exception chain screams for XOR.

Nice catch. It doesn't preserve every condition, but you get away with it because something that's divisible by 100 is always divisible by 4, so that case never occurs.

Share this post


Link to post
Share on other sites

This topic is 4708 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this