Previous Page
Next Page

Creating a Countdown

Sooner or later, you'll want to put a countdown on your pages that tells the user how many days or hours until a particular event. Script 13.8 (HTML) and Script 13.9 (JavaScript) lets one of the authors know his responsibilities, in no uncertain terms, as you can see in Figure 13.6.

Script 13.8. The HTML for the countdown script.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
     <title>Dynamic Countdown</title>
     <script language="Javascript" type="text/ javascript" src="script06.js">
     </script>
</head>
<body bgcolor="#FFFFFF">
     <p>Dori says:</p>
     <p>It's only <span class="daysTill" id="bday"> </span> days until my birthday and 
<span class="daysTill" id="xmas"> </span> days until Christmas, so you'd better start 
shopping now!</p>
     <p>And it's only <span class="daysTill" id="anniv"> </span> days until our 
anniversary...</p>
</body>
</html>

Script 13.9. This script counts down the number of days Tom stays out of the doghouse.

window.onload = showDays;

function showDays() {
     var allTags = document.getElementsByTagName("*");

     for (var i=0;i<allTags.length; i++) {
        if (allTags[i].className.indexOf("daysTill") > -1) {
           allTags[i].innerHTML = showTheDaysTill(allTags[i].id);
        }
     }

     function showTheDaysTill(thisDate) {
        var theDays;

        switch(thisDate) {
           case "anniv":
              theDays = daysTill(5,6);
              break;
           case "bday":
              theDays = daysTill(8,7);
              break;
           case "xmas":
              theDays = daysTill(12,25);
              break;
           default:
        }
        return theDays + " ";
     }

     function daysTill(mm,dd) {
        var now = new Date();
        var inDate = new Date(now.getFullYear(),mm-1,dd);
        if (inDate.getTime() < now.getTime()) {
           inDate.setYear(now.getFullYear()+1);
        }

        return (Math.ceil(dayToDays(inDate) - dayToDays(now)));
     }

     function dayToDays(inTime) {
        return (inTime.getTime() / (1000 * 60 * 60 * 24));
     }
}

Figure 13.6. Loading this page gives one of the authors his marching orders.


To create a countdown:

1.
var allTags = document. getElementsByTagName("*");



Create a new allTags array, and fill it with every tag on the page.

2.
for (var i=0;i<allTags.length; i++) {
  if (allTags[i].className. indexOf("daysTill") > -1) {
    allTags[i].innerHTML = showTheDaysTill(allTags[i].id);
  }



This loop scans through allTags to see if the string daysTill is found in the class attribute of any tags on the page. Remember that a tag could have multiple class attributes (i.e., class="firstClass daysTill somethingElse fourthThing").

If we found daysTill, we call the showTheDaysTill() function, which is passed one parameter: that tag's id (which stores what date to put up on the page). That function returns a value that is then put into innerHTML.

3.
switch(thisDate) {
  case "anniv":
     theDays = daysTill(5,6);
     break;
  case "bday":
     theDays = daysTill(8,7);
     break;
  case "xmas":
     theDays = daysTill(12,25);
     break;
     default:



If you don't remember the switch/case multi-level conditionals, you can review the discussion in Chapter 3. Here, we are using the value of thisDate to test against the three case statements. For the anniv case, we're setting theDays to May 6 (5,6 is the numerical representation, much like you would write it in the real world); for bday, we're setting it to August 7; and for xmas, theDays gets set to December 25.

4.
return theDays + " ";



The showTheDays() function ends by returning the number of days followed by a space. This is to work around a problem in IE: it eats the spaces in the HTML. If the script doesn't return a space at the end, the number runs into the word "days". If you just stuck the word "days" into this function, then there'd need to be a space after that, and so on.

5.
function daysTill(mm,dd) {
  var now = new Date();
  var inDate = new Date (now.getFullYear(),mm-1,dd);



This step shows the daysTill() function, which receives the dates from the case statements in step 3. Then, we create the now and inDate variables. The latter variable is filled with the current year, but with the month (with 1 subtracted from it to get it right; see the "More Weird Time Stuff" sidebar) and the day that were passed in.

6.
if (inDate.getTime() <> now.getTime()) {
  inDate.setYear (now.getFullYear()+1);
}



We then check that date against today. If that date in this year has already passed, we increment the year, going for next year's instead.

7.
return (Math.ceil(dayToDays(inDate) - dayToDays(now)));



Here, we're calculating the number of days between inDate and the current date. The Math.ceil() method makes sure that our result is a whole number.

8.
function dayToDays(inTime) {
  return (inTime.getTime() / (1000 * 60 * 60 * 24));



JavaScript stores dates in milliseconds since January 1, 1970. In order to compare two dates, change this to be the number of days since January 1, 1970. First, get the number of milliseconds in a day by multiplying 1000 (the number of milliseconds in a second) by 60 (number of seconds in a minute), by 60 again (number of minutes in an hour), and then by 24 (number of hours in a day). Dividing the number of milliseconds returned by getTime() by this number gives the number of days since January 1, 1970.

More Weird Time Stuff

Month numbering in JavaScript begins with 0 and day numbering with 1, and JavaScript deals inconsistently with years prior to 1970, depending on the version of JavaScript your browser is using.

Navigator 2 (using JavaScript 1.0) couldn't deal with years before 1970 at all and had a Year 2000 Problem, as it returned the wrong answer for dates in or after 2000. Navigator 3 (which used JavaScript 1.1) supposedly changed the value returned by the getYear() method to be two digits if the year is in the 1900s and four digits if the year was before 1900 or after 2000. However, this is not true for all versions of Netscape; for example, Netscape Navigator 4 for Mac returns 100 for the year 2000. And to make things even worse, this still occurs in Firefoxthe current version (1.5) still returns numbers in the hundreds (versus in the 2000s) for getYear().

JavaScript 1.2 (in Navigator 4, and also in ECMAScript-compatible browsers such as Internet Explorer 4 and later) introduced a new method, getFullYear(), which always returns four-digit years. We recommend that you use getFullYear() any time you know that you'll only be working with version 4 and later browsers, so that's what we're using throughout this book.

The getTime() method in JavaScript, for reasons probably best left unexplored, returns a number that is the number of milliseconds since January 1, 1970. Luckily, we hardly ever have to look at that number, as there have been a whopping number of milliseconds in the past three decades.



Previous Page
Next Page