From:
Subject: View Source: JavaScript Date Object Techniques
Date: Wed, 27 Mar 2002 15:03:40 +0100
MIME-Version: 1.0
Content-Type: multipart/related;
boundary="----=_NextPart_000_0050_01C1D5A0.945533E0";
type="text/html"
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
This is a multi-part message in MIME format.
------=_NextPart_000_0050_01C1D5A0.945533E0
Content-Type: text/html;
charset="Windows-1252"
Content-Transfer-Encoding: quoted-printable
Content-Location: http://developer.netscape.com/viewsource/goodman_dateobject.html
View Source: JavaScript Date Object =
Techniques
Readers who belonged to the Macintosh community about ten years ago =
may=20
remember my personal information management (PIM) commercial product, =
called=20
Focal Point. One of the modules of this PIM was the ever-popular =
appointment=20
calendar. Perhaps the most valuable lessons I learned from creating and=20
upgrading that application were the intricacies of programming dates and =
time,=20
both the internal algorithms and user interfaces designed for a =
worldwide=20
audience.
This experience makes me, I suppose, hypersensitive to the =
implementation of=20
date and time in a programming environment, such as JavaScript. Not that =
I have=20
any intention of implementing an appointment calendar in JavaScript. =
(Except as=20
a client-side assistant to a substantial server-based program, the =
language is=20
not suited to this kind of application.) But given the powers of the =
Date object=20
in JavaScript in Navigator 3.0, I'm surprised by the lack of date- and=20
time-oriented scripting in Web pages.
The purpose of this article is to explain the concepts behind =
JavaScript's=20
Date object and describe a few practical implications of this object in =
both=20
plain and forms-based HTML pages. Along the way, I'll also point out =
some of the=20
pitfalls and bugs you'll need to work around, including a few recent=20
discoveries.
Note: There were many global and platform-specific structural =
changes=20
to the Date object between Navigator versions 2 and 3. This article =
discusses=20
the Date object only as implemented in Navigator 3. Communicator will =
likely=20
follow the Navigator 3 mold as well as deal with the gremlins described =
later in=20
this article.
WHERE THE DATE =
OBJECT COMES FROM=20
Many scripters have seen the JavaScript object roadmap from my book=20
(available in Adobe =
Acrobat=20
format as a free FTP=20
download). In this roadmap, the Date object stands apart from the=20
window-document object hierarchy, because a Date is a computational =
object,=20
rather than one that reflects "physical" elements in an HTML page. The =
object=20
has no fewer than 22 methods that give the scripter access to every time =
and=20
date component of the object.
The idea for the Date object and its methods didn't fall out of the =
sky as a=20
feature unique to JavaScript. No, the syntax is borrowed directly from =
Java 1.0.=20
In fact, once you master the JavaScript Date object, you will have also =
mastered=20
95 percent of Java's Date object. (Note: Java 1.1 has enhanced date =
handling=20
powers with a new object called Calendar.)
CREATING A BASIC =
DATE OBJECT
Its Java heritage explains why using the Date object requires what in =
Java is=20
a very common occurrence: creating an instance =
of--instantiating--the=20
object before any statement can examine, change, or perform =
operations on=20
a date. For example, to create a default Date object (whose date is =
today's date=20
as indicated by the client system's internal clock), the syntax is the=20
following:
var today =3D new Date()
When no parameters accompany the Date() object constructor,=20
JavaScript automatically reads the client's internal clock setting, and =
creates=20
the object with the date and time at the instant at which the object is =
created.=20
Therefore, after executing the above statement, the arbitrarily-named=20
variable today is a reference to a Date object in memory that =
holds the=20
current date and time. In other words, the object takes a snapshot of =
the=20
client's system clock; the content of this date/time "photo" doesn't =
change=20
unless a script statement invokes one of the Date object's methods that =
modifies=20
the object.
There are several more interesting ways to create a Date object -- =
all of=20
which entail assigning a specific date and time to the object other than =
the=20
current moment. For the sake of completeness the table "Date Object=20
Constructors," shows all Date object constructor formats for assigning =
specific=20
dates.
Date Object Constructors
Syntax
Example
new Date("Month dd, yyyy hh:mm:ss")
new Date("September 11, 1997 08:30:00")
new Date("Month dd, yyyy")
new Date("September 11, 1997")
new Date(yy,mm,dd,hh,mm,ss)
new Date(97,8,11,8,30,00)
new Date(yy,mm,dd)
new Date(97,8,11)
new Date(GMTmilliseconds)
new Date(873991800000)
To fully appreciate how these Date object constructors work, let's =
put the=20
Date object under a microscope to see what it's doing internally.
INSIDE THE DATE =
OBJECT
When you create a Date object with the current time and date, there =
is a lot=20
more going on inside JavaScript than you may be aware of. If you have =
trouble=20
figuring out what time it is in a neighboring time zone, then the Date =
object's=20
innards are going to make your head hurt.
To truly understand all of this, you need a working knowledge of the=20
recognized world time reference point, which runs through Greenwich, =
England.=20
Two common names for this time zone are Greenwich Mean Time (GMT) and=20
Coordinated Universal Time (UTC). Although there are tiny differences =
between=20
the two (the difference between atomic clocks and astronomical =
observations),=20
for our purposes, we can regard them as equals. If you are interested in =
how=20
these terms came about, excellent on-line sources include The Time Service =
Department=20
of the U.S. Naval Observatory and Greenwich =
2000.
The basic point to understand about GMT and time zones around the =
world is=20
that if you know the time at GMT, you can determine the local time =
anywhere on=20
the planet, because each time zone is measured relative to GMT, by =
international=20
convention. When the sun is directly overhead the GMT zone, for example, =
all=20
time zones to the east (through Russia, Asia, Australia, and part way =
across the=20
Pacific Ocean until you reach the International Date Line) are later in =
the day=20
than noon; the noon-day sun has already been there, done that. =
Conversely, all=20
time zones to the west (across the Atlantic, through North and South =
America,=20
and onward across the Pacific up to the date line) are earlier in the =
day, and=20
have lunchtime to look forward to. The figure "World Time Relative to =
Noon GMT"=20
represents a snapshot of the world's time at exactly noon GMT.=20
World Time Relative to Noon GMT
To eliminate the vaguaries of the world's time zones (some of which =
shift=20
during part of the year for the equivalent of America's Daylight Saving =
Time),=20
the JavaScript (and Java) Date object stores its information as GMT =
time. More=20
precisely, the date value is stored as the number of milliseconds before =
(positive) or after (negative) zero hours GMT on January 1, 1970.
DATE OBJECT VALUES
If you have played at all with the Date object, you may be quite =
confused=20
about why GMT has to come into the picture at all. After all, if you sit =
in=20
front of a Windows-based PC at Netscape's world headquarters in Mountain =
View,=20
California, and get the value of the current date and time, you see a =
value that=20
looks like this:
Thu Mar 20 23:09:48 Pacific Standard Time 1997
On a Mac OS computer in the same location, the value looks like =
this:
Thu Mar 20 23:09:48 1997
Take a look at the example in "Try=20
it on Your Client" to see how it looks in your system. What you see =
there,=20
however, is the Date object being automatically converted to your =
client's time=20
zone--even though it's the GMT date and time that's stored in the Date =
object.=20
Also, when you use the Date object methods that get and set components =
of a Date=20
object (year, month, date, day of the week, hour, minute, and second), =
those=20
values are reflected in your client's local time, not GMT. In fact, the =
only=20
values that reveal the Date object's GMT date are the millisecond =
measurement=20
(accessible via the getTime() method) and the GMT string =
conversion=20
(via the toGMTString() method).
Try It On Your Client
See how the Date object reveals its value to your client =
software:
Here's a string representation of the Date object:
All of these conversions to local time, of course, rely on the proper =
setting=20
of the client computer's clock and relevant Control Panel settings about =
the=20
time zone of the computer's physical location. In a sense, this is a =
wild-card=20
issue; as a scripter, you can never be sure that the client's clock and =
time=20
zone are set correctly.
DATE OBJECT METHODS AND VALUES
Given the potential confusion between GMT and local date and time =
values, I=20
think it's a good idea to look at some specific values of a Date =
object's=20
components and see precisely which values are GMT-based and which are =
local. The=20
table "Date=20
Object Methods"shows all Date object methods and examples of =
their=20
values. (For more details on the syntax, see the Date object discussion =
in the=20
"Navigator Handbook JavaScript Guide.") In the Method =
column of=20
the table, dateObj is a placeholder for any variable that =
references a=20
previously created Date object. You can experiment with a number of =
dates and=20
time selections while viewing the results in the table.
Date Object Methods
OBTAINING AN ACCURATE =
DATE
Because your scripts are at the mercy of an accurate client clock =
setting, I=20
don't advise relying exclusively on the client to supply the precise GMT =
time=20
value if your application needs that data for a form's date or time =
field. For=20
example, if it requires the exact time of a form submission, you might =
want to=20
use a form submission CGI do the timestamping with the server's clock =
(assuming=20
you have control over that machine's clock settings).
If your scripts use dates for calculations or comparisons, consider =
carefully=20
how you generate Date objects. Bear in mind that visitors are most =
likely to be=20
located in time zones other than yours. Therefore, if you attempt to =
create a=20
Date object for a specific date and time, the GMT Date object value for =
visitors=20
from other time zones will be different than the value you used to test =
out your=20
page. Consider the following Date object constructor statement:
var myDate =3D new Date(1997,11,24,18,0,0) =
Those constructor values represent 6:00 P.M. =
on December=20
24, 1997. For someone in the Eastern Standard Time zone, the object's =
GMT value=20
of myDate is 11:00 P.M. on December 24; =
for=20
someone in the Pacific Standard Time zone, the object's GMT value is =
2:00 A.M. on December 25.
To establish a firm GMT date and time in an object, you need to use =
one of=20
the last two methods of "Date=20
Object Methods" (Date.parse() and Date.UTC()) to =
first=20
obtain the GMT millisecond value. You can then use that millisecond =
value as a=20
parameter to the Date() constructor.
Each of these methods requires a specific parameter to do its =
job.=20
Date.UTC() may be the simpler of the two to use, provided you know =
the GMT=20
time you wish to create. The parameters consist of a comma-delimited =
list of=20
integer values corresponding to the year, month, date, hour, minute, and =
second,=20
in that order. That's what I used in the example shown just=20
above.
If you aren't comfortable with converting your local time to GMT just =
yet,=20
you can use the Date.parse() method instead. Its parameter is a =
string=20
patterned after a date format established by the Internet Engineering =
Task Force.=20
What I like about this format is that you can specify either the GMT =
time or the=20
local time along with an offset from GMT. For example, let's say you are =
in New=20
York (Eastern Standard Time) and want to create a Date object that =
corresponds=20
to 6:00 P.M. EST on Christmas Eve. Any of the =
following=20
statements will do the trick:
var myDate =3D new Date("24 Dec 1997 23:00:00 GMT") var myDate =
=3D new=20
Date("24 Dec 1997 18:00:00 GMT+0500") var myDate =3D new Date("24 Dec =
1997=20
18:00:00 EST")
In the second version, the GMT+0500 indicates that the time =
zone is=20
five hours west of GMT. JavaScript (as influenced by Java) also knows =
the most=20
common time zone abbreviations used in the western hemisphere =
(EST,=20
EDT, CST, CDT, MST, MDT, =
PST,=20
and PDT). That no other time zones are allowed is a sign that =
the Java=20
model suffers from an American myopia when it comes to global dates and =
times.=20
Even so, the application of the GMT format, plus or minus an amount of =
time=20
represented by the hhmm value after GMT, means that =
this=20
system can be used around the Globe.
DOING THE MATH =
When it comes to scripting date calculations, such as the number of =
days=20
between dates or the date six weeks from today, you can use the =
milliseconds=20
value of Date objects. I also find it convenient to define some global =
variables=20
in documents that perform date arithmetic, as shown in the =
following:
var MINUTE =3D 60 * 1000 var HOUR =3D MINUTE * 60 var DAY =
=3D HOUR *=20
24 var WEEK =3D DAY * 7
I use all uppercase names because I treat these values like constants =
-- a=20
common stylistic convention. With these variables predefined, I can use =
them as=20
shortcuts in calculations. For example, to calculate the number of days =
between=20
dates, take the difference between two Date object values and then =
divide that=20
by the DAY variable, as shown here:
var today =3D new Date() var xmas =3D new =
Date(1997,11,25) var=20
shoppingDays =3D (xmas - today) / DAY
Notice that you can subtract two Date objects directly to determine =
their=20
difference in milliseconds. But for other calculations involving Date =
objects=20
and other value types, you must first convert the objects to =
milliseconds via=20
the getTime() method. For example, say you want to create a new =
object, futureDate, with the date and time for precisely six =
weeks from=20
now. First, you'd capture the current date as (GMT) milliseconds; next, =
you'd=20
add that value to six times the product of the WEEK global =
variable, as=20
shown in the following code:
var today =3D (new Date()).getTime() var futureDate =3D new =
Date(today +=20
(WEEK * 6))
SOME BUGS AND=20
GREMLINS
The most difficult part of working with the Date object is dealing =
with some=20
platform-specific bugs (primarily on the Mac OS platform) and one =
annoying=20
inconsistency.
The Mac OS version of Navigator 3 exhibits a couple of problems you =
should be=20
aware of. One occurs only when the Date & Time control panel has =
Daylight=20
Saving time turned on. When Daylight Saving is engaged, JavaScript =
miscalculates=20
the conversion between local and GMT date values by one hour (in =
Navigator 2,=20
this discrepancy was an entire day). For example, consider the following =
Date=20
object constructor and the result:
new Date("July 4, 1997 =
12:00:00")
// result on Daylight Saving Mac --> Fri Jul 4 13:00:00 1997
To handle this problem, I define one more global variable in any page =
that=20
includes date calculations. This variable, DATEADJUSTMENT, is=20
calculated for every platform, just in case there's an unknown bug =
lurking on a=20
platform I can't test. Here are the statements that set the =
variable:
function adjustDate() {
var base =3D new Date()
var testDate =3D base
testDate =3D testDate.toLocaleString()
testDate =3D new Date(testDate)
DATEADJUSTMENT =3D testDate.getTime() - base.getTime()
}
Each time a new date is created, the DATEADJUSTMENT value =
must be=20
subtracted from it. The process of creating an accurate Date object this =
way=20
requires that you create two Date objects; the adjustment must be =
factored for=20
both constructors, as shown in the following:
var nowInMS =3D (new Date().getTime() - (2 * =
DATEADJUSTMENT) var=20
nowDateObject =3D new Date(nowInMS)
When this date adjustment bug doesn't afflict the client, the =
variable does=20
contain a small number of milliseconds (the time it takes to execute the =
adjustDate() function). But unless you're calculating times at =
that=20
granularity, the tiny adjustment won't affect normal date and time=20
calculations.
MAC OS TIME=20
ZONES
Another, more serious bug affects Mac OS users whose time zone =
settings place=20
them at GMT or eastward to the International Date Line. The problem is =
that=20
JavaScript miscalculates the time zone offset entirely, causing Date =
objects=20
created from the internal clock or via constructors that use local =
values (that=20
is, all but the constructor for GMT milliseconds) to be one full day =
later than=20
the intended date.
At the heart of the matter is that, on the Mac OS, JavaScript counts =
the time=20
zone offset westward from GMT all the way around the Globe instead of =
using=20
negative numbers east from the GMT to the International Date Line. The =
time zone=20
offset for Sydney, Australia, should be -600; on Mac OS computers, =
however,=20
JavaScript renders it as a positive 840. The erroneous counting =
continues all=20
the way to GMT, whose offset value is rendered as 1440 (60 minutes times =
24=20
zones) instead of zero.
The strange behavior here is that the Mac OS reflects the proper =
local time=20
and date components but gets the Date object GMT value wrong by one full =
day.=20
Therefore, if your script requires an accurate GMT version of the local =
date,=20
the script needs to factor this zone error whenever the GMT value is=20
involved.
To adjust for this potential error, I add one more global variable =
definition=20
to the adjustDate() function, as follows:
function =
adjustDate() {
var base =3D new Date()
var testDate =3D base
testDate =3D testDate.toLocaleString()
testDate =3D new Date(testDate)
DATEADJUSTMENT =3D testDate.getTime() - base.getTime() - zoneError
ZONEERROR =3D (base.getTimezoneOffset() >=3D 720) ? DAY : 0
}
To create a Date object with the corrected GMT value, here is how to =
use both=20
date adjustment global variables:
var nowInMS =3D (new Date().getTime() - (2 * DATEADJUSTMENT) -=20
ZONEERROR) var nowDateObject =3D new Date(nowInMS)
This last code sample works accurately on all Navigator 3.0 platforms =
that=20
I've been able to test by setting them to a variety of time zones around =
the=20
world.
ONE INCONSISTENCY
JavaScript makes one departure from the Java Date object that could =
have a=20
negative impact on scripts using dates that reach to the year 2000 and =
beyond.=20
This isn't a "Year 2000" problem per se, but you need to script around =
the=20
problem just the same, at least until the problem is fixed in a future=20
release.
At issue is the way JavaScript treats the year component of a Date =
object.=20
According to the Java specification, years are integers after the year =
1900. In=20
other words, if you use the getYear() method for a Date object =
that=20
holds a 1997 date, the returned value should be 97. This is how both =
Java and=20
JavaScript work for dates prior to 2000.
Java, however, remains true to the algorithm into the future, where =
the year=20
2001 is represented by 101. JavaScript, however, treats all years =
beginning with=20
2000 as the actual year value: 2001 is 2001. This jump in values could =
trip up a=20
script that relies on a returned year value in sequence with years prior =
to=20
2000.
I prefer to do away with ambiguities such as starting the year counts =
with=20
1900. Therefore, I recommend processing all values that come from =
the=20
getYear() method through a filter function that adds 1900 to any =
returned=20
value that is less than 100. The good news is that the setYear() =
method=20
and all Date object constructors that take an integer value for the year =
accurately handle four-digit numbers. Use 'em.
ONE LAST COMPATIBILITY TIDBIT
While I have not performed exhaustive tests on all Navigator =
platforms, the=20
most intelligent implementation I've seen is on the Windows 95 platform. =
At=20
least for North America, if you specify in the Date/Time control panel =
that you=20
want Windows 95 to automatically adjust your clock for Daylight Saving, =
your=20
Date object handling gets an added bonus: The correct offset to GMT is=20
calculated for you for any date throughout the year.
For example, Pacific Standard Time is eight hours earlier than GMT, =
while=20
Pacific Daylight Time is seven hours earlier. If you live in the Pacific =
time=20
zone and create a Date object for local noon in December (when standard =
time is=20
in effect), the GMT equivalent is set to 8:00 P.M. If you=20
create a Date object for noon on some day in August, though, the GMT =
equivalent=20
is properly set to 7:00 P.M.wno matter what time =
of year=20
the script runs to create that object. This is very smart.
In contrast, the GMT offset for Daylight Saving time on the Mac OS is =
governed by the current state of the system clock -- whether or not =
Daylight=20
Saving time is turned on. Therefore, if you are in the winter months in =
North=20
America and create a Date object for a July 4 fireworks event at 9:00 =
P.M., the GMT time will be calculated on the winter =
months'=20
standard time offset. When July comes around, the Daylight Saving =
conversion=20
will display the event as starting at 10:00 P.M.--too bad=20
you missed the show.
It can be fun to experiment with changes to the control panels and =
their=20
effects on the Date object. Be aware, however, that Navigator 3 picks up =
information about the client's clock setting (and time zone offset) when =
it=20
launches. If you make a change to the control panel, you must quit and =
relaunch=20
Navigator for the changes to affect your script experiments.
DATE OBJECT VALIDATION
It may be tempting to use the Date object as a way to help validate =
date and=20
time entries in forms whose fields get submitted to CGI programs for =
further=20
processing. What's easy to forget, however, is that there are numerous =
accepted=20
date and time formats in use around the world. Unless you've used =
software=20
that's been localized for other countries, you probably haven't seen the =
large=20
variety of formats currently in use. In the United States, for example, =
the=20
short date format is mm/dd/yyyy. In many other parts of the world, the =
month and=20
date positions are switched. In still other parts of the world, there =
might be=20
different delimiter characters between the components, such as a dash =
(-) or a=20
period (.) instead of a slash (/). The same is true for time =
formats.
The JavaScript Date object is not smart enough to know whether =
3/4/1997 is=20
March 4, 1997, or April 3, 1997. Nor can any script that you write parse =
such a=20
text field entry. And just because you supply a sample entry in your =
form or=20
label doesn't mean that the visitor will follow it.
All of this leads me to suggest that you divide date and time entry =
fields=20
into multiple components, each of which can be easily validated with =
JavaScript.=20
For example, the following form, "Example Form," provides three fields =
for date=20
entry, each of which is backed up by a healthy validation script to =
check for=20
range and integers.
To view the source code for this form and validation functions, click here.
You can even do away with all the validation scripts entirely by =
setting up=20
the data entry components as Select objects. You saw an example of this =
earlier=20
in the table "Date=20
Object Methods." With this scheme, there is no possible way for =
incorrect=20
data to slip through.
Other options for date selection include Java calendar applets (in =
which the=20
visitor navigates to the desired month, and clicks on the desired date) =
and even=20
creating dynamic calendars with JavaScript in separate frames. Let your =
page=20
design rule the best way to evoke a date or time entry from =
visitors.
SUMMARY
As this lengthy examination of the Date object implies, scripting =
dates and=20
times is not necessarily the easiest task imaginable for enhancing your =
Web=20
pages. But that might signal an opportunity to help users navigate dates =
and=20
times in a way that distinguishes your pages from the crowd. For =
example, I push=20
the envelope a bit in some parts of my own Web site by combining date =
conversions and=20
arithmetic along with the HTTP cookie. I do this to point out all =
areas of=20
a page that have been updated since the visitor's last time at the =
pageweven=20
though I may have been through several update cycles in the =
meantime.
To accomplish an application such as this requires in-depth study of =
the Date=20
object and lots of experimentation with clock and time zone settings of=20
Navigator client platforms. I'm convinced, however, that there are many =
great=20
ideas out there waiting to be discovered for want of an understanding of =
the=20
Date object. If this article inspires you, let View =
Source=20
know what you've accomplished. We'll be glad to point the world to your=20
masterpiece.
View Source wants your feedback! Write to=20
us and let us know what you think of this article.
Author and consultant Danny=20
Goodman's 25th book is theJavaScript Bible, the updated 2d edition of his =
bestselling=20
JavaScript Handbook, published by IDG Books. His next title, =
arriving at=20
the end of February 1997, is The Official Marimba Guide to Bongo, =
published by Sams.net.