A simple formatDate function for JavaScript
One thing in JavaScript that's really lacking is date formatting. If you want to display a date in JavaScript there aren't a whole lot of options available especially if you want to display a date as numeric notation (ie. 10/31/2007 for example). I decided that I need at least some basic date formatting functionality in my apps, so I created a basic date formatting function. While I was at it I had to create a few helpers along the way which I'll also show below.
This is one thing where the Microsoft ASP.NET AJAX client library actually excels - it has a whole complement of type formatting functions similar to .NET code, but since I'm not using the library I needed to roll my own. I took a brief look to see what the MS client libs are doing but the amount of code involved for formatting is huge and scattered all over the place. To be expected though given in the completeness of the support which is much more than my simple needs. (FWIW, it's really interesting to see the sheer amount of code that runs in the MS AJAX libraries!).
I also searched around for a other JavaScript implementations and I dug up a few but the problem with many of them is that the code gets rather lengthy quickly as most libraries support too many features including string based date representations, which then requires localization etc.
My main goal is to provide only basic date formatting for numeric date display. Things like 12/01/1966 and 2005-12-31 19:00:31 and 12-07 or 12:01pm for example. That's only a fraction of the date formatting we're used to in .NET, but really how many different date formats do you ever work with anyway?
In any case here's a formatDate extension for the Date prototype:
Date.prototype.formatDate = function(format){var date = this;
if (!format) format="MM/dd/yyyy"; var month = date.getMonth() + 1; var year = date.getFullYear(); format = format.replace("MM",month.toString().padL(2,"0"));
if (format.indexOf("yyyy") > -1)
format = format.replace("yyyy",year.toString());else if (format.indexOf("yy") > -1)
format = format.replace("yy",year.toString().substr(2,2));format = format.replace("dd",date.getDate().toString().padL(2,"0"));
var hours = date.getHours(); if (format.indexOf("t") > -1)
{ if (hours > 11)format = format.replace("t","pm")
elseformat = format.replace("t","am")
}
if (format.indexOf("HH") > -1)
format = format.replace("HH",hours.toString().padL(2,"0"));
if (format.indexOf("hh") > -1) {
if (hours > 12) hours - 12; if (hours == 0) hours = 12;format = format.replace("hh",hours.toString().padL(2,"0"));
}
if (format.indexOf("mm") > -1)
format = format.replace("mm",date.getMinutes().toString().padL(2,"0"));
if (format.indexOf("ss") > -1)
format = format.replace("ss",date.getSeconds().toString().padL(2,"0"));
return format;}
With this you can format dates like this:
var date = new Date();
var cr = "\n";
var str = date.formatDate("yyyy-MM-dd HH:mm") + cr +
date.formatDate("MM/dd/yyyy hh:mm t") + cr + date.formatDate("MM-yyyy hh:mmt") ;alert(str);
The date formatting isn't terribly flexible so months, days, hours, minutes and seconds can only be represented in 2 digit format, but again that's the most common way to do it anyway around the world.
The code above depends on a few helper functions that String.prototype.padL and String.prototype.padR and String.repeat:
String.repeat = function(chr,count){ var str = "";
for(var x=0;x<count;x++) {str += chr};
return str;}
String.prototype.padL = function(width,pad){ if (!width ||width<1)return this;
if (!pad) pad=" ";
var length = width - this.length
if (length < 1) return this.substr(0,width);
return (String.repeat(pad,length) + this).substr(0,width);
}
String.prototype.padR = function(width,pad){ if (!width || width<1)return this;
if (!pad) pad=" ";
var length = width - this.length
if (length < 1) this.substr(0,width);
return (this + String.repeat(pad,length)).substr(0,width);
}
The static String.repeat repeats a given character or string n number of times, which is required for padding values. .padL and padR, pad a string left and right and also trim a string if the width is exceeded. This is useful in many situations for string trimming and in the date formatting for right filling numbers with 0's (ie. 2 turns into 02).
While I was at it I also ran into a very basic string.format implemementation which was just too easy to pass up. Again, not a full implementation like in .NET in that it only supports string replacement without format specifiers, but still highly useful:
String.format = function(frmt,args){ for(var x=0; x<arguments.length; x++)
{frmt = frmt.replace("{" + x + "}",arguments[x+1]);
}
return frmt;}
With it you can turn the previous data example to:
var date = new Date();
var cr = "\n";
alert(String.format("Date 1: {0}\nDate 2:{1}\nDate3: {2}", date.formatDate("yyyy-MM-dd HH:mm"), date.formatDate("MM/dd/yyyy hh:mm t"), date.formatDate("MM-yyyy hh:mmt") ));
Even this very basic implementation can save a fair bit of string concatenation code in many cases.
None of this is rocket science of course, but it's nice to have a few small and lean functions that provide basic utility functionality to your JavaScript code. Basic date formatting especially is something I've often cursed and this will go a long way to simplifying matters.
The Voices of Reason
# re: A simple formatDate function for JavaScript
# re: A simple formatDate function for JavaScript
Tom
# re: A simple formatDate function for JavaScript
# re: A simple formatDate function for JavaScript
Then, repeat(chr,count), best implementation (optimized for speed) is as such: { var parts = new Array(count+1); parts.join(chr); }. Won't everybody agree? This you can find in the prototype.js library, and shame on me I forgot the name of the person who introduced it.
Summing, before introducing some code from a tribune such as you, Rick, have, and introducing it as a allegedly good example to follow, make sure your code is real good. I'm sorry for my negative comment here. But someone needs to have said that a long time ago. This goes only, strictly, to your JavaScript examples. Best wishes, anyhow.
# re: A simple formatDate function for JavaScript
One thing I've found here on the blog is that comments very often come up with solutions that are better than what I originally posted and while sometimes it can be embarrassing (to me) I still think that that's a great thing overall. Often times there are also new feature ideas or completely overlooked aspects.
The value of posts like this IMHO is to give ideas or point out things we do frequently and repeatedly without much thought. And as I mentioned above a lot of times more complete solutions come out of the comments and frequently there's the value of the post and not necessarily directly in the code but the topic and discussion as a whole.
That said - while I get the idea of what you're saying, why don't you post the code of a revision alternative which you already have in your head and contribute it here? That'll really make your point and also provide a public contribution that will be useful for others...
# re: A simple formatDate function for JavaScript
Let current time be 7:21 PM
then
var date = new Date();
alert(String.format("{0}", date.formatDate("MM/dd/yyyy hh:mm:ss t")));
displays 09/23/2008 19:21:31 pm instead of 09/23/2008 07:21:31
Is it a bug or somthing else?
# re: A simple formatDate function for JavaScript
var date = new Date(); alert(String.format("{0}", date.formatDate("MM/dd/yyyy HH:mm:ss")));
# re: A simple formatDate function for JavaScript
The basic requirement that i think every developer need to take in mind is not to hard code the layout! e.g. for Hebrew its dd/mm/yy and for English its mm/dd/yy.
# re: A simple formatDate function for JavaScript
however... After you mentioned the great libraries for .Net, I realized.... hey, javascript for dates really sucks. So... I wrote a quick handler in about 20 seconds to use "isDate" and then send back the format I like. I called that handler via Ajax from the page. :)
JavaScript gurus world wide would be horrified. But... a flawless solution that's just a bit over-the-top.
# re: A simple formatDate function for JavaScript
# re: A simple formatDate function for JavaScript
The line: if (hours > 12) hours - 12;
should be: if (hours > 12) hours -= 12;
This will fix the issue first mentioned by Samir Nigam.
# re: A simple formatDate function for JavaScript
instead of: if (hours > 12) hours - 12;
# re: A simple formatDate function for JavaScript
# re: A simple formatDate function for JavaScript
I like it, nice and concise.
However, is there anything that can be done to get it to work with the culture of the browser? IOW, if I set my default browser culture to de-DE or to en-AU and enter 14/8/1969 into the following textbox:
<asp:TextBox id="test" runat="server" onblur="this.value= new Date(this.value).formatDate('MM-yyyy');"/>I would expect to see 08-1969 but instead I see 02-1970.
Thanks.
# re: A simple formatDate function for JavaScript
# re: A simple formatDate function for JavaScript
I was looking for an ultra-lightweight JavaScript function to format dates and was happy to come across your post. After using it for a bit, I found myself wanting the following: 1) to mimic more of Microsoft's custom date and time format strings function (http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx), and 2) handling JSON dates with Microsoft's formatting.
For the first item, I made the the following changes (still relatively compact, in my opinion):
Date.prototype.formatDate = function(format) { var date = this; var _monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; var _dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; var _year = date.getFullYear(); var _month = date.getMonth(); var _day = date.getDay(); var _date = date.getDate(); var _hours = date.getHours(); var _minutes = date.getMinutes(); var _seconds = date.getSeconds(); if (!format) format = "MM/dd/yyyy"; format = format.replace("yyyy", "{0}").replace("yy", "{1}").replace("y", "{2}") .replace("MMMM", "{3}").replace("MMM", "{4}").replace("MM", "{5}").replace("M", "{6}") .replace("dddd", "{7}").replace("ddd", "{8}").replace("dd", "{9}").replace("d", "{10}") .replace("hh", "{11}").replace("h", "{12}").replace("HH", "{13}").replace("H", "{14}") .replace("mm", "{15}").replace("m", "{16}") .replace("ss", "{17}").replace("s", "{18}") .replace("tt", "{19}").replace("t", "{20}"); if (format.indexOf("{0}") > -1) format = format.replace("{0}", _year.toString()); if (format.indexOf("{1}") > -1) format = format.replace("{1}", _year.toString().substr(2, 2)); if (format.indexOf("{2}") > -1) format = format.replace("{2}", parseInt(_year.toString().substr(2, 2)).toString()); if (format.indexOf("{3}") > -1) format = format.replace("{3}", _monthNames[_month]); if (format.indexOf("{4}") > -1) format = format.replace("{4}", _monthNames[_month].substr(0, 3)); if (format.indexOf("{5}") > -1) format = format.replace("{5}", (_month + 1).toString().padL(2, "0")); if (format.indexOf("{6}") > -1) format = format.replace("{6}", (_month + 1).toString()); if (format.indexOf("{7}") > -1) format = format.replace("{7}", _dayNames[_day]); if (format.indexOf("{8}") > -1) format = format.replace("{8}", _dayNames[_day].substr(0, 3)); if (format.indexOf("{9}") > -1) format = format.replace("{9}", _date.toString().padL(2, "0")); if (format.indexOf("{10}") > -1) format = format.replace("{10}", _date.toString()); if (format.indexOf("{11}") > -1) { var _h = _hours; if (_hours > 12) _h -= 12; if (_hours == 0) _h = 12; format = format.replace("{11}", _h.toString().padL(2, "0")); } if (format.indexOf("{12}") > -1) { var _h = _hours; if (_hours > 12) _h -= 12; if (_hours == 0) _h = 12; format = format.replace("{12}", _h.toString()); } if (format.indexOf("{13}") > -1) format = format.replace("{13}", _hours.toString().padL(2, "0")); if (format.indexOf("{14}") > -1) format = format.replace("{14}", _hours.toString()); if (format.indexOf("{15}") > -1) format = format.replace("{15}", _minutes.toString().padL(2, "0")); if (format.indexOf("{16}") > -1) format = format.replace("{16}", _minutes.toString()); if (format.indexOf("{17}") > -1) format = format.replace("{17}", _seconds.toString().padL(2, "0")); if (format.indexOf("{18}") > -1) format = format.replace("{18}", _seconds.toString()); if (format.indexOf("{19}") > -1) { if (_hours > 11) format = format.replace("{19}", "pm") else format = format.replace("{19}", "am"); } if (format.indexOf("{20}") > -1) { if (_hours > 11) format = format.replace("{20}", "p") else format = format.replace("{20}", "a"); } return format; }
For the second part, I added the following small block of code:
String.prototype.jsonFormatDate = function(format) { var t = parseInt(this.replace(/\/Date\(/, "").replace(/\)\//, "")); var d = new Date(); d.setTime(t); return d.formatDate(format); }
# re: A simple formatDate function for JavaScript
String.prototype.formatDate = function(format) { var d = new Date(); if (this.indexOf("/Date(") == 0) { d.setTime(parseInt(this.replace(/\/Date\(/, "").replace(/\)\//, ""))); } else { d = new Date(this); } return d.formatDate(format); }
This approach can "detect" the Microsoft formatting; otherwise, it leaves the string alone. Additionally, the prototype function name for the String (formatDate) is now the same as for Date. This makes things more consistent.
# re: A simple formatDate function for JavaScript
http://fisforformat.sourceforge.net/
It is able to output every date format I can think of (and then some) and it has some other neat features!
(FYI, it was listed as a jQuery plugin, but I've confirmed it works perfectly fine without jQuery.)
# re: A simple formatDate function for JavaScript