You are here: irt.org | Articles | JavaScript | Date and Time | Travelling Through Time [ previous next ]
Published on: Saturday 23rd August 1997 By: Martin Webb
This article will describe how to display and manipulate the current time, show the difference between two dates, show a countdown to and from a specific time and date, and how to trigger an event after a delay.
Within JavaScript there isn't a spearate Time object. However, the Date object provides methods for accessing the date and time.
The Date object has the following methods: eval, getDate, getDay, getHours, getMinutes, getMonth, getSeconds getTime, getTimezoneOffset, getYear, parse, setDate, setHours, setMinutes, setMonth, setSeconds, setTime, toGMTString, toLocaleString, toString, UTC, valueOf.
JavaScript stores the date as the number of milliseconds since January 1, 1970 00:00:00.
To create a date object we can use four different methods:
Once a date object has been created, then it keeps its original value until you change it. It doesn't automatically keep time, this is something you have to do yourself:
<SCRIPT LANGUAGE="JavaScript"><!-- var dateObject = new date(); // get the initial current date and time ... // lots of code in here ... dateObject = new date(); // get the current date and time again //--></SCRIPT>
As an example in the following form if you click show it will show the value of the date object, if you click update it will get the current date and time again and then show the value of the date object:
The script for the previous example is fairly simple, it first creates a global dateObject based on the Now date and time. It uses two onClick event handlers to invoke the showDateTime() and updateDateTime() functions, which either shows the value of dateObject or updates it then shows it.
Note, the use of the toString() method is required for Microsoft Internet Explorer 3.0, otherwise it chokes.
<SCRIPT LANGUAGE="JavaScript"><!-- var dateObject = new Date(); // get the initial current date and time function showDateTime() { document.showDateTimeForm.formField.value = dateObject.toString(); } function updateDateTime() { dateObject = new Date(); // get the current date and time again showDateTime(); } //--></SCRIPT> <FORM NAME="showDateTimeForm" onSubmit="return false;"> <INPUT TYPE="TEXT" NAME="formField" VALUE="" SIZE="42"> <INPUT TYPE="BUTTON" VALUE="Show" onClick="showDateTime()"> <INPUT TYPE="BUTTON" VALUE="Update" onClick="updateDateTime()"> </FORM>
The value held in a date object is not very user friendly. For example, on my system and browser the value I see is something like: Sun Aug 17 11:45:02 GMT Daylight Time 1997. This will obviously depend on things, suchas time zone, daylight saving, system settings, browser settings etc. It is fairly simple to format the date and time to show it in the format you want to show, for example 11:45:02am Sunday 17th August 1997. We can use the Date methods to extract the portions of the date we need and then reformat it anyway we like.
For example:
When using dateObject = new Date(1997, 8, 17, 11, 45, 02);:
When using dateObject = new Date(2065, 1, 4);:
We can use these methods to reformat the date:
<SCRIPT LANGUAGE="JavaScript"><!-- function formatDate1(year,month,date,hour,minute,second) { if (!year) year=0; if (!month) month=0; if (!date) date=0; if (!hour) hour=0; if (!minute) minute=0; if (!second) second=0; var dateObject = new Date(year,month,date,hour,minute,second); return dateObject.getHours() + ' ' + dateObject.getMinutes() + ' ' + dateObject.getSeconds() + ' ' + dateObject.getDay() + ' ' + dateObject.getDate() + ' ' + dateObject.getMonth() + ' ' + dateObject.getYear(); } document.write(formatDate1(1997, 8, 17, 11, 45, 02)+'<BR>'); document.write(formatDate1(2065, 1, 4)+'<BR>'); //--></SCRIPT>
Which when run produces the following:
Which doesn't quite give us what we want, but with the addition of some validation and further formatting:
<SCRIPT LANGUAGE="JavaScript"><!-- function padout(number) { return (number < 10) ? '0' + number : number; } function ampm(number) { return (number < 12) ? 'am' : 'pm'; } function y2k(number) { return (number < 1000) ? number + 1900 : number; } function nths(day) { if (day == 1 || day == 21 || day == 31) return 'st'; else if (day == 2 || day == 22) return 'nd'; else if (day == 3 || day == 23) return 'rd'; else return 'th'; } function makeArray0() { for (i = 0; i<makeArray0.arguments.length; i++) this[i] = makeArray0.arguments[i]; } var days = new makeArray0("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"); var months = new makeArray0('January','February','March','April','May','June','July','August','September','October','November','December'); function formatDate(year,month,date,hour,minute,second) { if (!year) year=0; if (!month) month=0; if (!date) date=0; if (!hour) hour=0; if (!minute) minute=0; if (!second) second=0; var dateObject = new Date(year,month,date,hour,minute,second); var myHours = dateObject.getHours(); var myMinutes = dateObject.getMinutes(); var mySeconds = dateObject.getSeconds(); var myDay = dateObject.getDay(); var myDate = dateObject.getDate(); var myMonth = dateObject.getMonth(); var myYear = dateObject.getYear(); return padout(myHours) + ':' + padout(myMinutes) + ':' + padout(mySeconds) + ampm(myHours) + ' ' + days[myDay] + ' ' + myDate + nths(myDate) + ' ' + months[myMonth] + ' ' + y2k(myYear); } document.write(formatDate(1997, 8, 17, 11, 45, 02)+'<BR>'); document.write(formatDate(2065, 1, 4)+'<BR>'); //--></SCRIPT>
The padout() function ensures that the number passed is padded with a leading zere, e.g. changes '9' to '09'. The ampm() function returns 'am' if the number passed is 12, else it returns 'pm'. The y2k() function converts dates less the year 2000 to 4 digits, e.g. changes '97' to '1997'. The makeArray0() function creates an array out of the text strings passed to it, it is then used to create the days[] and months[] arrays.
When run it produces the following:
How do you calculate the difference between, say for example, 11:45:02am Sunday 17th August 1997 and 18:00:00pm Wednesday 31st December 1997. If you convert the dates to the number of miliseconds since 1970 using the getTime() date object method, you can subtract the figures to give the difference in milliseconds, you can then convert this to days, hours, minutes, seconds:
<SCRIPT LANGUAGE="JavaScript"><!-- var date1 = new Date(97, 8, 17, 11, 45, 2); var date2 = new Date(97, 12, 31, 18, 0, 0); var milliseconds1 = date1.getTime(); var milliseconds2 = date2.getTime(); var difference = milliseconds2 - milliseconds1; document.write('difference in milliseconds = ' + difference + '<BR>'); document.write('difference in seconds = ' + difference/1000 + '<BR>'); document.write('difference in minutes = ' + difference/1000/60 + '<BR>'); document.write('difference in hours = ' + difference/1000/60/60 + '<BR>'); document.write('difference in days = ' + difference/1000/60/60/24 + '<BR>'); var daysDifference = Math.floor(difference/1000/60/60/24); difference = difference - daysDifference*1000*60*60*24 var hoursDifference = Math.floor(difference/1000/60/60); difference = difference - hoursDifference*1000*60*60 var minutesDifference = Math.floor(difference/1000/60); difference = difference - minutesDifference*1000*60 var secondsDifference = Math.floor(difference/1000); document.write('difference = ' + daysDifference + ' day/s ' + hoursDifference + ' hour/s ' + minutesDifference + ' minute/s ' + secondsDifference + ' second/s '); //--></SCRIPT>
Which when run produces the following:
Now that we know how to calculate the difference between two dates, we can continually perform this to create a countdown to a certain date, for example Christmas, the Millennium, the Grand Opening of your web site...
The following example extends the previous one, first the Show button on the differenceForm form uses the onClick event handler to pass a date object and a reference to the current forms formfield using this.form, to the setField() function. The setField() function then subtracts the difference between the when date passed and the date now using the date objects UTC() method.
It checks the value of the daysDifference to see if its negative, i.e. the when date is in the past. If it is then it multiplies the daysDifference by -1. This allows the setField function to be used as a countback as well as a countdown. To show this in action the example has two forms, one with the date of the millenium (i.e. 1st January 2001), the other using an historic date.
Finally it checks the current value of the referenced object form field, if its the same as the new value, then it won't update the form field. This gets rid of that annoying flicker when the field is updated with the same contents.
<SCRIPT LANGUAGE="JavaScript"><!-- function y2k(number) { return (number < 1000) ? number + 1900 : number; } function setField(when,object) { var now = new Date(); var difference = Date.UTC(y2k(when.getYear()),when.getMonth(),when.getDate(),when.getHours(),when.getMinutes(),when.getSeconds()) - Date.UTC(y2k(now.getYear()),now.getMonth(),now.getDate(),now.getHours(),now.getMinutes(),now.getSeconds()) var daysDifference = Math.floor(difference/1000/60/60/24); difference = difference - daysDifference*1000*60*60*24 var hoursDifference = Math.floor(difference/1000/60/60); difference = difference - hoursDifference*1000*60*60 var minutesDifference = Math.floor(difference/1000/60); difference = difference - minutesDifference*1000*60 var secondsDifference = Math.floor(difference/1000); if (daysDifference < 0) daysDifference = daysDifference * (-1); var fieldValue = daysDifference + ' days ' + hoursDifference + ' hours ' + minutesDifference + ' minutes ' + secondsDifference + ' seconds'; if (object.value != fieldValue) object.value = fieldValue; } //--></SCRIPT> <FORM NAME="differenceForm1" onSubmit="return false;"> <INPUT TYPE="TEXT" NAME="formField1" VALUE="" SIZE="42"> <INPUT TYPE="BUTTON" VALUE="Show" onClick="setField(new Date(2001, 1, 1),this.form.formField1)"> </FORM> <FORM NAME="differenceForm2" onSubmit="return false;"> <INPUT TYPE="TEXT" NAME="formField2" VALUE="" SIZE="42"> <INPUT TYPE="BUTTON" VALUE="Show" onClick="setField(new Date(1990, 1, 1),this.form.formField2)"> </FORM>
Why not press either of the the two Show buttons?
The previous examples rely on the user to press the buttons to update the displays each time. It is possible to automate this process so that the form fields are updated at regular intervals using the setTimeout() method.
The setTimeout() takes two parameters, the expression to be actioned, and the delay interval before actioning the expression.
For example setTimeout('alert("hello World"),5000); will invoke the alert("Hello World") every 5000 milliseconds, i.e every 5 seconds. Note the expression is a string, therefore JavaScripts statements that you want to be actioned need to be enclosed within quotes.
The next example use the same setField() function from the previous example. However it uses the the setTimeout() method to continually invoke the setCountdown() function every 0.5 second. The seTimeout() method is placed within the function it invokes, so that it continually invokes itself. This then means there has to be one initial call to the setCountdown() function to get the countdown started.
<FORM NAME="countdownForm" onSubmit="return false;"> <INPUT TYPE="TEXT" NAME="formField" VALUE="" SIZE="42"> till the new Millennium. </FORM> <SCRIPT LANGUAGE="JavaScript"><!-- function setCountdown() { setField(new Date(2001, 0, 1),document.countdownForm.formField); setTimeout('setCountdown()',500); } setCountdown(); //--></SCRIPT>
When run it looks like this:
Note, the setTimeout() method does not delay or suspend the script, as the following example will show:
<SCRIPT LANGUAGE="JavaScript"><!-- function test() { alert('1'); setTimeout('alert("2")',500); alert('3'); } //--></SCRIPT> <FORM><INPUT TYPE="BUTTON" VALUE="Press Me" onClick="test()"></FORM>
Why not try it out:
When run it shows the alerts as 1, 3, 2.
Note, be careful when using the setTimeout() method, if you use it to call script that writes to the current document, after the current document has been rendered, then it may overwrite the current document and any script it contains.
Extending "Born of the 4th of July"