JavaScript Date Ranges/Calculations with Datejs



If there is anything I hate more than the smell of durian, it is having to deal with date range calculations in JavaScript. Luckily though, we have the Datejs JavaScript Date Library to prevent us from having to pull our hair out.

Mission

I was recently faced with having to implement a date range drop-down menu very similar to of the one that is beautifully implemented in Google Adwords:

Google Adwords Date Range Pull-Down Menu

The select input element had to return 3 pieces of information: The name of the option, start date, and end date of the selected option.

Here are the specific options that I had to implement for the date ranges:

  • This month to date
  • This quarter to date
  • Last 7 days
  • Last 30 days
  • Last 365 days
  • Last week (Mon to Sun)
  • Last full month
  • Last full quarter
  • Last full year

The Plan


The tricky thing about select input elements is that they only return one value but this mission required me to return the option name, a start date, and an end date. The solution I chose to go with was a JSON string with the following name/value pairs for each option:

'[display name of the option]':'{start:[start date],end:[end date]}'

It looks messy but it really is one name/value pair depicted in different colors. The value itself, though, is a JSON array that contains 2 name/value pairs: The start and end dates.

The actual value string for one of the options would look something like this:

'Last week (Mon to Sun)':'{"start":"07/18/2011","end":"07/24/2011"}'

Once all of the select values are calculated using Datejs, the plan is to populate a select input element with all the options via jQuery. This allows for more of a separation between the HTML and the JavaScript code which is easier to maintain and a bit more organized.

The Code

Let’s start easy and begin with the HTML code for the select input:

  1. <select id="dateRange" name="dateRange">
    
  2. </select>

That was pretty painless. We’ve prepared the select input element and gave it an id and a name but we have yet to populate it with the options. This will be taken care of later with the help of JavaScript.

The next part of the plan is to do the actual date range calculations. This was done relatively easily with the help of Datejs. Here is the JavaScript code for that:

  1. // Import Datejs JavaScript Library
  2. <script type="text/javascript" src="[PATH_TO_YOUR_DATEJS_FILE]/date.js"></script>
  3.  
  4. // Calculate date ranges for date pull down menu
  5. <script type="text/javascript">
  6. var today = Date.parse('today').toString('yyyy-MM-dd');
  7. var firstDayOfMonth = Date.today().moveToFirstDayOfMonth().toString('yyyy-MM-dd');
  8. var month = Date.parse('today').toString('MM');
  9. var year = Date.parse('today').toString('yyyy');
  10. var quarterMonth = (Math.floor(month/3)*3)+1;
  11. var quarter = (Math.floor(month/3))+1;
  12. var lastQuarter = (quarter > 1) ? quarter - 1 : lastQuarter = 4;
  13. var quarterStartDate = (quarterMonth < 10) ? year+'-0'+quarterMonth+'-01' : year+'-'+quarterMonth+'-01';
  14. var lastSevenDaysStart = Date.today().add(-6).days().toString('yyyy-MM-dd');
  15. var lastThirtyDaysStart = Date.today().add(-29).days().toString('yyyy-MM-dd');
  16. var lastYearDayStart = Date.today().add(-364).days().toString('yyyy-MM-dd');
  17. var lastFullWeekStart = Date.today().add(-7).days().last().monday().toString('yyyy-MM-dd');
  18. var lastFullWeekEnd = Date.today().add(-7).days().last().monday().add(6).days().toString('yyyy-MM-dd');
  19. var lastFullMonthStart = Date.today().add(-1).months().moveToFirstDayOfMonth().toString('yyyy-MM-dd');
  20. var lastFullMonthEnd = Date.today().add(-1).months().moveToLastDayOfMonth().toString('yyyy-MM-dd');
  21. var lastFullQuarterStart = ((((lastQuarter-1)*3)+1) < 10) ? year+'-0'+(((lastQuarter-1)*3)+1)+'-01' : year+'-'+(((lastQuarter-1)*3)+1)+'-01';
  22. var lastFullQuarterEnd = Date.parse(lastFullQuarterStart).add(2).months().moveToLastDayOfMonth().toString('yyyy-MM-dd');
  23. var lastFullYearStart = Date.today().add(-1).years().toString('yyyy') + '-01-01';
  24. var lastFullYearEnd = Date.today().add(-1).years().toString('yyyy') + '-12-31';
  25.  
  26. // Prepare JavaScript array with the JSON 
  27. var selectOptions = {
  28.     'This month to date':'{"start":"'+firstDayOfMonth+'","end":"'+today+'"}',
  29.     'This quarter to date':'{"start":"'+quarterStartDate+'","end":"'+today+'"}',
  30.     'Last 7 days':'{"start":"'+lastSevenDaysStart+'","end":"'+today+'"}',
  31.     'Last 30 days':'{"start":"'+lastThirtyDaysStart+'","end":"'+today+'"}',
  32.     'Last 365 days':'{"start":"'+lastYearDayStart+'","end":"'+today+'"}',
  33.     'Last week (Mon to Sun)':'{"start":"'+lastFullWeekStart+'","end":"'+lastFullWeekEnd+'"}',
  34.     'Last full month':'{"start":"'+lastFullMonthStart+'","end":"'+lastFullMonthEnd+'"}',
  35.     'Last full quarter':'{"start":"'+lastFullQuarterStart+'","end":"'+lastFullQuarterEnd+'"}',
  36.     'Last full year':'{"start":"'+lastFullYearStart+'","end":"'+lastFullYearEnd+'"}'
  37. };
  38. </script>

Line 2 imports the Datejs library. You will have to download it and install via these instructions. Lines 5-23 calculates each of the date elements that I will need to piece together the final product. All the variables are pretty much self explanatory so I will not do the play-by-play for each line.

The excitement happens in lines 26-36 where everything is pieced together to form our JSON strings and put into an array called selectOptions.

Ok, now we have our empty select input and a JavaScript array with all our options. Next, we enlist the help of jQuery to help populate the select input element.

  1. // Load jQuery library hosted by Google - Note: If you already have jQuery imported DELETE the next line.
  2. <script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
  3.  
  4. <script type="text/javascript">
  5. $(document).ready(function() {
  6.     $.each(selectOptions, function(key, value) {      
  7.         if (key == 'Last 30 days') {
  8.             $('#date_range').
  9.                 append($("<option></option>").
  10.                 attr("value", value).
  11.                 attr("selected", "selected").
  12.                 text(key));           
  13.         }
  14.         else {
  15.             $('#date_range').
  16.                 append($("<option></option>").
  17.                 attr("value", value).
  18.                 text(key)); 
  19.         }
  20.     });
  21. });
  22. </script>

Line 2 imports the jQuery library which Google so nicely hosted for us =) Please remove or comment out this line if you already have jQuery working on your site. Line 5 contains the jQuery ready() function which is executed when the DOM is fully loaded. This is important for us because we need to have the select input element in place first before we can load the options. That makes sense. You need to watch The Empire Strikes Back before you watch Return of the Jedi.

Line 6 is the jQuery foreach function which will loop through each of our options in the selectOptions array by using the key => value pair (shown earlier in the Christmas colors). Lines 7-13 tests to see if the current key is equal to “Last 30 days” and if so, it will make it the default selected option. It does so by:

  1. Dynamically creating the option element and appending it to our select input that is accessed by the jQuery selector using the “date_range” id. [lines 8-9]
  2. Dynamically setting the value attribute of the option to the value from the name/value pair (this contains our start and end dates). [line 10]
  3. Dynamically setting the selected attribute to true which will make this option the default selected option. [line 11]
  4. Dynamically setting the displayed text of the option to the key which holds the display name for the option (e.g. “Last 30 days”). [line 12]

Lines 14-19 processes all the other elements in the same manner except that it does not set the selected attribute to true.

Here is the final product in all its glory:

Note: I noticed that the default selected option is NOT working correctly. I know this codes works in the original implementation and I have tried debugging it here but it is 2:12AM and I need sleep! I will come back to this at a later time…I promise.

To make this easier for you to implement, here is all the JavaScript code put together:

  1. // Load jQuery library hosted by Google - Note: If you already have jQuery imported DELETE the next line.
  2. <script src="//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" type="text/javascript"></script>
  3.  
  4. // Import Datejs JavaScript Library
  5. <script type="text/javascript" src="[PATH_TO_YOUR_DATEJS_FILE]/date.js"></script>
  6.  
  7. <script type="text/javascript">
  8. $(document).ready(function() {
  9.     $.each(selectOptions, function(key, value) {      
  10.         if (key == 'Last 30 days') {
  11.             $('#date_range').
  12.                 append($("<option></option>").
  13.                 attr("value", value).
  14.                 attr("selected", "selected").
  15.                 text(key));           
  16.         }
  17.         else {
  18.             $('#date_range').
  19.                 append($("<option></option>").
  20.                 attr("value", value).
  21.                 text(key)); 
  22.         }
  23.     });
  24. });
  25.  
  26. // Calculate date ranges for date pull down menu
  27. var today = Date.parse('today').toString('yyyy-MM-dd');
  28. var firstDayOfMonth = Date.today().moveToFirstDayOfMonth().toString('yyyy-MM-dd');
  29. var month = Date.parse('today').toString('MM');
  30. var year = Date.parse('today').toString('yyyy');
  31. var quarterMonth = (Math.floor(month/3)*3)+1;
  32. var quarter = (Math.floor(month/3))+1;
  33. var lastQuarter = (quarter > 1) ? quarter - 1 : lastQuarter = 4;
  34. var quarterStartDate = (quarterMonth < 10) ? year+'-0'+quarterMonth+'-01' : year+'-'+quarterMonth+'-01';
  35. var lastSevenDaysStart = Date.today().add(-6).days().toString('yyyy-MM-dd');
  36. var lastThirtyDaysStart = Date.today().add(-29).days().toString('yyyy-MM-dd');
  37. var lastYearDayStart = Date.today().add(-364).days().toString('yyyy-MM-dd');
  38. var lastFullWeekStart = Date.today().add(-7).days().last().monday().toString('yyyy-MM-dd');
  39. var lastFullWeekEnd = Date.today().add(-7).days().last().monday().add(6).days().toString('yyyy-MM-dd');
  40. var lastFullMonthStart = Date.today().add(-1).months().moveToFirstDayOfMonth().toString('yyyy-MM-dd');
  41. var lastFullMonthEnd = Date.today().add(-1).months().moveToLastDayOfMonth().toString('yyyy-MM-dd');
  42. var lastFullQuarterStart = ((((lastQuarter-1)*3)+1) < 10) ? year+'-0'+(((lastQuarter-1)*3)+1)+'-01' : year+'-'+(((lastQuarter-1)*3)+1)+'-01';
  43. var lastFullQuarterEnd = Date.parse(lastFullQuarterStart).add(2).months().moveToLastDayOfMonth().toString('yyyy-MM-dd');
  44. var lastFullYearStart = Date.today().add(-1).years().toString('yyyy') + '-01-01';
  45. var lastFullYearEnd = Date.today().add(-1).years().toString('yyyy') + '-12-31';
  46.  
  47. // Prepare JavaScript array with the JSON 
  48. var selectOptions = {
  49.     'This month to date':'{"start":"'+firstDayOfMonth+'","end":"'+today+'"}',
  50.     'This quarter to date':'{"start":"'+quarterStartDate+'","end":"'+today+'"}',
  51.     'Last 7 days':'{"start":"'+lastSevenDaysStart+'","end":"'+today+'"}',
  52.     'Last 30 days':'{"start":"'+lastThirtyDaysStart+'","end":"'+today+'"}',
  53.     'Last 365 days':'{"start":"'+lastYearDayStart+'","end":"'+today+'"}',
  54.     'Last week (Mon to Sun)':'{"start":"'+lastFullWeekStart+'","end":"'+lastFullWeekEnd+'"}',
  55.     'Last full month':'{"start":"'+lastFullMonthStart+'","end":"'+lastFullMonthEnd+'"}',
  56.     'Last full quarter':'{"start":"'+lastFullQuarterStart+'","end":"'+lastFullQuarterEnd+'"}',
  57.     'Last full year':'{"start":"'+lastFullYearStart+'","end":"'+lastFullYearEnd+'"}'
  58. };
  59. </script>

And there you have it! I hope this helps someone out there in the ether =)

Published by

Allen Liu

Building websites is a passion of mine. During the course of my work, I have created some snippets of code that I hope will prove useful to other developers.

One thought on “JavaScript Date Ranges/Calculations with Datejs”

Leave a Reply

Your email address will not be published. Required fields are marked *