reptile7's JavaScript blog
Thursday, February 18, 2010
 
The Date Object and Its Discontents
Blog Entry #171

HTML Goodies' "Beyond HTML : JavaScript" portal page links not once but twice to a "JavaScript Date/Time Methods" series of four tutorials authored by Vince Barnes. A slog through the Internet Archive's HTML Goodies timeline suggests that the "JavaScript Date/Time Methods" series was written in early 2005, well after the late-1990s period during which Joe Burns wrote HTML Goodies' original JavaScript Primers and Script Tips. At no point in the "JavaScript Date/Time Methods" tutorials does Vince link to any of Joe's earlier JavaScript materials dealing with the core JavaScript Date object - he could have at least linked to JavaScript Primers #3, for example. Vince doesn't link to any of Netscape's materials either, but of course, it's the exception rather than the rule when anybody links to the 'primary literature' in the Web coding world.

The "JavaScript Date/Time Methods" series is described as follows:
This HTML Goodies series shows how to use some of the more important Date and Time tools for Web Developers. Server Side and Client Side tools are discussed, along with some special considerations for the Web. Step through this mini-series to learn about the available tools and to develop yourself into a globally thinking citizen of the World Wide Web!
The series doesn't live up to the above hype, I'm sorry to report. The series tutorials present some basic information and two small scripts that illustrate only a handful of the Date object's 50+ methods. And whereas the spotlighted methods all appear in the Server-Side JavaScript 1.2 Reference's Date object documentation, and thus can be considered "server-side tools", there's nothing particular to server-side JavaScript in the series tutorials. As for special considerations for the Web, the series' first two tutorials sport some meandering discussion in this regard but that's about it.

Nonetheless, there's no reason why we can't take a quick look at what's going on in the "JavaScript Date/Time Methods" tutorials, why not? The organization of the series material leaves room for improvement. The first tutorial in the series, "What's The Time? Using JavaScript to Localize Time Displays", should really be the last of the lot, and we'll begin our tour of the series with its second and more basic tutorial, "The Date( ) Object".

Surveying the Date landscape

"The Date( ) Object" introduces the core JavaScript Date object, shows how to create Date object instances, and briefly discusses the information that is contained in an individual Date object.

Instantiation notes

• It's not necessary to variabilize a new Date object if you're only going to use it in one command; for example,

document.write("The current date and time is: " + new Date( ).toLocaleString( ));
/* Putting a semicolon immediately after toLocaleString( ) (i.e., before the right parenthesis of the document.write( ) command) will throw an error. */


outputs (outputted when I ran it)

The current date and time is: February 12, 2010 4:13:38 PM CST

without the need for a variable.

• In saying that a Date object can [have] any variable name you wish, Vince should more specifically state that a variable for a Date object (or for any other expression) can't be a JavaScript reserved word and must otherwise conform to JavaScript's rules for naming variables.

"The Date( ) Object" also features a mostly complete list of methods of the Date object. This list is missing the following methods:
now( ), toDateString( ), toLocaleDateString( ), toLocaleFormat( ), toLocaleTimeString( ), toSource( ), and toTimeString( ).
(I myself am leaving out here those Date object methods that are inherited from the core Object and Function objects.)
Two of the methods on Vince's list, setDay( ) and setUTCDay( ), are in fact NOT JavaScript Date object methods. Netscape tersely comments here on why the Date object does not have a setDay( ) method: There is a getDay( ) method that returns the day of the week, but no corresponding setDay( ) method, because the day of the week is set automatically.

For a full list of JavaScript Date object methods, see the current Date object page in the Core JavaScript 1.5 Reference.

Vince correctly notes that the getYear( ) and setYear( ) methods are deprecated. As of this writing, the toGMTString( ) method is also deprecated - we'll have more to say about this method later.

Vince is moreover right to single out the static parse( ) and UTC( ) methods, but these methods do not belong or have any relation to the Date constructor. The parse( ) and UTC( ) methods are not methods of Date object instances, they don't act on Date objects, they don't create Date objects, and they don't return Date objects. They do respectively act on string and number data corresponding to Date objects and then return millisecond values again corresponding to those objects. For example:

var ms40years = Date.UTC(2010, 0, 1, 0, 0, 0, 0);
/* ms40years returns 1262304000000, the number of milliseconds between January 1, 1970, 00:00:00 UTC and January 1, 2010, 00:00:00 UTC. */


JavaScript 1.5 introduced a third static Date method, now( ), which returns the milliseconds elapsed since 1 January 1970 00:00:00 UTC up until now as a number, quoting Mozilla. Of the OS X GUI browsers on my computer, the now( ) method is supported by Camino, Chrome, Firefox, and Safari, but is not supported by MSIE or Opera.
(In its now( ) description, Mozilla links the word number to its page for the core JavaScript Number object. FYI, typeof Date.now( ) returns number and not object.)

Lastly, whereas a Date object's fields are indeed accessed via its methods, it is not true that [t]he Date( ) object doesn't have properties that can be directly read and written. As you can see from the aforelinked Mozilla Date object page, the Date object does have a small collection of properties, the majority of which are inherited from the core Function object and most of which are read-only. These properties and their returns are not relevant to our present discussion, however.

The methods listed in "The Date( ) Object" are relisted in a somewhat more organized way and with a bit of elaboration in the third and fourth series tutorials, which are both titled "Using Date( ) Object Methods".

Before moving on, I want to comment on something in Vince's "Date Object( )" introduction that I find historically odd:
With all these time zone issues, formatting problems and mathematical nightmares, web programmers all over the world would spend hour after hour writing code to handle the variety of situations their page might have to contend with unless somebody did something to help them out.

They did.

Included in JavaScript is a Date Object. This object is a part of the overall specification of JavaScript and is available to any page that can include JavaScript (these days, that pretty much means any page.)
The JavaScript Date object, which to my understanding was patterned on the standard Java Date class, was implemented in JavaScript 1.0, the very first version of JavaScript. As public specifications, both Java and JavaScript made their debuts in the first half of 1996 and thus between the W3C's approvals of HTML 2.0 (September 22, 1995) and HTML 3.2 (January 14, 1997). Web coders can incorporate dynamic date/time content into an HTML page via
(a) the applet element, which was implemented in HTML 3.2 but is now deprecated,
(b) the script element, which was also implemented (if in a very cursory way) in HTML 3.2, and
(c) the object element, which was introduced in HTML 4.
So I fail to see how Web coders could have spent hour after hour writing [date/time] code prior to 1996 because they simply didn't have any HTML tools enabling them to do so back then. (I admit I am not conversant with date/time programming for the Internet in the pre-Web days.)

Another dayspan calculator

There's no real code to speak of in either "The Date( ) Object" or the fourth-in-the-series "Using Date( ) Object Methods" tutorial, but the third-in-the-series "Using Date( ) Object Methods" tutorial concludes with a short script that calculates the number of days spanning two Date objects:

<script type="text/javascript">

today = new Date( ); // set today's date
birthday = new Date( ); // set up the Birthday object

birthday.setMonth(11); // set birthday month to December
birthday.setDate(15); // set birthday date to the 15th

if (today.getTime( ) < birthday.getTime( )) {
diff = birthday.getTime( ) - today.getTime( );
diff = Math.floor(diff / (1000 * 60 * 60 * 24));
document.write("There are " + diff + " days until December 15."); }

</script>


The script should really appear at the end of the fourth-in-the-series "Using Date( ) Object Methods" tutorial as that tutorial does discuss getTime( ), the (not-so-)key Date object method upon which the script relies. You might recall that we encountered a similar dayspan calculator script in Script Tips #29 and #30, which we deconstructed in Blog Entry #62.

The script specifically calculates the number of days between today, a variable holding the current day, and birthday, a variable set to December 15 of the same year.

Comments

• Per this Netscape example, it's actually not necessary to use the getTime( ) method to carry out a today vs. birthday millisecond comparison; the if declaration and the first if block statement can be written as:

if (today < birthday) {
diff = birthday - today;


• The today and birthday objects are initially created at almost the same time. After birthday is set to December 15, today and birthday have identical getHours( ), getMinutes( ), and getSeconds( ) returns, and even their getMilliseconds( ) returns are usually identical. As a result, diff = birthday - today; is an even multiple of 86,400,000 - the number of milliseconds in a day - in most runs of the script, and one is tempted to throw out the Math.floor( ) function on the following line. However, on isolated occasion, I find that the today/birthday getMilliseconds( ) returns are off by a millisecond (not more than that), so perhaps we should leave the Math.floor( ) function in place.

• After the script, Vince has an assignment for us: As an interesting exercise, try enhancing this script to determine if today is the birthday, or if this year's birthday has already passed (there's already code for that) and printing an appropriate message in each case. To handle the "today is the birthday" situation, the if statement can be rewritten as:

if (today <= birthday) {
diff = birthday - today;
diff = Math.floor(diff / (1000 * 60 * 60 * 24));
if (!diff) // If diff is 0, which converts to false in a Boolean context:
document.write("Happy Birthday!");
else document.write("There are " + diff + " days until December 15."); }


To handle the "this year's birthday has already passed" situation, we can supplement the if statement with a suitable else clause:

if (today <= birthday) { ... }
else // If today is greater than (i.e., later than) birthday:
document.write("You missed my birthday, but it's not too late to get me a nice present.");


Localize it

In general terms, "What's The Time? Using JavaScript to Localize Time Displays", the first "JavaScript Date/Time Methods" tutorial, scratches the surface of the broader issues of computing internationalization and localization, which are beyond the scope of this entry.

"What's The Time?..." concludes with a script that showcases the toLocaleString( ) Date object method and for good measure also displays returns for the getTimezoneOffset( ) and toGMTString( ) Date object methods:

<html><head></head><body><script type="text/javascript">
ourDate = new Date( );
document.write("The time and date at your computer's location is: " + ourDate.toLocaleString( ) + ".<br />");
document.write("The time zone offset between local time and GMT is " + ourDate.getTimezoneOffset( ) + " minutes.<br />");
document.write("The time and date (GMT) is: " + ourDate.toGMTString( ) + ".<br />");
</script></body></html>


Comments

• The toLocaleString( ) method converts the date to a string using the formatting convention of the operating system where the script is running, quoting Mozilla. The toLocaleString( ) return format on my computer is given in the Instantiation notes subsection above; depending on your locale, your toLocaleString( ) return, which you can check via the demo that follows the script in the tutorial, may or may not be formatted differently.

JavaScript has more specific toLocaleDateString( ) and toLocalTimeString( ) Date object methods that respectively return the date and time parts of the toLocaleString( ) return. Contra Netscape/Mozilla, the toLocaleDateString( ) and toLocaleTimeString( ) methods were not implemented in JavaScript 1.0 but in fact first appeared in JavaScript 1.5. (The aforementioned toLocaleFormat( ) method is not related to these methods. I am not inclined to discuss the toLocaleFormat( ) method as it is only supported by Firefox and Camino on my computer.)

• We previously discussed the getTimezoneOffset( ) method in Blog Entry #103 in the course of working through the "World Clock" script of Script Tips #87-90.

• Like the toLocaleString( ) method, the deprecated toGMTString( ) method returns a string giving the date and time, but in the GMT (UTC+0) time zone; toGMTString( ) has been replaced by a toUTCString( ) method giving an identical return (at least they're identical on my computer). The toGMTString( )/toUTCString( ) return is formatted a bit differently vis-à-vis the toLocaleString( ) return and, unlike the toLocaleString( ) return, also gives the day of the week as a three-letter abbreviation:

document.write(new Date( ).toUTCString( ));
// Return: Wed, 17 Feb 2010 01:01:16 GMT


Of course, the usefulness of any date/time script depends on whether or not the date and time are set correctly on the user's computer. In his "What's The Time?..." introduction, Vince notes that the date and time on a client computer can be synchronized with that of a remote server - for example, I could coordinate my computer clock with Apple's time.apple.com server - but the user doesn't have to do that, and there's nothing stopping the user from maintaining her/his computer at an incorrect date and time.
(When my old G3 iMac would hang, sometimes its clock date was reset to January 1, 1904. Upon restarting, I was prompted to reset the clock and always did so, but there was nothing forcing me to do so.)

Regarding time zones, Vince observes, Every modern operating system holds a setting that tells it where it is, or more specifically which time zone it's in, which is true -
Setting the time zone on my iMac
but there's nothing stopping the user from maintaining her/his computer at an incorrect time zone setting, either; indeed, one "What's The Time?..." commenter affirms, I have seen users who have their computers set to a different time zone than the one they are in. Also traveling with a laptop across time zones only gives you the time of the owner's home and not where the laptop is 'now'.

Regarding daylight saving time, Vince's claim that you don't have to worry about it because operating systems adjust for daylight saving times, if applicable should be generally true if you were to buy a new computer today, but what if here in the U.S. you were to buy a used, pre-2007 computer that was produced when the DST period was different? What if the government in your locale were to change the DST period in the future, or were to implement DST if it doesn't currently do so or vice versa?

Again, it is ultimately up to the user to sort out these variables - date, time, time zone, DST - in order to utilize a date/time script.

In the next few posts, we'll jazz up your forms via a tour of "JavaScript Form Scripts", another "Beyond HTML : JavaScript" series comprising four tutorials. We'll take up the first "JavaScript Form Scripts" tutorial, "Submit The Form Using Enter", in the following entry.

reptile7

Friday, February 05, 2010
 
Let's Get Out While We Can
Blog Entry #170

So, what's on tap today? In this post we'll check over HTML Goodies' "Escape Characters" tutorial. "Escape Characters" briefly discusses the following JavaScript special characters:
(1-2) \' and \", towards the end of respectively placing single-quote/apostrophe and double-quote characters in dialog box messages and in document.write( ) strings; and
(3-4) \r and \t, towards the end of respectively inserting line breaks and tabs in dialog box messages.

Backslash it

Joe's description of the role of the backslash (\) character in a JavaScript special character is a bit hazy:
The backslash is the key. If you plop that in front of the quotes or the letter "r" you escape the coding long enough for the script to understand you want the character to represent text rather than a command to be used in the coding. That's why we call it an escape character. Get it?
I myself don't like the use of the word "escape" in this context. The backslash in a JavaScript special character is in essence an operator that transforms certain literal characters to metacharacters - characters that have a special function and consequently are not meant to be interpreted literally - and certain metacharacters to literal characters. (Joe's above quote addresses the metacharacter ("command") to literal character ("text") operation but not the literal character to metacharacter operation.)

For example, in JavaScript the single-quote (') and double-quote (") characters are metacharacters whose special function is to delimit string literals. If you want these characters to appear as literal characters in a string, you can if necessary convert them to literal characters by preceding them with a backslash, as detailed below. The backslash itself is a metacharacter that signals the beginning of a JavaScript special character, and must be prepended with another backslash to be rendered literally in a string.

Complementarily, preceding a lowercase n with a backslash transforms it from a literal character to a \n metacharacter signifying a newline; prefacing a literal t with a backslash creates a \t metacharacter signifying a horizontal tab; and so on. For most literal characters, however, a preceding backslash has no effect and is ignored by the JavaScript engine, e.g., window.alert("Hello \World"); will simply display Hello World on the alert( ) box.

Alternatively, there are ways to reference a literal character in JavaScript that involve a backslash, e.g., a lowercase a can be encoded by
(1) \141 (using its octal ASCII code position),
(2) \x61 (using its hexadecimal ASCII code position), and
(3) \u0061 (using its Unicode code position);
however, such formulations are not discussed in "Escape Characters".

Quote formatting, revisited

In the tutorial, Joe seems to have a fundamental misunderstanding of JavaScript quote formatting as he implies that single-quote and double-quote characters appearing in strings are necessarily escaped, which is not true. Here is his sample code for putting single-quote/apostrophe and double-quote characters in a document.write( ) string:

document.write('We\'re going to \"need\" to know where you\'re going tonight, young man!');

To review, it is necessary to
(a) escape single-quote/apostrophe characters in a string delimited by single quotes and
(b) escape double-quote characters in a string delimited by double quotes, but
(c) double-quote characters can appear literally ("unescaped") in a string delimited by single quotes and
(d) single-quote/apostrophe characters can appear literally in a string delimited by double quotes.
This all holds regardless of the extent of quote nesting:

document.write('Alice said, "Bob said, \'Carol said, "Dave said, \'...\' " \' " ');

It follows that, whereas the apostrophes in Joe's write( ) string, which he chose to delimit with single quotes, must indeed be escaped, there's no need whatsoever to escape the double quotes surrounding the word need, and the command can be written as:

document.write('We\'re going to "need" to know where you\'re going tonight, young man!');

Per the discussion of the previous section, there are several other ways to encode an apostrophe in JavaScript: \047, \x27, and \u0027 will all do the trick. In addition, for a document.write( ) command executed by a Web browser, apostrophes can also be coded by &#39; or &apos; HTML character references because the write( ) string constitutes HTML element #PCDATA content - even if you don't specify any markup, the string is still part of the body element. But obviously, the easiest way to code an apostrophe in this case is to just precede it with a backslash.

Had Joe delimited the write( ) string with double quotes, the apostrophes could have appeared literally but then the double quotes around need would need to be escaped or referenced as described above.

For Netscape's own discussion of JavaScript quote formatting (which could be more complete than it is, but I guess you could say that about pretty much all coding instructional material), see the "String Literals" and "Using Quotation Marks" sections in the JavaScript 1.3 Client-Side Guide.

Break my lines

Joe rolls out prompt( ) and alert( ) box examples in which the \r escape sequence is used to induce line breaks in the messages on the boxes. Here's his prompt( ) box code:

var name = prompt("Please write your \'name\' in the box\rWrite it with \"quotes\" like this.","");
// Again, the single quotes surrounding the word name do not need to be escaped.


The \r sequence signifies a carriage return, which does not correspond to a move-to-the-first-character-position-of-the-next-line effect in all situations but does so in HTML and in JavaScript as well, at least with most browsers. (This doesn't mean that a carriage return will necessarily generate a line break in practice, as explained below.) However, two "Escape Characters" commenters report that they're having a problem with Joe's \r examples when using Firefox; sure enough, Firefox ignores the \r sequence altogether (both characters, not just the backslash) on a prompt( ) or alert( ) or confirm( ) box:

Joe's 'Prompt Example' when using Firefox

All of the other OS X GUI browsers on my computer - Camino, Chrome, MSIE, Opera, and Safari - force a line break after the word box in the prompt( ) text. (Firefox automatically wraps the prompt( ) text after the nested "quotes" string; Joe does not force a line break at this point in the text.) Another commenter points out that the correct escape sequence for a newline is \n, and replacing \r with \n does indeed give the expected effect with Firefox:

A Firefox prompt( ) box featuring a newline

Unlike the window dialog methods, which are at least for now purely scriptic methods, document.write( ) has long had one foot in the HTML world (as implied above), and neither \r nor \n in a document.write( ) string will normally force a line break because, per the W3C's recommendation, Web browsers generally render carriage returns and newlines as ASCII spaces, i.e., space characters as generated by the space bar at the bottom of the keyboard. (This is also the reason why the document.writeln( ) method does not normally induce line breaks.) There is an important exception to this: wrapping a write( ) string in a pre element will enable you to force line breaks with \r or \n sequences, e.g.,

document.write("<pre>The backslash\ris the key.</pre>"

outputs:
The backslash
is the key.
But as Joe notes in the tutorial's "document.write Example" section, document.write( ) line breaks are more straightforwardly effected via the br element.

Keeping tabs on tabs

Finally, Joe offers the following code for an alert( ) box whose message comprises nine text lines and contains a three-line section formatted with \t tabs:

alert('OK Then!\r\rYou want a neat box like \"this\" one?\r\rWell!\r\rYou\'ll need:\rBrains\tBeauty\t\tTalent\rMoney\tDog food\t\tLuck\rA Cat\tEye of Newt\tA Shrubbery!\r\rAnd the ability to \'read\' this tutorial.\r\rOK?');
// The tabbed section is in purple.


Most of the OS X browsers on my computer (including Lynx!) render a tab as eight ASCII spaces in a monospace font. To the extent that this is a 'normal' rendering, here's what Joe's alert( ) box should look like:
Joe's 'Alert Example' when using Chrome
On the other hand, dialog box text is generally rendered in a sans-serif font - this is why it is necessary to put two tabs between Dog food, which contains eight characters but does not quite reach the second tab stop, and Luck in order to get Luck to line up with Talent and A Shrubbery! in the third column of the tabbed section of the alert( ) box.
Brains	Beauty		Talent
Money	Dog food		Luck
A Cat	Eye of Newt	A Shrubbery!
12345678123456781234567812345678
Browser notes

• For Firefox, change each \r to a \n and the alert( ) box will look as it should.

• Camino cuts off the OK? at the bottom of the box although the rest of the box looks OK.

Joe's 'Alert Example' when using Camino

• MSIE 5.2.3 won't render tabs at all. :-(
Joe's 'Alert Example' when using MSIE 5.2.3
As for a \r carriage return and a \n newline, a \t tab in a document.write( ) string will translate to an ASCII space unless the write( ) string is wrapped in a pre element, speaking of which...

Tabs - HTML Goodies

Near the end of the "Prompt Example" section, Joe links to a sister tutorial, "Tabs - HTML Goodies", which according to the top of its page should be located in HTML Goodies' /beyond/javascript/ directory although there's no link to it on the "Beyond HTML : JavaScript" portal page. "Tabs - HTML Goodies" discusses the creation of a tabbed layout via placing \t sequences in document.write( ) strings and then wrapping the write( ) text in a pre or xmp element. Don't use the xmp element: it's obsolete. Use the pre element if you're going to do this.

Moreover, in "Tabs - HTML Goodies" Joe notes, Others told me they created a tabbed layout*, copied and pasted it into their HTML document and then surround[ed] it with the <pre> or <xmp> tags, which IMO is a better approach to HTML tabbing than the document.write( ) and \t approach, notwithstanding Joe's later, somewhat-at-variance comment that I know I said earlier in the tutorial that using the pre or xmp tag didn't work [in a non-script HTML context] because the tabs often didn't transfer correctly - especially if you're using a non-block font. (I'm not quite sure what Joe means by "non-block [sans-serif?] font", as "block" is not one of the W3C's generic font families.)

*Perhaps the most reliable way to generate tabs in HTML is to hard-code them with &#9; character references (which will still need to appear in a pre element) - it was necessary for me to do this for my Dog food-to-Luck graphic above because, even as pre element content, my keyboard-tab-key-generated tabs are converted to ASCII spaces in the Blogger post textarea field.

Pre element text is typically rendered in a monospace font, and if you were to override this - with, say, a font-family:Arial,sans-serif; CSS declaration - then I can see how it might cause problems with your tabbing. If you're serious about using tabs, keep everything in a monospace font and you should be able to work it out.

Next up on the "Beyond HTML : JavaScript" menu is a "JavaScript Date/Time Methods" series of four tutorials that we'll dispatch collectively in the following entry.

reptile7


Powered by Blogger

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