From the Web:

Dave Eisenberg's Calendar


Dave Eisenberg's calendar (http://www.best.com/~nessus/js-today.html) is a good example of the use of expressions and variables, as well as functions and objects. The program generates a dynamic Web page that includes a greeting suited to the time of day (such as "Good Evening!"), the time of day, and the current month's calendar with the current date highlighted.

In addition, the page includes an image suited to the current time of day.

In doing this, Eisenberg makes use of several techniques that we haven't seen yet. His script uses the Date object, as well as several new methods including Math.floor() from the Math object and others from the Date object.

The source code for the page is in Listing W1.1.


Listing W1.1. Dave Eisenberg's calendar.
<HTML>
<HEAD>
<TITLE>Greetings from Dave Eisenberg</TITLE>
</HEAD>

<BODY>

<SCRIPT LANGUAGE="JavaScript">
<!--  to hide script contents from old browsers

function greeting()
{
   var today = new Date();
   var hrs = today.getHours();

   document.writeln("<CENTER>");
   if ((hrs >=6) && (hrs <=18))
   {
      document.writeln("<IMG SRC=\"daypix/day");
      document.write(Math.floor(hrs / 10));
      document.write(Math.floor(hrs % 10));
      document.write("00.gif\">");
   }
   else
      document.write("<IMG SRC=\"daypix/night1.gif\">");

   document.writeln("<BR>");
   document.write("<H1>Good ");
   if (hrs < 6)
      document.write("(Early) Morning");
   else if (hrs < 12)
      document.write("Morning");
   else if (hrs <= 18)
      document.write("Afternoon");
   else
      document.write("Evening");
   document.writeln("!</H1>");
   document.write("You entered this page at ");
   dayStr = today.toLocaleString();
   i = dayStr.indexOf(' ');
   n = dayStr.length;
   document.write(dayStr.substring(i+1, n));
   document.writeln("</CENTER>");
}

function montharr(m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11)
{
   this[0] = m0;
   this[1] = m1;
   this[2] = m2;
   this[3] = m3;
   this[4] = m4;
   this[5] = m5;
   this[6] = m6;
   this[7] = m7;
   this[8] = m8;
   this[9] = m9;
   this[10] = m10;
   this[11] = m11;
}

function calendar()
{
   var monthNames = "JanFebMarAprMayJunJulAugSepOctNovDec";
   var today = new Date();
   var thisDay;
   var monthDays = new montharr(31, 28, 31, 30, 31, 30, 31, 31, 30,
      31, 30, 31);

   year = today.getYear() + 1900;
   thisDay = today.getDate();

   // do the classic leap year calculation
   if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
      monthDays[1] = 29;

   // figure out how many days this month will have...
   nDays = monthDays[today.getMonth()];

   // and go back to the first day of the month...
   firstDay = today;
   firstDay.setDate(1);
   // and figure out which day of the week it hits...
   startDay = firstDay.getDay();

   document.writeln("<CENTER>");
   document.write("<TABLE BORDER>");
   document.write("<TR><TH COLSPAN=7>");
   document.write(monthNames.substring(today.getMonth() * 3,
      (today.getMonth() + 1) * 3));
   document.write(". ");
   document.write(year);
   document.write("<TR><TH>Sun<TH>Mon<TH>Tue<TH>Wed<TH>Thu<TH>Fri<TH>Sat");

   // now write the blanks at the beginning of the calendar
   document.write("<TR>");
   column = 0;
   for (i=0; i<startDay; i++)
   {
      document.write("<TD>");
      column++;
   }

   for (i=1; i<=nDays; i++)
   {
      document.write("<TD>");
      if (i == thisDay)
         document.write("<FONT COLOR=\"#FF0000\">")
document.write(i);
      if (i == thisDay)
         document.write("</FONT>")
column++;
      if (column == 7)
      {
         document.write("<TR>"); // start a new row
         column = 0;
      }
   }
   document.write("</TABLE>");
   document.writeln("</CENTER>");
}
document.write(greeting());
document.write("<HR>");
document.write(calendar());
document.write("<HR>");
document.write("<A HREF=\"http://www.best.com/~nessus\">");
document.write("Back to Dave Eisenberg's resume<\A>");

<!-- end hiding contents from old browsers  -->
</SCRIPT>

</BODY>
</HTML>

The code produces results like those in Figures W1.1 and W1.2.

Figure W1.1 : During the daytime, the user gets one of several images depicting the time of day.

Figure W1.2 :Using the Date object, the program builds a calendar for the current month.


The first thing you notice about this script is that it is not placed inside the header of the HTML file. The author does this because there is no chance of events triggering calls to functions which have not yet been defined.

In addition, all HTML code is dynamically generated by the script.

The calendar program uses three functions. The calls are made in sequence by the main body of the script:

document.write(greeting());
document.write("<HR>");
document.write(calendar());
document.write("<HR>");
document.write("<A HREF=\"http://www.best.com/~nessus\">");
document.write("Back to Dave Eisenberg's resume<\A>");

At the top of the script, two global declarations (today and hrs) occur. The command var today = new Date(); creates an instance of the system's Date object in much the same way you could create an instance of any object you defined yourself.

The Date object enables programmers to create an object that contains information about a particular date and provides a set of methods to work with that information.

In order to create an instance of the Date object, you use the form: variable = new Date(parameters) where the parameters can be any of the following:

Note
In JavaScript, it is not possible to create dates before 1 January 1970. The date 1 January 1970 at 00:00:00 is known as the epoch.

The Date object provides the methods outlined in Table W1.1.

Table W1.1. Methods of the Date object.

NameDescription
getDate Returns the day of the month as an integer from 1 to 31
getDay Returns the day of the week as an integer where zero is Sunday and one is Monday
getHours Returns the hour as an integer between 0 and 23
getMinutes Returns the minutes as an integer from 0 to 59
getMonth Returns the month as an integer from 0 to 11 where zero is January and 11 is December
getSeconds Returns the seconds as an integer between 0 and 59
getTime Returns the number of milliseconds since 1 January 1970 at 00:00:00
getTimezoneOffset Returns the difference between the local time and Greenwich Mean Time in minutes
getYear Returns the year as a two-digit integer
parse Returns the number of milliseconds since 1 January 1970 at 00:00:00 for the date string passed to it
setDate Sets the day of the month based on an integer argument from 1 to 31
setHours Sets the hour based on an argument from 0 to 23
setMinutes Sets the minutes based on an argument from 0 to 59
setMonth Sets the month based on an argument from 0 to 11
setSeconds Sets the seconds based on an argument between 0 and 59
setTime Sets the time based on an argument representing the number of milliseconds since 1 January 1970 at 00:00:00
setYear Sets the year based on a four-digit integer greater than 1900
toString Returns the current date as a string
toGMTString Returns the current date and time using the Internet GMT conventions (i.e. in the form "Mon, 18 Dec 1995 17:28:35 GMT")
toLocaleString Returns the date as a string in the form "MM/DD/YY HH:MM:SS"
UTC Takes a comma delimited date and returns the number of milliseconds since 1 January 1970 at 00:00:00 GMT time

Based on this information, the variable declaration var hrs = today=getHours() will contain the current hour when the user loads the page.

The first function the script calls is greeting(), which displays the appropriate image and welcome message along with the current time:

function greeting()
{
   var today = new Date();
   var hrs = today.getHours();

   document.writeln("<CENTER>");
   if ((hrs >=6) && (hrs <=18))
   {
      document.writeln("<IMG SRC=\"daypix/day");
      document.write(Math.floor(hrs / 10));
      document.write(Math.floor(hrs % 10));
      document.write("00.gif\">");
   }
   else
      document.write("<IMG SRC=\"daypix/night1.gif\">");

   document.writeln("<BR>");
   document.write("<H1>Good ");
   if (hrs < 6)
      document.write("(Early) Morning");
   else if (hrs < 12)
      document.write("Morning");
   else if (hrs <= 18)
      document.write("Afternoon");
   else
      document.write("Evening");
   document.writeln("!</H1>");
   document.write("You entered this page at ");
   dayStr = today.toLocaleString();
   i = dayStr.indexOf(' ');
   n = dayStr.length;
   document.write(dayStr.substring(i+1, n));
   document.writeln("</CENTER>");
}

The function determines that it is daytime if hrs is between 6 and 18 and then builds an image tag. The filename includes a number built out of the hrs variable using Math.floor(). This method returns the closest integer less than the argument. In that way, if hrs is 12, the image's filename would be day1200.gif.

Tip
Math.ceil() is similar to Math.floor() except it returns the nearest integer greater than the value of the argument.

The current time, which is output at the end of the function, is obtained from the string returned by the Date.toLocaleString() method. This string contains the date and time separated by a single space. The function uses the indexOf() method of the string object to locate the index of the space in the string. The length property of the string object is used to determine the index of the last character in the string.

The substring() method then returns the portion of the string after the index up to the end of the string. The string object, and in particular the substring() method, are discussed in more detail in later chapters. The string object is covered in depth in Chapter 10, "Strings, Math, and the History List."

The next function to be called is the calendar() function, which does the more complex job of building the calendar. The calendar is designed using HTML tables, which are discussed further in Chapter 7, "Loops."

function calendar()
{
   var monthNames = "JanFebMarAprMayJunJulAugSepOctNovDec";
   var today = new Date();
   var thisDay;
   var monthDays = new montharr(31, 28, 31, 30, 31, 30, 31, 31, 30,
      31, 30, 31);

   year = today.getYear() + 1900;
   thisDay = today.getDate();

   // do the classic leap year calculation
   if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
      monthDays[1] = 29;

   // figure out how many days this month will have...
   nDays = monthDays[today.getMonth()];

   // and go back to the first day of the month...
   firstDay = today;
   firstDay.setDate(1);
   // and figure out which day of the week it hits...
   startDay = firstDay.getDay();

   document.writeln("<CENTER>");
   document.write("<TABLE BORDER>");
   document.write("<TR><TH COLSPAN=7>");
   document.write(monthNames.substring(today.getMonth() * 3,
      (today.getMonth() + 1) * 3));
   document.write(". ");
   document.write(year);
   document.write("<TR><TH>Sun<TH>Mon<TH>Tue<TH>Wed<TH>Thu<TH>Fri<TH>Sat");

   // now write the blanks at the beginning of the calendar
   document.write("<TR>");
   column = 0;
   for (i=0; i<startDay; i++)
   {
      document.write("<TD>");
      column++;
   }

   for (i=1; i<=nDays; i++)
   {
      document.write("<TD>");
      if (i == thisDay)
         document.write("<FONT COLOR=\"#FF0000\">")
      document.write(i);
      if (i == thisDay)
         document.write("</FONT>")
      column++;
      if (column == 7)
      {
         document.write("<TR>"); // start a new row
         column = 0;
      }
   }
   document.write("</TABLE>");
   document.writeln("</CENTER>");
}

The function starts by defining variables that will be used later in the function, as well as defining an instance of the Date object called today and an instance of the montharr object (defined by the montharr() function), which contains 12 properties with the number of days in each month of the year.

The first step is to determine whether it is a leap year so that the value of monthDays[1] (for February) can be adjusted. This is done by using today.getYear() to get the current year and then using the following if statement to check whether the year is a leap year:

if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
      monthDays[1] = 29;

Next, the variable nDays is assigned the number of days in the current month. The index used in monthDays is the value returned by today.getMonth() because it returns an integer that corresponds to the indexes of the monthDays object.

A copy of today, called firstDay, is created, and the date is set to the first of the month using firstDay.setDate(1), in order to figure out the day of the week using startDay = firstDay.getDay(). You could have used today.setDate(1) and today.getDay(), but that would have made the script harder to read and understand.

The function then outputs the opening tags of the table and writes out the current month by using the substring() method on the variable monthNames. This is followed by writing the number of blank calendar spaces needed in the first row, using a for loop, which is covered in Chapter 7.

Next, another for loop is used to write out the dates of the month in sequence. The if statements with the condition (i== thisDay) are used to determine whether the text color should be changed for the current table cell.

The variable column is incremented throughout both for loops to keep track of which column of the seven-column table the current date is written into. If the date has been written into the seventh column, then the last if statement in the second loop starts a table row with the TR tag and resets column to zero.

Finally, the function writes out all the closing HTML for the table.