Blog
Nov. 19, 2009
Simple JavaScript Date Formatting
This week, in anticipation of our alpha launch, Jason asked me to write a mechanism for giving a user the ability to embed one of our feeds on their webpage. You know the drill here; we give them a box of code to copy and paste onto their page, and then after that it just sort of magically works. Anyway, in the process of doing this, I was at a point where I wanted to format what the date and time would look like.
Jason and I do a pretty good job of talking about what's coming around the corner, and he'd mentioned to me in passing that one thing he'd like in the future is a mechanism to allow the user to customize what the time formatting looked like, so I wanted to make sure I planned for that in advance. So, this morning I took on the challenge of taking a JavaScript date object (created from an integer Unix timestamp) and formatting it.
I decided that the best use of time was probably just to write a function to take a date and output it in an arbitrary way, rather than hard-coding the exact formatting we were going to use to start. That would allow me to easily accept an arbitrary format later, and also allow Jason some flexibility if he didn't like how one of the formats looked when he saw the final page; he could just edit the format string rather than asking me to revisit the date formatter.
The next step was determining how to specify a date format. Despite being a Python developer, I actually think that PHP has one of the nicer date formatting libraries I've seen (the developers of Django seem to agree with me on this; they copied PHP's date formatting for their template filters). I therefore settled on PHP's date() function as the standard for the formatting strings I would understand, although I only implemented a subset of the format strings, at least for now.
The function is nothing special; it simply iterates over all the tokens I understand and does string replacements. After completing it, however, Jason and I both felt like this might be something that other JavaScript developers might be able to use. Therefore, we're offering it here for anyone to shamelessly copy as they see fit. And, of course, if anyone finds a bug, or has an improvement, or just wants to implement the formatting tokens I chose to skip, I'm all ears!
/**
* Return a formatted date string
*
* Arguments:
* - date: A JavaScript Date object; if you have a unix timestamp, you want "new Date(timestamp * 1000)"
* - format: The format string; this is a subset of PHP's date formatting strings,
* see http://www.php.net/manual/en/function.date.php for a reference
*
* Author and License:
* - author: Luke Sneeringer, FeedMagnet (luke@feedmagnet.com)
* - license: New BSD License (http://www.opensource.org/licenses/bsd-license.php)
*/
function formatDate(date, format) {
// return a number as a string leading zeros when necessary
function _pad(n, digits) {
n = n.toString()
while (n.length < digits) {
n = '0' + n
}
return n
}
// the working response
var response = format
// escape the characters I supported
var supported = 'djDNwlFmMnyYgGhHisaA'
for (var i = 0; i < supported.length; i += 1) {
var ch = supported.charAt(i)
response = response.replace(ch, '%' + ch)
}
// day of the month
if (format.indexOf('d') > -1 || format.indexOf('j') > -1) {
response = response.replace('%j', date.getDate().toString())
response = response.replace('%d', _pad(date.getDate(), 2))
}
// day of the week
if (format.indexOf('D') > -1 || format.indexOf('N') > -1 || format.indexOf('w') > -1 || format.indexOf('l') > -1) {
var d_short = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
var d_long = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
response = response.replace('%w', date.getDay().toString())
response = response.replace('%N', (date.getDay() + 1).toString())
response = response.replace('%D', d_short[date.getDay()])
response = response.replace('%l', d_long[date.getDay()])
}
// month
if (format.indexOf('F') > -1 || format.indexOf('m') > -1 || format.indexOf('M') > -1 || format.indexOf('n') > -1) {
var m_short = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
var m_long = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
response = response.replace('%F', m_long[date.getMonth()])
response = response.replace('%m', _pad(date.getMonth() + 1, 2))
response = response.replace('%M', m_short[date.getMonth()])
response = response.replace('%n', (date.getMonth() + 1).toString())
}
// year
if (format.indexOf('y') > -1 || format.indexOf('Y') > -1) {
response = response.replace('%y', date.getFullYear().toString().substr(2))
response = response.replace('%Y', date.getFullYear())
}
// hours
if (format.indexOf('g') > -1 || format.indexOf('G') > -1 || format.indexOf('h') > -1 || format.indexOf('H') > -1) {
var hours = date.getHours()
response = response.replace('%G', hours.toString())
response = response.replace('%H', _pad(hours, 2))
// get 12-hour time
if (hours == 0) { hours = 12 }
if (hours > 12) { hours -= 12 }
response = response.replace('%g', hours.toString())
response = response.replace('%h', _pad(hours, 2))
}
// minutes
if (format.indexOf('i') > -1) {
response = response.replace('%i', _pad(date.getMinutes(), 2))
}
// seconds
if (format.indexOf('s') > -1) {
response = response.replace('%s', _pad(date.getSeconds(), 2))
}
// AM and PM
if (format.indexOf('a') > -1 || format.indexOf('A') > -1) {
var m = date.getHours() > 0 && date.getHours < 12 ? 'am' : 'pm'
response = response.replace('%a', m)
response = response.replace('%A', m.toUpperCase())
}
return response
}
