Skip to page content or skip to Accesskey List.
Search evolt.org
evolt.org login: or register

Work

Main Page Content

Building A Quick Countdown Application

Rated 3.94 (Ratings: 4) (Add your rating)

Log in to add a comment
(1 comment so far)

Want more?

 
Picture of mwarden

Matt Warden

Member info | Full bio

User since: May 18, 1999

Last login: December 11, 2009

Articles written: 7

Ever find yourself counting down the days until an event? A visit from an out-of-town friend? A trip to Chile? An upcoming evoltageddon? I know I do this quite often. I used to spend a lot of time staring at the Windows calendar, counting days. Then I got bored one rainy day...

The easiest way I found to write a countdown script was to break down time into the smallest unit needed. For this script, seconds will do just fine (it's more fun to watch seconds decrement than it is to watch minutes do the same). If you want to use milliseconds, well, it's your CPU.

The script involves two parts: one on the server side, and one on the client side (the entire thing could be client side, but it's much simpler to rely on a single clock than it is to rely on X clocks on client computers). Here's the basic rundown of what we have to do to create this countdown script:

  • Determine the relation between your time and the time on your server

On the server side...

  • Get the current server time in a variable
  • Store the "zero time" (the time at which the countdown should be zero based on on your server's clock!!!) in a variable
  • Find the difference, in seconds, between the current time and zero time (we'll call this iSecondsLeft for this article).
  • Set a variable to hold the remaining days. This value can be found by taking the whole integer portion only of the quotient of iSecondsLeft divided by 86,400 (60 seconds * 60 minutes * 24 hours)
  • Reassign iSecondsLeft to the result of iSecondsLeft modulus 86,400 *
  • Set a variable to hold the remaining hours. This value can be found by taking the whole integer portion only of the quotient of iSecondsLeft divided by 3,600 (60 seconds * 60 minutes).
  • Reassign iSecondsLeft to the result of iSecondsLeft modulus 3,600 *
  • Set a variable to hold the remaining minutes. This value can be found by taking the whole integer portion only of the quotient of iSecondsLeft divided by 60 (60 seconds).
  • Reassign iSecondsLeft to the result of iSecondsLeft modulus 60 *
  • You now have variables holding the remaining time broken down into days, hours, and seconds until the event.
  • Create text form fields (or other containers that may not degrade as well) and write the variables to the value attribute of each field.

* If you don't have the modulus operator available to you, you can achieve the same effect by using multiplication and subtraction. For instance, if you needed to calculate iSecondsLeft modulus 86,400 without using the modulus operator, you could use: iSecondsLeft - (numberOfDays * 86,400) and you will get the same value.

Now, at this point, you have enough to simply write out the remaining time. However, one second later this value will be inaccurate. You could refresh the screen every second, but then you're putting unnecessary strain on the server. The solution involves a balance between server and client. So, we need some scripting on the client:

On the client-side...

  • Add the function decrement() to the onLoad event handler of the <body> element
  • In the function decrement(), first check an iterations counter. If the counter is greater than 300 (or some other value determined by you), refresh the page. This ensures that the script is synched with the server clock every 300 seconds
  • If the iterations counter is below 300, decrement the seconds, taking into account the possibility that seconds are already at 0, in which case minutes have to be decremented and seconds set to 59, unless minutes are also at 0, in which case hours must be decremented and minutes have to be set to 59 and seconds have to be set to 59, and so on.
  • Finally, increment the iterations counter and set a timer to recall the function in one second (in JavaScript, you would do this by calling:
    setTimeout("decrement();", 1000);).

That's the basics. Below is an example implementation of the above idea. It is written in ASP and client-side JavaScript.

<%@EnableSessionState = False%>
<%
Response.Expires = 0

currentTime = Now()

destinationTime = CDate("8/15/2003 14:00:00")

iTotalSeconds = DateDiff("s", currentTime, destinationTime)

iSecondsLeft = iTotalSeconds

days = Fix(iSecondsLeft / (60 * 60 * 24))
iSecondsLeft = iSecondsLeft mod (60 * 60 * 24)

hours = Fix(iSecondsLeft/(60 * 60))
iSecondsLeft = iSecondsLeft mod (60 * 60)

minutes = Fix(iSecondsLeft / (60))
iSecondsLeft = iSecondsLeft mod 60

seconds = iSecondsLeft

%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html><head>
<script language="JavaScript" type="text/javascript">
<!-- hide from older browsers

iterations = 0;

function decrement()
{
	
if (iterations > 300)
{
	window.location = '<%Response.Write Request.ServerVariables("SCRIPT_NAME")%>';
}

sec = (document.fooform.sec.value)-0;
min = (document.fooform.min.value)-0;
hrs = (document.fooform.hrs.value)-0;
day = (document.fooform.day.value)-0;

// check first to see if there is any time left at all
// this is done by adding the time units and testing 
// its value
if ((sec+min+hrs+day) > 0)
{


if (sec > 0)
	document.fooform.sec.value = (sec-1);
else
{
	if (min > 0 )
		document.fooform.min.value = min-1;
	else
	{
		if (hrs > 0)
			document.fooform.hrs.value = hrs-1;
		else
		{
			if (day > 0)
				document.fooform.day.value = day-1;
			else
				document.fooform.day.value = 0;
			
			document.fooform.hrs.value = 23
		}
		
		document.fooform.min.value = 59
	}
	
	document.fooform.sec.value = 59;
}

setTimeout("decrement();", 1000);

}
else
{
	document.fooform.sec.style.color = "#cc0000";
	document.fooform.min.style.color = "#cc0000";
	document.fooform.hrs.style.color = "#cc0000";
	document.fooform.day.style.color = "#cc0000";
	
	alert("Evolt has taken over the world!");
}

iterations++;
}

// -->
</script>
<style type="text/css">
INPUT {
	font-family:  Verdana, Arial, Helvetica, sans-serif;
	font-size: 13px;
	width: 28px;
	border: none;
	text-align: right;
	background-color: #3399ff;
	color: #003399;
	font-weight: bold;
}

BODY {
	font-family:  Verdana, Arial, Helvetica, sans-serif;
	font-size: 13px;
	background-color: #3399ff;
	color: #003399;
}

P {
	width: 600px;
	text-align: center;
}
</style>
<title>Evolt's World Domination Timeline</title>
</head>

<body onLoad="decrement();">
<form name="fooform" id="fooform" action="<%Response.Write
Request.ServerVariables("SCRIPT_NAME")%>">

<p><a href="http://evolt.org/"><img
src="/evolt/evolt_logo.gif" border="0" alt="Evolt.org
logo" longdesc="http://evolt.org/evolt_images"></a></p>

<p style="padding-top: 30px;">Assuming no one <a
href="http://www.cia.gov/" target="_new">important</a> gets tipped off, Evolt's world
domination plan will have been executed in

<%
Response.Write	_
  "<input type=""text"" name=""day"" value=""" & days &
"""> days, " _
& "<input type=""text"" name=""hrs"" value=""" & hours &
"""> hours, " _
& "<input type=""text"" name=""min"" value=""" & minutes
& """> minutes, and " _
& "<input type=""text"" name=""sec"" value=""" & seconds
& """> seconds."
%>

</p>

<p>
A note to those important people: <strong>I'm just kidding</strong>.
</p>
</form>
</body>
</html>

Matt Warden spends his spare time writing up author bios for his accounts on various websites... er... you know what? It's all here somewhere anyways. No use repeating myself...

Nicely explained

Submitted by mcmonkey on March 28, 2002 - 19:18.

Good job, Matt.

If you want to get fancy, pull out months to go, in addition to days, hours, minutes, and seconds.

There are two methods of doing this. One is to build an array of days in each month, [31, 28, 31, ...], add up the entries between the current month and the target month, and subtract that number from the total number of days to go. Of course you'll have to build that array on demand in case of leap year. And what if the countdown period is more than one year in includes both a normal, stock February and the souped-up, leap February?

A second method is to get a difference in months, add the difference to the current date, and calculate the rest of your numbers from the modified date.

I choose the second method, an example of which can be found at www.catandsean.org in JavaScript. Feel free to borrow (the target date is declared in the script), but be warned. There’s an error in the calculations which throws off the display on the day of, but before, the event. Email me if you want the corrected code.

When you calculate the difference in months, you need to consider the current date in relation to the target date. For example, if today is March 28 and the event is April 29, the difference is 1 month and 1 day. If event is April 27, the difference is 0 months and 30 days, not 1 month and –1 day.

if (TargetDay

(The actual code is a little different to account for people counting months 1…12 with the computer counting 0…11.)

Then calculate your days, hours, minutes and seconds on the modified date.

futurestring=montharray[TargetMonth-1]+" "+ TargetDay +", "+ TargetYear+" "+ TargetHour+":"+ TargetMinute
TargetMonth_calc= CurrentMonth + difference_month
todaystring_calc=montharray[TargetMonth_calc]+" "+CurrentDay+", "+CurrentYear+" "+CurrentHour+":"+CurrentMinute+":"+CurrentSecond
difference_calc=Date.parse(futurestring)-Date.parse(todaystring_calc)

A little extra is a catch for correct english, e.g. “1 hour” rather than “1 hours”.

Thanks to djc for using this for his example on article validation, otherwise I would of missed it!

login or register to post comments

The access keys for this page are: ALT (Control on a Mac) plus:

evolt.orgEvolt.org is an all-volunteer resource for web developers made up of a discussion list, a browser archive, and member-submitted articles. This article is the property of its author, please do not redistribute or use elsewhere without checking with the author.