Tuesday, April 22, 2008

strftime in Javascript

As a follow-up to my last post about Javascript date functions, I went ahead and implemented strftime for javascript.

Have a look at the demo at the link above, and download the code: strftime.js. It's distributed under a BSD license, so use it and give me feedback. Post comments here for now.The code is documented using doxygen style comments.

You should also check out Stoyan's time input library that lets you do the equivalent of php's strtotime function.

Labels: , , , , ,

10 Comments:

Blogger Mikko said...

Hi,
I ran into what looks like a bug with timezone specifiers:

Value of format specifier %z is printed out as "+0-300" (should be
"+0300"), as d.getTimezoneOffset() returns a negative number, and xPad
doesn't take the minus character into account. My simple fix: replace

var H = Date.ext.util.xPad(parseInt(o/60, 10), 0);

with

var H = Date.ext.util.xPad(parseInt(Math.abs(o)/60, 10), 0);

Also, with %Z, your script relies on date string containing the name of timezone in parentheses. This holds for Firefox, but not for Internet Explorer
(tested on 7.0.5730.13), on which you get the whole date string (looks bad).

Otherwise this is a fine script, especially since localisation is so easy. Thanks!

7:46 AM  
Blogger Blues said...

Thanks for the report. I've fixed this in svn, and given you credit for it.

I'll make a release once I've tested this, and the %p changes I've made.

11:39 AM  
Blogger Brett said...

Hi,

Very nice stuff! I've been working with the PHP.JS project and your function would make a nice addition there (ours is an MIT-style license, which looks like it will fit fine with yours).

I'll need to mix it around (i.e., not use a class), since we are insisting that each function can work independently just as a function, with the exception of sometimes using, out of necessity, a global window.php_js object.

There are a few items you may be interested in:

1. There is a call to "Date.ext.util.G" which should apparently be "Date.ext.formats.G"
2. To aggregates, add the following (also add it to the regular expressions): F: '%y-%m-%d',
3. To formats, add the following (also add it to the regular expression): l: function (d) {var l=d.getHours()%12; return Date.ext.util.xPad(l===0?12:l, ' ');},
s: function(d) { return Date.parse(d)/1000; },
4. You may wish to add their documentation from PHP as well for F, l, s
5. It looks like Date.ext.formats.c is not being used
6. When you copy one object to another directly, you are copying by reference--so your assignments for the en-US, en-GB, and en-AU are all tied together. You might consider first wrapping the right-hand assignment in a call to a copy() function like this:

var _copy = function (orig) {
var newObj = {};
for (var i in orig) {
newObj[i] = orig[i];
}
return newObj;
};
7. And if you want to be a little more open to XHTML: var NS_XHTML = 'http://www.w3.org/1999/xhtml';
var NS_XML = 'http://www.w3.org/XML/1998/namespace';
if (document.getElementsByTagNameNS &&
document.getElementsByTagNameNS(NS_XHTML, 'html')[0]) {
if (document.getElementsByTagNameNS(NS_XHTML, 'html')[0].getAttributeNS &&
document.getElementsByTagNameNS(NS_XHTML, 'html')[0].getAttributeNS(NS_XML, 'lang')) {
Date.prototype.locale = document.getElementsByTagName(NS_XHTML, 'html')[0].getAttributeNS(NS_XML, 'lang');
}
else if(document.getElementsByTagNameNS(NS_XHTML, 'html')[0].lang) { // XHTML 1.0 only
Date.prototype.locale = document.getElementsByTagNameNS(NS_XHTML, 'html')[0].lang
}
}
else if(document.getElementsByTagName('html')[0] && document.getElementsByTagName('html')[0].lang) {
Date.prototype.locale = document.getElementsByTagName('html')[0].lang;
}

Look forward to your version of strptime() (hint hint) ;)

best, Brett

9:06 PM  
Blogger Blues said...

Hi Brett, thanks for the comments and detailed suggestions. I've actually folded this implementation into the YUI library - it's part of the datasource utility and referred to as YAHOO.util.Date. It probably already has some of the fixes that you've suggested since I went all out with completeness on that version.

YUI is under the BSD license, so should also be compatible with your project. Feel free to pull the implementation out of there and reuse it. The main difference is that the YUI version does not touch the Date prototype.

As regards strptime. Well, let's say that I've been thinking about it :)

9:39 PM  
Blogger Brett said...

Very cool, Blues--I noticed a couple improvements there which I also added to our version... Well, if it is any help, I see at the PHP manual page for strptime() that there is a link to some code meant to implement it in PHP (since it is not available for Windows), which might be of some help: http://sauron.lionel.free.fr/?page=php_lib_strptime . You might also see the comment about it at http://php.net/strptime

best wishes and thanks so much again!

12:31 PM  
Blogger Blues said...

Thanks for the link Brett, though I might have to implement sscanf in Javascript first (though I'm sure you probably already have that done).

My approach is more likely to be regex based. The bigger problem though is locale support. The parser for en-UK dates is going to be different from the parser for fr-CA dates.

5:13 PM  
Blogger Brett said...

No, unfortunately no sscanf yet. (We have printf and sprintf though.)

By the way, as I see Yahoo did in making a separate locale package (your work too?), I had some fun adding a setlocale() function for PHP--so some of your work should end up in that function too. It's funny how certain features like setlocale(), and even potentially the output buffering functions in PHP can be mimicked in JavaScript--while still keeping the simple PHP syntax (though we can still wrap all of the functions in a namespace and/or an instantiable/configurable class--the latter being a future goal).

Anyhow, thanks again, and it'd be great if you could drop us a note if you came up with something and don't mind.

best, Brett

7:36 PM  
Blogger Blues said...

yeah, DateLocale is also my work. I actually have a php script to generate javascript date locales. It's pretty simple actually. Something like this:

setlocale(LC_TIME, 'locale');
$lc = array (
"a" => array(),
"A" => array(),
"b" => array(),
"B" => array(),
"c" => "%Y %m %d (%a) %r",
"p" => array(),
"P" => array(),
"r" => "%p %I %M %S %p %Z",
"x" => "%Y %m %d",
"X" => "%H %M %S"
);
$lc['c'] = strftime("%c");
$lc['r'] = strftime("%r");
$lc['x'] = strftime("%X");
$lc['X'] = strftime("%X");
for($i=6; $i<13; $i++)
{
$d = strtotime("2008/01/$i");
$lc['a'][] = strftime("%a", $d);
$lc['A'][] = strftime("%A", $d);
}
for($i=1; $i<13; $i++)
{
$d = strtotime("2008/$i/1");
$lc['b'][] = strftime("%b", $d);
$lc['B'][] = strftime("%B", $d);
}

$d = strtotime("2008/01/01 10:00:00");
$lc['p'][] = strftime("%p", $d);
$lc['P'][] = strftime("%p", $d);
$d = strtotime("2008/01/01 22:00:00");
$lc['p'][] = strftime("%p", $d);
$lc['P'][] = strftime("%p", $d);

echo json_encode($lc);

8:05 PM  
Blogger kvz said...

Hello, we are working on an open source javascript libary that aims to port php functionality to javascript here: http://phpjs.org and we would very much like to use your strftime in it.
Would you be okay with it if we credit it to you? Our dual license is: mit/gpl

4:34 AM  
Blogger Blues said...

kvz, like I mentioned to Brett above, you'd be better off using the code from the YUI library where I've made many bug fixes and enhancements. YUI is under the BSD licence, so you should be able to copy the code as long as you maintain the licence for that one function.

12:31 PM  

Post a Comment

<< Home