SHARE
Facebook X Pinterest WhatsApp

Learn How To Use JavaScript Dates and Leap Years

Jan 9, 2012

Think that you can calculate date intervals without worrying about leap years? Think again. It’s true that, as long as you follow the guidelines set out in my previous Calculating the Difference between Two Dates article, the leap years will be accounted for and handled correctly. But this presumes that you aren’t interested in any particulars about the leap years themselves.

If you ever find yourself trying to calculate any kind of annualized figures, you’ll soon realize that it can pay off to know how to separate leap years from non-leap years. This article will introduce a few useful functions that you can use to work with leap years if and when the need arises.

And by the way, this is leading up to something pretty useful in the next article, where we will implement a JavaScript annualized returns calculator which will feature the HTML5 Date Picker element with a jQuery widget fallback.

Determining Whether or not a Given Year is a Leap Year

The first step in working with leap years is determining whether or not a given date contains a leap year. The following method is added to the Date’s prototype object so that it can be applied directly to any Date object as in aDate.isLeapYear(). It accepts a boolean that tells it whether to use Universal (UTC) time. While you wouldn’t think that a date would be affected by UTC, if the time is close enough for midnight for the time zone to shift the UTC into the next year, this method will return the correctly adjusted day. For more information on UTC time, see my Date Creation in JavaScript article.

Date.prototype.isLeapYear = function(utc) {
    var y = utc ? this.getUTCFullYear() : this.getFullYear();
    return !(y % 4) && (y % 100) || !(y % 400);
};

The above expression evaluates whether or not the given date falls within a leap year using the three following Gregorian calendar rules:

  1. Most years divisible by 4 are Leap Years (i.e. 1996)
  2. However, most years divisible by 100 are not (i.e. 1900)
  3. Unless they are also divisible by 400, in which case they are leap years (i.e. 2000)

Calculating Days while Ignoring Leap Years

Our second leap year function calculates the number of days between two dates while ignoring the extra leap year days. Such a function is useful when you want to divide the total number of days by 365 to arrive to a yearly figure.

The function would still have to take into account if the current year was a leap year and the two dates span the end of February. It does that by creating new dates using the non-leap year of 2010, which is used to determine the number of days difference within the same year. That figure is then added to 365 multiplied by number of years difference.

function daysBetweenExcludingLeapYears( date1, date2, utc ) {
    //2010 was NOT a leap year
    var cmpDate1 = new Date(2010, date1.getMonth(), date1.getDate());
    var cmpDate2 = new Date(2010, date2.getMonth(), date2.getDate());
    var date1Year = utc ? date1.getUTCFullYear() : date1.getFullYear();
    var date2Year = utc ? date2.getUTCFullYear() : date2.getFullYear();

    return Date.daysBetween(cmpDate1, cmpDate2) + (365 * (date1Year - date2Year));
}

Here is the static Date.daysBetween() function. It was covered in the Calculating the Difference between Two Dates article.

Date.daysBetween = function( date1, date2 ) {
  //Get 1 day in milliseconds
  var one_day=1000*60*60*24;

  // Convert both dates to milliseconds
  var date1_ms = date1.getTime();
  var date2_ms = date2.getTime();

  // Calculate the difference in milliseconds
  var difference_ms = date2_ms - date1_ms;
    
  // Convert back to days and return
  return Math.round(difference_ms/one_day); 
}

Counting Only Leap Year Days between Two Dates

Our final function of the day tallies up the number of days between two dates that are part of leap years. It can be useful in separating leap year days from non-leap year ones. It does that by breaking down the date range into three parts: the partial first year days, the full years, and the partial end year days. In all three parts, the isLeapYear() function is used to good effect in deciding whether or not to count the days of that year.

Again, the optional utc boolean argument is present. However, in this function it is used to set the year getter and setter to the correct function at the top of the function because the getter in particular is called numerous times. A working date is stored in a temporary (tmp) variable using the new Date(milliseconds) constructor so that a copy is created:

Date.leapYearDaysBetween = function(date1, date2, utc) {
    var count     = 0;
    var fnGetYear = utc ? getUTCFullYear : getFullYear;
    var fnSetYear = utc ? setUTCFullYear : setFullYear;
	
    if (d1.fnGetYear() == date2.fnGetYear() && date1.isLeapYear()) { 
        count = Date.daysBetween(date1,date2);
    } else {
      var lastDayInYear = new Date(date1.fnGetYear(), 11, 31);
      var tmp = new Date(date1.getTime()); //copy the date
      while (tmp.fnGetYear() < date2.fnGetYear()) {
          if (tmp.isLeapYear()) count += Date.daysBetween(tmp,lastDayInYear);

          tmp.fnSetYear(tmp.fnGetYear()+1);
      }
      if ( date2.isLeapYear() ) {
          var firstDayInYear = new Date(tmp.fnGetYear(), 0, 1);
          count += Date.daysBetween(firstDayInYear, date2);
      }
   }
   return count;
}

In case you’re wondering, I did not include an equivalent function for calculating non-leap year days because that can be ascertained by subtracting the results of the Date.leapYearDaysBetween() function from those of Date.daysBetween().

Conclusion

As we’ll be seeing in the next article, leap years take on extra importance when dealing with annualized figures. In fact, you might be surprised just how much of a difference it makes for accuracy when you account for leap years properly.

About the Author

Rob Gravelle resides in Ottawa, Canada, and is the founder of GravelleConsulting.com. Rob has built systems for Intelligence-related organizations such as Canada Border Services, CSIS as well as for numerous commercial businesses. Email Rob to receive a free estimate on your software project. Should you hire Rob and his firm, you’ll receive 15% off for mentioning that you heard about it here!

Recommended for you...

The Revolutionary ES6 Rest and Spread Operators
Rob Gravelle
Aug 23, 2022
Ahead of Time (AOT) Compilation in Angular
Tariq Siddiqui
Aug 16, 2022
Converting a JavaScript Object to a String
Rob Gravelle
Aug 14, 2022
Understanding Primitive Type Coercion in JavaScript
Rob Gravelle
Jul 28, 2022
HTML Goodies Logo

The original home of HTML tutorials. HTMLGoodies is a website dedicated to publishing tutorials that cover every aspect of being a web developer. We cover programming and web development tutorials on languages and technologies such as HTML, JavaScript, and CSS. In addition, our articles cover web frameworks like Angular and React.JS, as well as popular Content Management Systems (CMS) that include WordPress, Drupal, and Joomla. Website development platforms like Shopify, Squarespace, and Wix are also featured. Topics related to solid web design and Internet Marketing also find a home on HTMLGoodies, as we discuss UX/UI Design, Search Engine Optimization (SEO), and web dev best practices.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.