[Webinar] Learn how to a build a cloud-first strategyRegister Now

x
Solved

# Time difference between two dates considering leap year -Urgent

Posted on 2011-05-02
Medium Priority
1,800 Views
The following j-script below calculates term in years, months and days. However, it is not working when there are leap years within the term. Here is an example of the behavior in the system with the script enabled. Clearly this is a 6 year lease, not a “5 Years, 11 Months, 28 Days” term:.

How I can I add leap year in following code.
here code I am using

/* Function calculates difference between Commencement and Expiry date and displays in the format 'X Yrs,  Y Mos,  Z Days' */
DateDifference = function(commence, expiry)
{
if(commence == null || expiry == null)
{
return '0 Yrs  0 Mos  0 Days';
}
else
{
// Difference between 2 dates
var diffDate =  expiry - commence;

// Years
var years = diffDate/31536000000;
// Months
var months = (diffDate % 31536000000)/2628000000;
// Days
var days = ((diffDate % 31536000000) % 2628000000)/86400000;

// Result string
var result =  Math.floor(years) + " Yrs, " + Math.floor(months) + " Mos, " + Math.floor(days) + " Days";

return result;
}
}

Thanks
Masood

Date-difference.docx
0
Question by:mas1963
• 12
• 11
• 11
• +2

LVL 33

Expert Comment

ID: 35505555
What inputs does the function take -- by this I mean, what format are the commence and expiry parameters in?
0

LVL 9

Expert Comment

ID: 35505602
Would it be worth separating the year (2011) and then going through a for(var i=startyear; i<=endyear; i++) { } loop checking the year? If it is a leap year, add 86400000 (86400 seconds in a day, what are the extra three 0's for?).

Leap years are every 4 years, except years divisible by 100 unless they are also divisible by 400. (2000 is, 2100 isn't, 2200 isn't, 2300 isn't, 2400 is) so 2096 is before 2104 for leap years.

Also, this will never be entirely accurate in its current state. You're assuming that months have 30.416 days. No months have that.

It may be better to do, and this is not code, just logic:

years = endyear - startyear;
months = endmonth - startmonth; If months < 0 { years--; months=12+months; (the negative creates a number lower than 12) }
days = enddays - startdays; If days < 0 { months--; if months < 0 { years--; months=12-months; } days=(days in the month)-days; }

Is this all going to be client-side processing? If not, use whatever server-side language you're using to do this.

There are dozens of these kinds of things already made: http://ditio.net/2010/05/02/javascript-date-difference-calculation/ -- whether or not they take into account leap years is another issue.
0

LVL 33

Expert Comment

ID: 35505627
>> ...  this will never be entirely accurate in its current state.  You're assuming that months have 30.416 days.

I agree, and if you are going to make this assumption, you may as well also assume that a year has 31557600000ms instead of 31536000000ms.  (Since a year is actually closer to 365.25 days.)  This might improve the accuracy somewhat, but it won't be exact.
0

Author Comment

ID: 35505639
I will appreicate if you can provide me working code as I need it urgent.
stare date is 1/1/ 2011 and expiry as 12/31/2016 ( dd/mm/yyyy) format

Thanks
Mas
0

Author Comment

ID: 35505715
I will be happy if you can change the logic which I have and add the logic of checking he leap year to calculate the date difference.
0

LVL 9

Expert Comment

ID: 35505840
Very quickly thrown together and tested. This is basing on you inputting as DATE FORMATS as you have said above and not as integers, as your code implies. You can add variables to use the information in other days. It also features a very (VERY) simple date verification, so you can't put the end date as sometime in the past, or enter February 29th UNLESS it is a leap year.

I have not added month checks (1-12) or year checks.

``````<script type='text/javascript'>
//1/1/ 2011 and expiry as 12/31/2016

var startDate='01/01/2011';
var endDate='12/31/2016';

var startExplode=startDate.split('/');
var startYears=parseInt(startExplode[2],10);
var startMonths=parseInt(startExplode[0],10);
var startDays=parseInt(startExplode[1],10);
var endExplode=endDate.split('/');
var endYears=parseInt(endExplode[2],10);
var endMonths=parseInt(endExplode[0],10);
var endDays=parseInt(endExplode[1],10);
startDate=new Date(startDate).getTime();
endDate=new Date(endDate).getTime();

if((startYears < endYears || startMonths < endMonths || startDays < endDays) && startDate < endDate) {

var dateDifference=endDate-startDate;

var datesPerMonth=new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);

if(endYears%4==0) { datesPerMonth[2]=29; }
if(endYears%100==0 && endYears%400>0) { datesPerMonth[2]=28; }

if(startDays<=datesPerMonth[startMonths]) {
if(endDays<=datesPerMonth[endMonths]) {

var diffYears=endYears-startYears;
var diffMonths=endMonths-startMonths; if(diffMonths < 0) { diffYears--; diffMonths=(12-diffMonths); }
var diffDays=endDays-startDays; if(diffDays < 0) { diffMonths--; if(diffMonths<0) { diffYears--; diffMonths=(12-diffMonths); } diffDays=datesPerMonth[(endMonths==1?12:(endMonths-1))]-diffDays; }

document.write("Difference: "+diffYears+" years; "+diffMonths+" months; "+diffDays+" days");
}
}
}
</script>
``````
0

LVL 9

Expert Comment

ID: 35505889
Ignore that, it doesn't work with start months higer than end months. I'll make some changes.
0

LVL 9

Expert Comment

ID: 35505908
My mistake. I had - instead of + when dealing with negatives, which I said above wouldn't work. Rushing is bad, kids.

``````<script type='text/javascript'>
//1/1/ 2011 and expiry as 12/31/2016

var startDate='12/01/2011';
var endDate='12/31/2016';
endDate='02/29/2016';

var startExplode=startDate.split('/');
var startYears=parseInt(startExplode[2],10);
var startMonths=parseInt(startExplode[0],10);
var startDays=parseInt(startExplode[1],10);
var endExplode=endDate.split('/');
var endYears=parseInt(endExplode[2],10);
var endMonths=parseInt(endExplode[0],10);
var endDays=parseInt(endExplode[1],10);
startDate=new Date(startDate).getTime();
endDate=new Date(endDate).getTime();

if((startYears < endYears || startMonths < endMonths || startDays < endDays) && startDate < endDate) {

var dateDifference=endDate-startDate;

var datesPerMonth=new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);

if(endYears%4==0) { datesPerMonth[2]=29; }
if(endYears%100==0 && endYears%400>0) { datesPerMonth[2]=28; }

if(startDays<=datesPerMonth[startMonths]) {
if(endDays<=datesPerMonth[endMonths]) {

var diffYears=endYears-startYears; // if(endMonths < startMonths || (endMonths == startMonths && endDays < startDays)) { diffYears--; }
var diffMonths=endMonths-startMonths; if(diffMonths < 0) { diffYears--; diffMonths=(12+diffMonths); }
var diffDays=endDays-startDays; if(diffDays < 0) { diffMonths--; if(diffMonths<0) { diffYears--; diffMonths=(12+diffMonths); } diffDays=datesPerMonth[(endMonths==1?12:(endMonths-1))]+diffDays; }

document.write("Difference: "+diffYears+" years; "+diffMonths+" months; "+diffDays+" days");
}
}
}
</script>
``````
0

Author Comment

ID: 35506105
Hi Vampireofdarkness,
Thanks for code.
I have question, time difference between  1/1/ 2011 and 12/31/2016 should be 6 year, but I ran your code I am getting Difference: 5 years; 0 months; 30 days ??

could you please look into it.

Thanks
Mas
0

LVL 75

Expert Comment

ID: 35506107
NEVER use document.write after a page has loaded. I know you example is inline, but the asker had a function.

Anyway - have a read here http://www.merlyn.demon.co.uk/js-date1.htm#DYMD

Also takes me back to http://www.irt.org/script/29.htm
0

Author Comment

ID: 35506137
Should we check each year between start and end date (including start date and end date) as leap year ??
0

LVL 9

Expert Comment

ID: 35506153
@mas1963 the difference between 1/1/2011 and 12/31/2016 is not 6 years. At greatest it is 5 years, 11 months, 30 days, 23 hours, 59 minutes and 59 seconds.

Also, in my code the start date is 12/01/2011, not 01/01/2011, which is why you are showing 0 months.

The code checks for leap years.

@mplungjan: the code was used as a complete HTML file, not as a separate script, as implied by the fact it is self executing.
0

Author Comment

ID: 35506224
Hi Vampireofdarkness,
code also checking each year between start and end date (including start date and end date) as leap year ??

Thanks
Mas
0

LVL 9

Expert Comment

ID: 35506244
No, it doesn't need to because you're not doing a total day count. It does check for leap years IF REQUIRED when counting days between months (see lines 26, 27 and 34).
0

Author Comment

ID: 35506294

Hi Hi Vampireofdarkness,
If I check the date difference between 1/1/2013 and 12/31/2015 , I am getting Difference: 2 years; 11 months; 30 days . Should it be 3 year, 0 month, 0 days

Thanks
Mas

0

LVL 75

Expert Comment

ID: 35506345
You mean 0 minutes into 1/1/2013 until but not including 1 minute past midnight on the second of Jan 2015
0

LVL 9

Expert Comment

ID: 35506353
The difference isn't showing as 3 years because it ISN'T 3 years. 01/01/2011 00:00 to 12/31/2011 00:00 is NOT a year. 01/01/2011 00:00 to 12/31/2011 23:59 is still NOT a year. It is 11 months, 30 days, 23 hours and 59 minutes.

If you want it to show 3 years (ie- one day more than it should) I would suggest changing the code so that you either

1. Subtract one day from the startDate variable (and make sure if you go into negatives to subtract from the months and year accordingly)
2. Add to the endDate variable (also noting the months and years)
3. Add to the diffDays, remembering months and years
0

LVL 75

Expert Comment

ID: 35506376
also normalise the hour to 0,0,0,0 to not deal with DST :)
0

LVL 82

Expert Comment

ID: 35506682
>>Clearly this is a 6 year lease, not a “5 Years, 11 Months, 28 Days” term
No it is NOT.
The year starts at 1/1/2011 00:00:00, but on 12/31/2011 23:59:59 there are ZERO years elapsed still.

You have to wait until January 1 to be able to say "A year has elapsed!".

Also note, when you say that the expiration date is:
12/31/2016

Javascript assuming you mean 12/31/2016 00:00:00, but based on your (wrong) assumptions of elapsed times, what you really mean is 12/31/2016 23:59:59.

But like I said, at 12/31/2016 23:59:59 the sixth year has NOT completed yet. So for your intended purposes, add a day to whatever your end date is and you will get the time frame you want/expect.
0

LVL 75

Expert Comment

ID: 35506757
Here is my take on this.

1: calculate number of days till the first of next month
2: calculate the number of months till end of year
3: calculate number of years from the 1st of Jan to the 1st of Jan of the end year
4: add months from 1st of Jan of the end year to end month start
5: add days from 1st of end month to end date

TODO: Test if days within same month and months within same year, but it seems a good start :)
``````<script>
/* Attempt on an accurate year month day difference by
Michel Plungjan, javascripts(a)plungjan.name
It will be appreciated if this comment stays */
var DateDifference = function(commence, expiry) {
if (!commence || !expiry) return '0 Yrs  0 Mos  0 Days';
var months = 0;
var years  = 0;
var days   = 0;
var start  = new Date(Date.parse(commence))
start.setHours(0,0,0,0); // normalise
var end = new Date(Date.parse(expiry));
end.setHours(0,0,0,0); // at midnight

var firstOfNextMonth = new Date(start.getFullYear(),start.getMonth()+1,1,0,0,0,0); // 1st of the next month
var numberOfDaysInStartMonth = new Date(start.getFullYear(),start.getMonth()+1,0,0,0,0,0).getDate();

var daysToNextMonth=0;
daysToNextMonth++;
}
if (daysToNextMonth===numberOfDaysInStartMonth) {
days=0;
months++;
}
var monthsToNextYear = 12-(start.getMonth()+1);
months += monthsToNextYear;
if (months === 12) {
months = 0;
years++;
}
if (end.getFullYear() > start.getFullYear()+1) {
for (var i=start.getFullYear()+1, n=end.getFullYear();i<n;i++) {
years++;
}
}

firstOfNextMonth = new Date(end.getFullYear(),end.getMonth()+1,1,0,0,0,0); // 1st of the next month
var numberOfDaysInEndMonth = new Date(end.getFullYear(),end.getMonth()+1,0,0,0,0,0).getDate();

if (end.getDate()===numberOfDaysInEndMonth) {
days=0;
months++;
}
else days += end.getDate()+1; // 24 hours
months += end.getMonth();
if (months === 12) {
months = 0;
years++;
}

return years+" year"+((years==1)?" ":"s ")+months+" month"+((months==1)?" ":"s ")+days+" day"+((days==1)?" ":"s ")
}
</script>
``````
0

Author Comment

ID: 35692963
Hi Vampireofdarkness,
Sorry for late reply, I was testing it.
I used you code and I am almost there but
It’s not working on months. For example. 1/1/2011 – 1/31/2011 should  be 1 month not 30 days

Or 1/1/2011 – 6/30/2011 should be 6 months not 5 months, 29 days

Hi mplungjan,
in your code how we can check leap year ?

Thanks
Masood
0

LVL 75

Expert Comment

ID: 35693274
No need to check leap year - never was
0

LVL 9

Expert Comment

ID: 35693409
@mplungjan - There is a need to check leap year if you're calculating the days between Jan 15th and March 14th. February may or may not have 29 days.

@mas1963 - please read above. 1st Jan to 31st Jan is 30 days, not a month (31 days, in this case). If you want to change the output, you need to add one day to the output and change the months and years accordingly. I have said this at least twice.

Modified code, NOTE THAT THIS IS NOT CONTAINED WITHIN A FUNCTION: datesPerMonth moved to the top, added the endDays++; line (Line 17?)
``````<script type='text/javascript'>

var datesPerMonth=new Array(0,31,28,31,30,31,30,31,31,30,31,30,31);

var startDate='1/01/2011';
var endDate='12/31/2016';

var startExplode=startDate.split('/');
var startYears=parseInt(startExplode[2],10);
var startMonths=parseInt(startExplode[0],10);
var startDays=parseInt(startExplode[1],10);
var endExplode=endDate.split('/');
var endYears=parseInt(endExplode[2],10);
var endMonths=parseInt(endExplode[0],10);
var endDays=parseInt(endExplode[1],10);

endDays++; if(endDays>datesPerMonth[endMonths]) { endDays=1; endMonths++; if(endMonths==13) { endMonths=1; endYears++; } }

startDate=new Date(startDate).getTime();
endDate=new Date(endDate).getTime();

if((startYears < endYears || startMonths < endMonths || startDays < endDays) && startDate < endDate) {

var dateDifference=endDate-startDate;

if(endYears%4==0) { datesPerMonth[2]=29; }
if(endYears%100==0 && endYears%400>0) { datesPerMonth[2]=28; }

if(startDays<=datesPerMonth[startMonths]) {
if(endDays<=datesPerMonth[endMonths]) {

var diffYears=endYears-startYears; // if(endMonths < startMonths || (endMonths == startMonths && endDays < startDays)) { diffYears--; }
var diffMonths=endMonths-startMonths; if(diffMonths < 0) { diffYears--; diffMonths=(12+diffMonths); }
var diffDays=endDays-startDays; if(diffDays < 0) { diffMonths--; if(diffMonths<0) { diffYears--; diffMonths=(12+diffMonths); } diffDays=datesPerMonth[(endMonths==1?12:(endMonths-1))]+diffDays; }

document.write("Difference: "+diffYears+" years; "+diffMonths+" months; "+diffDays+" days");
}
}
}
</script>
``````

1/1/2011 - 12/31/2016 shows as 6 years, but now 1/1/2011 - 1/1/2016 shows as 5 years and 1 day (which by your method is correct)
0

Author Comment

ID: 35693853
Thanks Vampireofdarkness,
Its now working perfectly.
I need final help.
In result variable if years, month or days, any one is zero then in result i don't to show them.
var result =  Math.floor(diffYears) + " Yrs, " + Math.floor(diffMonths) + " Mos, " + Math.floor(diffDays) + " Days";
i

Thanks
Masood
0

LVL 9

Accepted Solution

Vampireofdarkness earned 800 total points
ID: 35693895
``````diffYears=(diffYears>0)?((diffYears==1)?diffYears+' year':diffYears+' years'):'';
diffMonths=(diffMonths>0)?((diffMonths==1)?diffMonths+' month':diffMonths+' months'):'';
diffDays=(diffDays>0)?((diffDays==1)?diffDays+' day':diffDays+' days'):'';

var result = diffYears+' '+diffMonths+' '+diffDays;
``````

Change the result output formatting to suit. You can also add Math.floor() into the conditional part if you want to, but it shouldn't be needed.

``````diffYears=(diffYears>0)?((diffYears==1)?Math.floor(diffYears)+' year':Math.floor(diffYears)+' years'):'';
``````
0

LVL 75

Expert Comment

ID: 35695552
My code does not check specifically for leap year. It gets the number of actual days in the month. I have not had time to make sure it works for dates in the same year, same month and same week for which I apologise. I will try to get to it these days where I am off.
0

LVL 75

Assisted Solution

Michel Plungjan earned 200 total points
ID: 35696108
@Masod

If I have
30th of Jan 2004 to 29th of Feb 2004 - is that 1 month 1 day (because it is all of Feb plus one day in Jan)
or is it 1 month (because it is 30 days) or is it 30 days

And if I have
30th of Jan 2005 to 28th of Feb 2005 - is that 1 month 1 day (because it is all of Feb plus one day in Jan)
or 29 days (because it is less than 30 days) or something else?
0

Author Closing Comment

ID: 35698299
I am really thankfull to Vampireofdarkness for his easy to understand solution and solution worked perfectly. I really appreciated other contributors too.
0

Author Comment

ID: 35698343
I also like to thanks mplungjan for your input.

Thanks all.
0

LVL 75

Expert Comment

ID: 35698368
masod: Would you like to answer my last question so I can implement it in my script?

Thanks

Right now I cheat by adding this to the script

if (start.getFullYear() === end.getFullYear() && (end.getDate()-start.getDate())<28 ) { // this is cheating!
return formatDiff(0,0,days);
}
function formatDiff(years,months,days) {
var res = [];
if (years)  res.push(years +" year" +((years ==1)?" ":"s "));
if (months) res.push(months+" month"+((months==1)?" ":"s "));
if (days)   res.push(days  +" day"  +((days  ==1)?" ":"s "));
return res.join(" ");
}
0

LVL 75

Expert Comment

ID: 35698442
Usign Vampire's script

If I have
var startDate='2/25/2004';
var endDate='3/4/2004';

I get 9 days

if I have
var startDate='2/25/2003';
var endDate='3/4/2003';

I get 8 days

But 25 @00:00 +26+27+28+29+1+2+3 @23:59
is 8 days, no?
0

LVL 9

Expert Comment

ID: 35699636
@mplungjan - I said the same thing many times. The user wanted both the start and end date to be included so that 1/1/x to 12/31/x is a year and not 11 months, 30 days. This would put 25, 26, 27, 28, 29th Feb, 1, 2, 3, 4th Mar. You're not including the 4th March, which the asker wanted.

You're using a leap year in your first example and a non-leap year in the second.
0

LVL 75

Expert Comment

ID: 35699777
Yes I was using that on purpose and there should be one more day in the leap year but it does not make sense to add ANOTHER day to a period that include 24 hours on the 25th and on the 3rd

Also in my opinion the 1st to the 29th of Feb in a leap year is a month and the 1st to the 28th of Feb is a month in a non-leap year
0

LVL 9

Expert Comment

ID: 35699808
If 2/1/x to 2/28/x is a month (ie- 28 days as 1 and 28 are included) in a non leap year, then by your same logic 25th Feb to 4th Mar in a leap year is 25, 26, 27, 28, 29, 1, 2, 3, 4 (ie- 9 days as 25 and 4 are included).

You can't selectively include the last day when calculating, otherwise when booking a holiday you could end up losing a day of your holiday depending on whether you leave on the last day of the month or not. Either you include the last day as a full day, or you don't.
0

LVL 75

Expert Comment

ID: 35699855
I am only getting more confused

25 - 1  < including
26 - 2
27 - 3
28 - 4
29 - 5
1  - 6
2 - 7
3 - 8 < including

unless of course you talk nights
then you arrive on the 25th and leave on the 4th
0

LVL 9

Expert Comment

ID: 35700001
You put 3/4/2004 (That's 4th March, not 3rd). You are not including the LAST day.

25 = 1
26 = 2
27 = 3
28 = 4
29 = 5
01 = 6
02 = 7
03 = 8
04 = 9

The asker wanted BOTH Start and End date included in the duration. Ending at 03/03/2004 is ending too early, according to the asker.
0

Author Comment

ID: 35707163
Vampireofdarkness is right.
As most of properties lease are day you sign the lease and end of day when ever lease is ending, so point is that we will include the day lease start and end of the days lease is ending.

I
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Active Directory replication delay is the cause to many problems.  Here is a super easy script to force Active Directory replication to all sites with by using an elevated PowerShell command prompt, and a tool to verify your changes.
Originally, this post was published on Monitis Blog, you can check it here . In business circles, we sometimes hear that today is the “age of the customer.” And so it is. Thanks to the enormous advances over the past few years in consumer techno…
Learn the basics of lists in Python. Lists, as their name suggests, are a means for ordering and storing values. : Lists are declared using brackets; for example: t = [1, 2, 3]: Lists may contain a mix of data types; for example: t = ['string', 1, T…
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…
###### Suggested Courses
Course of the Month20 days, 9 hours left to enroll