reptile7's JavaScript blog
Tuesday, December 03, 2013
The Christmas Countdown
Blog Entry #308

I see that the Java Goodies: Scripts that Display Text script collection sports a "How Many Days Until Christmas?" script, which I thought we might check over given that the year-end holiday season is officially under way. Dating to September 1997, the "Days Until Christmas" script determines the number of days until Christmas and then places on the page a "Did you know that there's only X days left until Christmas" message; as such it is closely related to the HTML Goodies JavaScript Script Tips #29-30 script, which similarly counted down the number of days until Y2K and which we dissected in Blog Entry #62. The "Days Until Christmas" script and the Script Tips #29-30 script were both authored by Jari Aarniala.

The "Days Until Christmas" script's demo page is here; the days number is wildly off for reasons we will discuss below.

The script

(Mozilla's Date object page provides links to separate pages for the getTime( ), getYear( ), setYear( ), getFullYear( ), and setFullYear( ) methods that are mentioned in this section.)

The "Days Until Christmas" script is a short one so let me give it to you in one go:

Did you know that there's
<script name="JavaScript">
today = new Date( );
xmas = new Date("December 25, 1997");
xmas.setYear = today.getYear;
daysLeft = (xmas.getTime( ) - today.getTime( )) / (1000 * 60 * 60 * 24);
daysLeft = Math.round(daysLeft);
document.write("only " + daysLeft + " days left until Christmas");

Quick deconstruction

(1) Separate Date objects
(a) for right this moment and
(b) for 12 AM Christmas 1997
are created and respectively assigned to today and xmas variables.

(2) The xmas year is set to the today year. (We wouldn't want to be stuck in 1997, would we?)

(3) The xmas and today getTime( ) returns are subtracted to give the number of milliseconds spanning xmas and today; the milliseconds span is divided by the number of milliseconds in a day to give the number of days spanning xmas and today; the days span is assigned to a daysLeft variable.

(4) daysLeft is rounded up or down to the nearest integer by the Math object's round( ) method.

(5) The integerized daysLeft is concatenated with "only " and " days left until Christmas" strings and the resulting string is appended to some pre-<script> text to give the complete Christmas countdown message.

The small stuff

• The script element does not have a name attribute; a type="text/javascript" attribute is of course what we want.

• The December 25, 1997 dateString argument should be specified as Dec 25, 1997 - see this section of RFC 2822.

• We don't need to reach for the getTime( ) method to determine the number of milliseconds spanning xmas and today: a simple xmas - today subtraction will suffice.

• If you want the daysLeft span to always include the current day - I want the daysLeft span to always include the current day - then you should not Math.round( ) daysLeft but instead 'ceil' it with a Math.ceil(daysLeft) command.

The problem

It's the xmas.setYear = today.getYear; line that throws a spanner into the works, however; this statement is problematic for two reasons:
(A) It does not actually copy the today year to xmas.
(B) It attempts to make use of the deprecated (read: obsolete) getYear( ) and setYear( ) methods, which are not suited for comparing a pre-2000 Date with a post-2000 Date.

Although it is true that a method is ultimately a property of the object with which it is associated, the today.getYear expression does not evaluate to the today.getYear( ) return and the xmas.setYear = today.getYear; assignment has no effect on the xmas.getYear( ) return; as a result, the original script was really only good for 1997. (This is not to say that the script 'doesn't work' for other years, it just won't give the daysLeft value that you want it to.) For what Jari was trying to do, the correct syntax is:

xmas.setYear(today.getYear( ));

The preceding command would have been OK for 1998 and 1999 but for 2000 and beyond we'll need to use the getFullYear( ) and setFullYear( ) methods instead:

xmas.setFullYear(today.getFullYear( ));

The last six days of the year

Now, what if Christmas has just passed and we're in the 26 December-to-31 December period and we want to know how many days there are before the next Christmas? The above getFullYear( )/setFullYear( ) command places xmas at this year's Christmas; subsequently we can push xmas to next year's Christmas via the following conditional:

if (today > xmas) xmas.setFullYear(today.getFullYear( ) + 1);

The 24th of December

And what if it's 24 December and you would like the script to print out "1 day" as opposed to "1 days"? Why, I think we can arrange that:

var plur_or_sing = daysLeft != 1 ? " days " : " day ";
document.write("only " + daysLeft + plur_or_sing + "left until Christmas?");
/* The ?: conditional operator is detailed here in the Mozilla JavaScript Reference. */


Demo notes

Per the More structure section of the previous post, the demo's countdown message is written to the page by assigning it to the innerHTML property of an id="countdownDiv" div element.

In place of the xmas Date I use a thisyearXmas Date that has today's year from the get-go:

var thisyearXmas = new Date(today.getFullYear( ), 11, 25);

The countdownDiv div's text characters are alternately colored red and green by functionality taken from the HTML Goodies JavaScript Script Tips #81-83 script, which we deconstructed in Blog Entry #99. Moreover, I apply to the text a monospace font to accentuate the alternating colors.

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)