HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Clean Calendar Object

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
calendarobjectclean

Problem

I am writing a small chunk of code (a module>?) that I will use to create a view on a page using angular. The angular directive will take care of generating the html.
The sole purpose of this module is expose a given month's data, specifically on what day it starts for the given year and how many days it has. I want to make this module as clean as possible and would appreciate anyfeedback.

function Calendar(month, year) {
var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
var months = [
    'January', 'February', 'March', 'April',
    'May', 'June', 'July', 'August', 'September',
    'October', 'November', 'December'
];
var daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

this.getMonthData = function() {
    var startingDay = new Date(this.year, this.month, 1).getDay();
    var monthLength = daysInMonth[this.month];

    if (this.month === 1) {
        if ((this.year % 4 === 0 && this.year % 100 !== 0) || this.year % 400 === 0) {
            monthLength = 29;
            }
        }
    };
}

Solution

For one, I see your code is a bit over-engineered. So let's go back to the problem: Given a year and month, determine what day that month starts in a year and how many days it has.

To start, I would need 2 functions to keep the code understandable. Trying to jam a lot of functionality into one function would only cause problems in trying to understand things.

function getFirstDayOfMonthAtYear(month, year){...}

function getLengthOfMonthAtYear(month, year){...}


You could go for a constructor to house the month and year value, and the functions be methods on the prototype. Also, your lookup arrays need to come with the constructor, not just some free-floating variable. You can attach them to the constructor, since functions are also objects.

function Calendar(year, month){
  // Default to January 1970
  this.month = month || 0;
  this.year  = year || 1970;

  // Generate the Date object so we don't need to create on every call.
  // Also note that months are zero-indexed. So if we provide the
  // real month number, we need to subtract 1.
  this.date = new Date(year, month - 1, 1);
}

Calendar.prototype.getFirstDay = function(){
  return Calendar.DAY_NAMES[this.date.getDay()];
};
Calendar.prototype.getMonthLength = function(){
  // I'll show you a trick next
};

// We use pseudo-static variables. Essentially we're just attaching
// to the constructor. That way, our lookup comes with the constructor.
Calendar.DAY_NAMES = ['Sun', 'Mon', ..., 'Sat'];


So it comes to getting how long a month is. There's a trick for that. You can construct a Date object with the current year but on the next month with date 0. JavaScript dates that underflows/overflows the months date range automatically increments/decrements the month. Then it's all a matter of doing getDate.

// So the date is March 0, 2004... essentially Feb 29, 2004
var daysOnFeb2004 = (new Date(2004, 2, 0)).getDate(); // 29


In the end:



function Calendar(year, month) {
this.month = month || 0;
this.year = year || 1970;
this.date = new Date(year, month - 1, 1);
}

Calendar.prototype.getFirstDay = function() {
return Calendar.DAY_NAMES[this.date.getDay()];
};

Calendar.prototype.getMonthLength = function() {
return (new Date(this.year, this.month, 0)).getDate();
};

Calendar.DAY_NAMES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

// Usage
var date = new Calendar(2004, 2);
document.write('First day: ' + date.getFirstDay() + ' Length:' + date.getMonthLength());

Code Snippets

function getFirstDayOfMonthAtYear(month, year){...}

function getLengthOfMonthAtYear(month, year){...}
function Calendar(year, month){
  // Default to January 1970
  this.month = month || 0;
  this.year  = year || 1970;

  // Generate the Date object so we don't need to create on every call.
  // Also note that months are zero-indexed. So if we provide the
  // real month number, we need to subtract 1.
  this.date = new Date(year, month - 1, 1);
}

Calendar.prototype.getFirstDay = function(){
  return Calendar.DAY_NAMES[this.date.getDay()];
};
Calendar.prototype.getMonthLength = function(){
  // I'll show you a trick next
};

// We use pseudo-static variables. Essentially we're just attaching
// to the constructor. That way, our lookup comes with the constructor.
Calendar.DAY_NAMES = ['Sun', 'Mon', ..., 'Sat'];
// So the date is March 0, 2004... essentially Feb 29, 2004
var daysOnFeb2004 = (new Date(2004, 2, 0)).getDate(); // 29

Context

StackExchange Code Review Q#109115, answer score: 3

Revisions (0)

No revisions yet.