In our time-tracking app, Tempo, we’ve got a date range drop-down menu, and that allows you to set the start and end dates for a report. Next to it are two text fields for the start and end date, which are over-ridden when the user selects one of the ranges.
This got a little confusing for users because the drop-down selection wasn’t reflected in the text fields, so I threw together some quick javascript for calculating the date end points client-side and setting the fields. In the end, I needed something like:
Tempo.activate_range_select = function() {
$j("select#interval").change(function(){
var $select = $j(this);
// for each interval, create a start and end date, and insert into date fields
var now = new Date();
var start_date = null;
var end_date = null;
switch($select.val()) {
case "today":
start_date = now.beginning_of_day();
end_date = now;
break;
case "yesterday":
start_date = now.days_ago(1).beginning_of_day();
end_date = now.days_ago(1).end_of_day();
break;
To get here, though, I had to work out these date calculation methods that you can see being used above. Those aren’t naturally occurring methods on the Date class in Javascript, but they can be if you write them yourself! And as you build out the simpler ones, they lend themselves to a full library.
So here’s a little library that extends the Date object with a big pile of handy methods: date.js It’s not all entirely original, I did find some tips out there in the wild and lifted a couple of handy things from the jQuery Date Picker’s date.js. But only a little.
A sampling of some of the methods:
Date.prototype.weekDay = function () {
// in ISO we want Mon = 0 and Sun = 6!
var day = this.getDay() - 1;
day = (day < 0) ? 6 : day;
return day;
};
Date.prototype.isLeapYear = function() {
var year = this.getFullYear();
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
};
Date.prototype.end_of_week = function() {
var d = this.copy();
d.setDate( this.getDate() + (6 - this.weekDay()) );
d.setHours(23,59,59);
return d;
};
/*
* figuring out the end of quarter:
*
# q1 = 31 + 28 + 31 = 90 + 2(leap)
# q2 = 30 + 31 + 30 = 91
# q3 = 31 + 31 + 30 = 92
# q4 = 31 + 30 + 31 = 92
*/
Date.prototype.end_of_quarter = function() {
var d = this.copy();
d.setHours(23,59,59);
switch( this.getQuarter() ) {
case 1:
// is this a leap year?
if ( this.isLeapYear() ) {
d.setMonth(0, 92); // allow overflow to set correct month and day
} else {
d.setMonth(0, 90)
}
break;
case 2:
d.setMonth(3, 91);
break;
case 3:
d.setMonth(6, 92);
break;
default:
d.setMonth(9, 92);
}
return d;
};