If you've ever programmed in PHP, you've probably come across the
date method, and maybe thought it was really neat.
I certainly have, and since formatting and otherwise
working with date strings in JavaScript isn't
exactly easy (a lot of getSomeUnit), I thought I'd implement
a generic solution once and for all, similar to the PHP one.
This is a pure client-side solution, and because of that, you can't
always be sure it'll work correctly. Time and date issues are some
of the more
complex matters in JavaScript.
Danny Goodman's article,
JavaScript Date Object Techniques is hideously old
(Netscape 3!), but still
provides a valuable first look at date programming and it's pitfalls.
Most important of all, this script in no way helps you determine
a time, and set it. All this does, is, when given a Date
object (where the date is always set), is to print
it out, in a easier way, compared to what JavaScript usually allows.
Always test your script, to ensure it works in whatever browser you need it to work in. If you're using this code for sensitive code, where accurate dating is required, you are out of your mind. Use this for cosmetic features and otherwise non-critical code.
Over the years I've gotten alot of feedback on this code, such as bug fixes and improvements. I've tried to update the JavaScript file to contain all contributors, but if you are not listed, my apologies.
Using this function is very simple. You start by downloading, and linking the JavaScript file formatDate.js. You then need to create a date, that you want to format. Let's start of simple, and just format what time it is right now:
d = new Date();
alert(d.formatDate("h:i A")); // shows "01:52 am", or something
// similar depending on current time
All the various codes you can use, are listed in a table below, and they all depend on whatever date the date object has. So, if we want to create a specific date:
// notice that month and date are zero indexed (1st is 0)
d = new Date(1999, 11, 30); // millenium new years eve
alert(d.formatDate("F dS")); // shows "December 31st"
If you want a letter, not to be interpreted as a code, but instead
as the mere letter, and you don't want to muck around with
string building, you can simply escape it. But instead of normal
escaping (using a single \),
you need to escape here with two slashes \\.
Like the letter F, is usually a code, for the month
name (January, etc), if you instead just want "F", you just go:
\\F.
d = new Date(1999,11,30); // millennium new years eve
// shows "31st of December, the year 1999"
alert(d.formatDate("dS of F, \\t\\he \\ye\\a\\r Y"));
Notice, how you you only need to escape those letters, that are actual
codes. Therefore, the letters o,f and e
doesn't need escaping.
For the full lowdown on how to set dates on Date objects I
refer to the
JavaScript 1.5 documentation on the Date object.
Most of PHP's date method's switches are supported. Are few aren't.
Here is a full list of supported switches, unsupported ones, and ones, that I might include in the future. The switches are compared against PHP 5.1.3.
| Supported switches | Unsupported switches | Currently unsupported, but might be included in the future |
| a, A, B, c, d, D, F, g, G, h, H, i, I (uppercase i), j, l (lowecase L), L, m, M, n, N, O, P, r, s, S, t, U, w, W, y, Y, z, Z | T, e, o |
And here is a full listing of that they do. Pretty much ripped from PHP's own page.
| Switch | Description | Example of returned values |
a |
Lowercase Ante meridiem and Post meridiem | am or pm |
A |
Uppercase Ante meridiem and Post meridiem | AM or PM |
B |
Swatch Internet time | 000 through 999 |
c |
ISO 8601 date | 2004-02-12T15:19:21+00:00 |
d |
Day of the month, 2 digits with leading zeros | 01 through 31 |
D |
A textual representation of a day, three letters | Mon through Sun |
F |
A full textual representation of a month | January through December |
g |
12-hour format of an hour without leading zeros | 1 through 12 |
G |
24-hour format of an hour without leading zeros | 0 through 23 |
h |
12-hour format of an hour with leading zeros | 01 through 12 |
H |
24-hour format of an hour with leading zeros | 00 through 23 |
i |
Minutes with leading zeros | 00 through 59 |
I (uppercase i) |
Whether or not the date is in daylights savings time | 1 if Daylight Savings Time, 0 otherwise |
j |
Day of the month without leading zeros | 1 through 31 |
l (lowercase L) |
A full textual representation of the day of the week | Sunday through Saturday |
L |
Whether it's a leap year | 1 if it is a leap year, 0 otherwise |
m |
Numeric representation of a month, with leading zeros | 01 through 12 |
M |
A short textual representation of a month, three letters | Jan through Dec |
n |
Numeric representation of a month, without leading zeros | 1 through 12 |
N |
ISO-8601 numeric representation of the day of the week | 1 (for Monday) through 7 (for Sunday) |
O |
Difference to Greenwich time (GMT) in hours | Example: +0200 |
P |
Difference to Greenwich time (GMT) with colon between hours and minutes | Example: +02:00 |
r |
RFC 822 formatted date | Example: Thu, 21 Dec 2000 16:01:07 +0200 |
s |
Seconds, with leading zeros | 00 through 59 |
S |
English ordinal suffix for the day of the month, 2 characters | st, nd, rd
or th. Works well with j |
t |
Number of days in the given month | 28 through 31 |
U |
Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) | 1060266789 |
w |
Numeric representation of the day of the week | 0 (for Sunday) through 6 (for
Saturday) |
W |
ISO-8601 week number of year | 1 through 53 |
y |
A two-digit representation of a year | Examples: 99 or 02 |
Y |
A full numeric representation of a year, 4 digits | Examples: 1999 or 2002 |
z |
The day of the year | 0 through 366 |
Z |
Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive | -43200 through 43200 |
The script was written, with emphasis on compatibility. Thankfully,
the Date object is part of Core JavaScript and
is thus standardized in
ECMAScript
3rd edition. Only methods, which are in that specification have been
used. ECMAScript 3rd edition corresponds roughly to
JavaScript 1.5, and to
JScript 5.5.
So that should cover the major newer browsers.
Nonetheless, older browsers might stumble a bit at places, especially problems with timezone offsets, and such things is hairy stuff, that one shouldn't really try and fix. For more on dates, and how browsers deal with it, Peter-Paul Koch, has a lot of good stuff on it.
You can pretty much count on the basic stuff, like getting days, date and year. What you might abstain from relying on (at least not without testing first), is things such as timezone offsets, and other similar switches.
The following browsers have been tested with the script, and found to work as expect. If there's any problems, these have been noted. If you know any of these to be wrong, or a browser, where something fails, please email me, and tell me.
| Browser | Works | Fails | Notes |
| Internet Explorer 6.0 SP1 | All | None | |
| Internet Explorer 5.0 (Win32) | All | None | |
| Opera 7.20 Beta | All | None | |
| Mozilla 1.4 | All | None | |
| Netscape Navigator 4.08 | All | None | |
| Netscape Navigator Gold 3.04 | None | All | Dies horribly, since it's flavor of JavaScript is SO old, that it's very syntax isn't even supported. It would be possible (and not too hard), to bastardize the script, so it would work with Netscape 3, but in the name of decent code, I've opted not to do this. |
| WebTV viewer 2.5 | None | All | null is returned in all cases. |
One of the major strengths of a this script, over
PHP's date function, is
that PHP's date function can only
spit out English, this one can be easily modified, to
spew out other languages, instead of English. And not
just from English, into, say a Danish script, but
it will be capable of both things at once. So if a user
with English set as his language, comes in, he will get
June, as well, "June", but a Dane will get it as "Juni" (Danish for June).
In the following section, I'll show how to make the script show Danish and English weekdays, instead of only English. The technique can be easily applied to all the other words just as easily (months, day suffix, and so forth).
In the top of the script, you will find this array entry:
var daysLong = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
Of course, we could just change that into Danish, and we'd be fine, but then there'd be no English of course. The solution is instead, to create two arrays, and rename them, so they show their language.
var daysLong_en = ["Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"];
var daysLong_dk = ["Søndag", "Mandag", "Tirsdag", "Onsdag",
"Torsdag", "Fredag", "Lørdag"];
And we now need to change the function, which goes into that array, so that, before getting the weekday, it checks for language the user has set.
Your options for seeing what language a user has set are
pretty limited and browser specific I'm afraid. Netscape
has traditionally (since version 4, Mozilla supports this one too)
supported the navigator.language
attribute, while Internet Explorer, also since version 4, has supported
navigator.browserLanguage. Opera supports both these (
though I do not know from what version).
You also need to write an array, with "supported" languages, so that in case the language could be detected, but it's not one that you've written text for, it'll just go back to English again.
var supportedLang = ["en", "dk"]; // for our little example,
// danish and english is it
The function that finds the week day is the following (the syntax may seem curious to you, but trust me, it works)
"l" : function () {
// A full textual representation of the day of the week
return daysLong[self.getDay()];
}
Which can then be rewritten into:
"l" : function () {
var lang = "en"; // we default to english
if (navigator) {
if (navigator.language) {
// netscape/mozilla
lang = navigator.language;
} else if (navigator.browserLanguage) {
// internet explorer
lang = navigator.browserLanguage;
}
}
// if language isn't supported
if (!supportedLang.exists(en)) lang = "en";
var a = eval("daysLong_" + lang);
return a[self.getDay()];
}
Of course, you can do the usual browser checking stuff, so you don't have to write that whole thing over and over. I'll leave it up to the reader, to make the script as small as possible :)
Here is a table, of how your browser handles the script. Use this table, to load up the various browser you want to check, and see if they work as expected.
The date used, is April 16, 1981, at 01:30 after midnight, that's my birthday, and the second date used is whatever it's right now. Of course, there's no "expected output" from the "now" time. If you're wondering why all the timezone stuff doesn't have a "expected", it's because the script always runs in YOUR timezone, and as such, that will show whatever timezone offset you currently have with UTC.
| Switch | Your browser (4/1981) | Expected (4/1981) | Your browser (now) |
a |
|
am |
|
A |
|
AM |
|
B |
|
020 |
|
d |
|
16 |
|
D |
|
Thu |
|
F |
|
April |
|
g |
|
1 |
|
G |
|
1 |
|
h |
|
01 |
|
H |
|
01 |
|
i |
|
30 |
|
j |
|
16 |
|
l (lowercase L) |
|
Thursday |
|
m |
|
04 |
|
M |
|
Apr |
|
n |
|
4 |
|
O |
|
N/A |
|
r |
|
Thu, 16 Apr 1981 01:30:00 +xxxx |
|
s |
|
00 |
|
S |
|
th |
|
t |
|
30 |
|
U |
|
356225400 |
|
w |
|
4 |
|
W |
|
16 |
|
y |
|
81 |
|
Y |
|
1981 |
|
z |
|
105 |
|
For a truly exercising test page, I've made a
huge table, that tests all switches. It randomly generates dates,
and you can then compare PHP's results, to the one generated by this script.
Keep in mind, that results printed by my script will be localized,
that is, numbers changed to fit your timezone. This is most clear in
the switch r and in the I switch. In the case of I however, the PHP version will often be wrong, since it works of whatever the server believes. The script version will work off the JavaScript date algorithms (which may or not be localized). Still, if there's anything that isn't
doing what I hope it's doing. Please let me know what
I'm doing (wrong).