JavaScript date
Format a local date/time
1 2 3 4 56 7 8 9 1011 12 13 14 1516 17 18 19 2021 22 23 24 2526 27 28 29 3031 32 33 34 3536 37 38 39 4041 42 43 44 4546 47 48 49 5051 52 53 54 5556 57 58 59 6061 62 63 64 6566 67 68 69 7071 72 73 74 7576 77 78 79 8081 82 83 84 8586 87 88 89 9091 92 93 94 9596 97 98 99 100101 102 103 104 105106 107 108 109 110111 112 113 114 115116 117 118 119 120121 122 123 124 125126 127 128 129 130131 132 133 134 135136 137 138 139 140141 142 143 144 145146 147 148 149 150151 152 153 154 155156 157 158 159 160161 162 163 164 165166 167 168 169 170171 172 173 174 175176 177 178 179 180181 182 183 184 185186 187 188 189 190191 192 193 194 195196 197 198 199 200201 202 203 204 205206 207 208 209 210211 212 213 214 215216 217 218 219 220221 222 223 224 225226 227 228 229 230231 232 233 234 235236 237 238 239 240241 242 243 244 245246 247 248 249 250251 252 253 254 255256 257 258 259 260261 262 263 264 265266 | function date (format, timestamp) { // Format a local date/time // // version: 1109.2015 // discuss at: http://phpjs.org/functions/date // + original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com) // + parts by: Peter-Paul Koch (http://www.quirksmode.org/js/beat.html) // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: MeEtc (http://yass.meetcweb.com) // + improved by: Brad Touesnard // + improved by: Tim Wiel // + improved by: Bryan Elliott // // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: David Randall // + input by: Brett Zamir (http://brett-zamir.me) // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: Theriault // + derived from: gettimeofday // + input by: majak // + bugfixed by: majak // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + input by: Alex // + bugfixed by: Brett Zamir (http://brett-zamir.me) // + improved by: Theriault // + improved by: Brett Zamir (http://brett-zamir.me) // + improved by: Theriault // + improved by: Thomas Beaucourt (http://www.webapp.fr) // + improved by: JT // + improved by: Theriault // + improved by: Rafał Kukawski (http://blog.kukawski.pl) // + bugfixed by: omid (http://phpjs.org/functions/380:380#comment_137122) // + input by: Martin // + input by: Alex Wilson // % note 1: Uses global: php_js to store the default timezone // % note 2: Although the function potentially allows timezone info (see notes), it currently does not set // % note 2: per a timezone specified by date_default_timezone_set(). Implementers might use // % note 2: this.php_js.currentTimezoneOffset and this.php_js.currentTimezoneDST set by that function // % note 2: in order to adjust the dates in this function (or our other date functions!) accordingly // * example 1: date('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400); // * returns 1: '09:09:40 m is month' // * example 2: date('F j, Y, g:i a', 1062462400); // * returns 2: 'September 2, 2003, 2:26 am' // * example 3: date('Y W o', 1062462400); // * returns 3: '2003 36 2003' // * example 4: x = date('Y m d', (new Date()).getTime()/1000); // * example 4: (x+'').length == 10 // 2009 01 09 // * returns 4: true // * example 5: date('W', 1104534000); // * returns 5: '53' // * example 6: date('B t', 1104534000); // * returns 6: '999 31' // * example 7: date('W U', 1293750000.82); // 2010-12-31 // * returns 7: '52 1293750000' // * example 8: date('W', 1293836400); // 2011-01-01 // * returns 8: '52' // * example 9: date('W Y-m-d', 1293974054); // 2011-01-02 // * returns 9: '52 2011-01-02' var that = this, jsdate, f, formatChr = /\\?([a-z])/gi, formatChrCb, // Keep this here (works, but for code commented-out // below for file size reasons) //, tal= [], _pad = function (n, c) { if ((n = n + '').length < c) { return new Array((++c) - n.length).join('0') + n; } return n; }, txt_words = ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; formatChrCb = function (t, s) { return f[t] ? f[t]() : s; }; f = { // Day d: function () { // Day of month w/leading 0; 01..31 return _pad(f.j(), 2); }, D: function () { // Shorthand day name; Mon...Sun return f.l().slice(0, 3); }, j: function () { // Day of month; 1..31 return jsdate.getDate(); }, l: function () { // Full day name; Monday...Sunday return txt_words[f.w()] + 'day'; }, N: function () { // ISO-8601 day of week; 1[Mon]..7[Sun] return f.w() || 7; }, S: function () { // Ordinal suffix for day of month; st, nd, rd, th var j = f.j(); return j > 4 && j < 21 ? 'th' : {1: 'st', 2: 'nd', 3: 'rd'}[j % 10] || 'th'; }, w: function () { // Day of week; 0[Sun]..6[Sat] return jsdate.getDay(); }, z: function () { // Day of year; 0..365 var a = new Date(f.Y(), f.n() - 1, f.j()), b = new Date(f.Y(), 0, 1); return Math.round((a - b) / 864e5) + 1; }, // Week W: function () { // ISO-8601 week number var a = new Date(f.Y(), f.n() - 1, f.j() - f.N() + 3), b = new Date(a.getFullYear(), 0, 4); return _pad(1 + Math.round((a - b) / 864e5 / 7), 2); }, // Month F: function () { // Full month name; January...December return txt_words[6 + f.n()]; }, m: function () { // Month w/leading 0; 01...12 return _pad(f.n(), 2); }, M: function () { // Shorthand month name; Jan...Dec return f.F().slice(0, 3); }, n: function () { // Month; 1...12 return jsdate.getMonth() + 1; }, t: function () { // Days in month; 28...31 return (new Date(f.Y(), f.n(), 0)).getDate(); }, // Year L: function () { // Is leap year?; 0 or 1 return new Date(f.Y(), 1, 29).getMonth() === 1 | 0; }, o: function () { // ISO-8601 year var n = f.n(), W = f.W(), Y = f.Y(); return Y + (n === 12 && W < 9 ? -1 : n === 1 && W > 9); }, Y: function () { // Full year; e.g. 1980...2010 return jsdate.getFullYear(); }, y: function () { // Last two digits of year; 00...99 return (f.Y() + "").slice(-2); }, // Time a: function () { // am or pm return jsdate.getHours() > 11 ? "pm" : "am"; }, A: function () { // AM or PM return f.a().toUpperCase(); }, B: function () { // Swatch Internet time; 000..999 var H = jsdate.getUTCHours() * 36e2, // Hours i = jsdate.getUTCMinutes() * 60, // Minutes s = jsdate.getUTCSeconds(); // Seconds return _pad(Math.floor((H + i + s + 36e2) / 86.4) % 1e3, 3); }, g: function () { // 12-Hours; 1..12 return f.G() % 12 || 12; }, G: function () { // 24-Hours; 0..23 return jsdate.getHours(); }, h: function () { // 12-Hours w/leading 0; 01..12 return _pad(f.g(), 2); }, H: function () { // 24-Hours w/leading 0; 00..23 return _pad(f.G(), 2); }, i: function () { // Minutes w/leading 0; 00..59 return _pad(jsdate.getMinutes(), 2); }, s: function () { // Seconds w/leading 0; 00..59 return _pad(jsdate.getSeconds(), 2); }, u: function () { // Microseconds; 000000-999000 return _pad(jsdate.getMilliseconds() * 1000, 6); }, // Timezone e: function () { // Timezone identifier; e.g. Atlantic/Azores, ... // The following works, but requires inclusion of the very large // timezone_abbreviations_list() function. /* return this.date_default_timezone_get(); */ throw 'Not supported (see source code of date() for timezone on how to add support)'; }, I: function () { // DST observed?; 0 or 1 // Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC. // If they are not equal, then DST is observed. var a = new Date(f.Y(), 0), // Jan 1 c = Date.UTC(f.Y(), 0), // Jan 1 UTC b = new Date(f.Y(), 6), // Jul 1 d = Date.UTC(f.Y(), 6); // Jul 1 UTC return 0 + ((a - c) !== (b - d)); }, O: function () { // Difference to GMT in hour format; e.g. +0200 var tzo = jsdate.getTimezoneOffset(), a = Math.abs(tzo); return (tzo > 0 ? "-" : "+") + _pad(Math.floor(a / 60) * 100 + a % 60, 4); }, P: function () { // Difference to GMT w/colon; e.g. +02:00 var O = f.O(); return (O.substr(0, 3) + ":" + O.substr(3, 2)); }, T: function () { // Timezone abbreviation; e.g. EST, MDT, ... // The following works, but requires inclusion of the very // large timezone_abbreviations_list() function. /* var abbr = '', i = 0, os = 0, default = 0; if (!tal.length) { tal = that.timezone_abbreviations_list(); } if (that.php_js && that.php_js.default_timezone) { default = that.php_js.default_timezone; for (abbr in tal) { for (i=0; i < tal[abbr].length; i++) { if (tal[abbr][i].timezone_id === default) { return abbr.toUpperCase(); } } } } for (abbr in tal) { for (i = 0; i < tal[abbr].length; i++) { os = -jsdate.getTimezoneOffset() * 60; if (tal[abbr][i].offset === os) { return abbr.toUpperCase(); } } } */ return 'UTC'; }, Z: function () { // Timezone offset in seconds (-43200...50400) return -jsdate.getTimezoneOffset() * 60; }, // Full Date/Time c: function () { // ISO-8601 date. return 'Y-m-d\\Th:i:sP'.replace(formatChr, formatChrCb); }, r: function () { // RFC 2822 return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb); }, U: function () { // Seconds since UNIX epoch return jsdate.getTime() / 1000 | 0; } }; this.date = function (format, timestamp) { that = this; jsdate = ((typeof timestamp === 'undefined') ? new Date() : // Not provided (timestamp instanceof Date) ? new Date(timestamp) : // JS Date() new Date(timestamp * 1000) // UNIX timestamp (auto-convert to int) ); return format.replace(formatChr, formatChrCb); }; return this.date(format, timestamp);} |
Examples
» Example 1
Running
1 | date('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400); |
Should return
1 | '09:09:40 m is month' |
» Example 2
Running
1 | date('F j, Y, g:i a', 1062462400); |
Should return
1 | 'September 2, 2003, 2:26 am' |
Dependencies
No dependencies, you can use this function standalone.
Open syntax issues
php.js uses JsLint to help us keep our code consistent and prevent some common bugs.
Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.
Authors
Thanks to the following developers, you get to have date goodness in JavaScript.
var date = function( a, s )
{
var d = isNaN( s *= 1000 ) ? new date() : new date( s ), f = d.getTime();
return ( '' + a ).replace( /a|A|d|D|F|g|G|h|H|i|I|j|l|L|m|M|n|s|S|t|T|U|w|y|Y|z|Z/g, function( a )
{
switch ( a )
{
case 'a' : return d.getHours() > 11 ? 'pm' : 'am';
case 'A' : return d.getHours() > 11 ? 'PM' : 'AM';
case 'd' : return ( '0' + d.getDate() ).slice(-2);
case 'D' : return [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ][ d.getDay() ];
case 'F' : return [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ][ d.getMonth() ];
case 'g' : return ( s = ( d.getHours() || 12 ) ) > 12 ? s - 12 : s;
case 'G' : return d.getHours();
case 'h' : return ( '0' + ( ( s = d.getHours() || 12 ) > 12 ? s - 12 : s ) ).slice(-2);
case 'H' : return ( '0' + d.getHours() ).slice(-2);
case 'i' : return ( '0' + d.getMinutes() ).slice(-2);
case 'I' : return (function(){ d.setDate(1); d.setMonth(0); s = [ d.getTimezoneOffset() ]; d.setMonth(6); s[1] = d.getTimezoneOffset(); d.setTime( f ); return s[0] == s[1] ? 0 : 1; })();
case 'j' : return d.getDate();
case 'l' : return [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ][ d.getDay() ];
case 'L' : return ( s = d.getFullYear() ) % 4 == 0 && ( s % 100 != 0 || s % 400 == 0 ) ? 1 : 0;
case 'm' : return ( '0' + ( d.getMonth() + 1 ) ).slice(-2);
case 'M' : return [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ][ d.getMonth() ];
case 'n' : return d.getMonth() + 1;
case 's' : return ( '0' + d.getSeconds() ).slice(-2);
case 'S' : return [ 'th', 'st', 'nd', 'rd' ][ ( s = d.getDate() ) < 4 ? s : 0 ];
case 't' : return (function(){ d.setDate(32); s = 32 - d.getDate(); d.setTime( f ); return s; })();
case 'T' : return 'UTC';
case 'U' : return ( '' + f ).slice( 0, -3 );
case 'w' : return d.getDay();
case 'y' : return ( '' + d.getFullYear() ).slice(-2);
case 'Y' : return d.getFullYear();
case 'z' : return (function(){ d.setMonth(0); return d.setTime( f - d.setDate(1) ) / 86400000; })();
default : return -d.getTimezoneOffset() * 60;
};
} );
};
Hello Everyone,
We can use Date () object to manipulate dates in java script. Whenever we want to access current date of the system or want to set new date in java script then we can use appropriate java script method of date function. In this demonstration we learn how to work with function of date object.........
For more details check this link.....
http://mindstick.com/Articles/c18de1aa-fd9c-433a-80ea-93c14522c856/?Implementing%20Date%20object%20in%20Java%20Script
Thanks !!!!
@omid: thanks for your bug report. The function is now fixed on Github (https://github.com/kvz/phpjs/commit/97aa7a53befc80544cd4bdc681deab041cfee779)
O return incorrect format
for example return +0350 instead of +0330
code must change to
var a = jsdate.getTimezoneOffset(); return (a > 0 ? "-" : "+") + _pad(Math.floor(Math.abs(a) / 60) * 100 + Math.abs(a) % 60, 4);
@Alex Wilson: Thanks very much for the implementation, but by relying on "new Function", it runs a bit more slowly, as well as has some eval-ish concerns.
A shorter implementation:
https://gist.github.com/raw/899179/40ef949f244fdbf4103804b870c515e134b611ec/php.date.js
I think I found a problem with this function:
date('d-m-Y', strtotime("2012-02-04 +6 WEEK"));
returns 17-05-2011 insted of 17-03-2012 as it should. Or am I doing something wrong?
Be aware that this implementation will emit non-zero-padded numbers when using "W" whereas php's native implementation does pad the lower numbers.
Looks like there's a bug in date() when using Firefox. It's certainly present on version 4.0b7 on Mac OS X, not sure about other versions.
<script type="text/javascript" src="php.full.min.js"></script>
<script type="text/javascript">
window.onload=function() {
var myDate='1970-01-01 00:00:00';
var myTimestamp=strtotime(myDate);
var myFormattedDate=date('d/m/Y H:i:s', myTimestamp);
alert('myDate: ' + myDate + '\n' + 'myTimestamp: ' + myTimestamp + '\n' + 'myFormattedDate: ' + myFormattedDate);
}
</script>
After applying date(), it incorrectly reports that the hour is 01, instead of 00.
Doesn't seem to be an issue in Safari.
In line 147 the code not right.
date('o-W',1293840000);
the result return 2012-52 , php function will return 2010-52.
maybe the code can change to
return Y + (n === 12 && W < 9 ? -1 : n === 1 && W > 9? -1 : 0);
thanks
@Nox: Thanks for the submissions. As far as JT's change, I don't have time right now to review; anyone else? As far as Date.prototype, we don't like to pollute the native prototype objects, though I know it can be convenient. As far as internationalization, as per PHP's recommendation (since date() is not localized), we use strftime & setlocale for localization of dates instead (as it provides a clear "PHP way" for us to implement it following the same API and behavior).
... Actually I just can't figure out where I should send the modified version... If you like to get it, just send me an email...
Thanks again
Nox
Hi, just send you an email with a few changes I recommend.
The first one was already made by @JT:
var date = (function() { ... return function(date, timestamp)
The second one is just a way to honor JS...
Date.prototype.format = function (format) {return date(format, this); };
And last but not least I changed to access to the day-strings and month-strings to make it more customizable.
/*...*/
F: function () { // Full month name; January...December
return date.i18n.months[12 + f.n()];
}
/*...*/
date.lang = { eng: {
days: [ /* days start with 0 */ ],
months: [null, /* months start with 1 */],
ordin: { /* ... */ }
}
};
date.i18n = date.lang.eng; // select english
Hope this is useful. If anyone needs my code send me an email.
Thanks for the code, I'm using it serverside on node.js like I was using PHP-date before,
Nox
@Kevin: Thanks, I found the problem: It relates with daylight saving time. So that was my fault. sorry.
@clinisbut: Tested it, but our output exactly matches PHP's.
Here, this snippet runs both in PHP as in the unnamespaced php.js version:
$timestamp = mktime(0, 0, 0, 10, 31, 2010);
$temp = $timestamp + (60*60*24*7);
$string_date = date('d-m-Y', $temp);
print($string_date);
Hi, I'm having an issue with date function.
Starting from a timestamp, I'm adding seven days and converting to string using date() function. Rarely, when I add seven days to 2010-10-31 it gives me 2010-11-6 instead of 2010-11-7.
This is my code
$P = new PHP_JS();
timestamp = $P.mktime( 0, 0, 0,month, day, year );
temp = timestamp + (60*60*24*7);
string_date = $P.date('d-m-Y', temp));
Other dates work fine... is this a bug?
@ Rafał Kukawski: I think I agree. As long as it's 10:00:00 (.9), it still is 10:00:00 and not 10:00:01 implemented your fix, thanks a lot! http://github.com/kvz/phpjs/commit/c3cd2f82d214c4b11edac89d14162fcad3a5675e
IMO in U() we should do Math.floor instead of Math.round, cause we shouldn't add 1 sec to the result when the millisecond part is just over 500. If you agree, my proposition is
U: function () { // Seconds since UNIX epoch
return Math.floor(jsdate.getTime() / 1000);
}
or even
U: function () { // Seconds since UNIX epoch
return jsdate.getTime() / 1000 | 0;
}
U: function () { // Seconds since UNIX epoch
return jsdate / 1e3 | 0;
}
if you accept less self-explaining code.
My proposition for checking for leap years would be
L: function(){
return new Date(jsdate.getFullYear(), 1, 29).getMonth()==1|0;
}
It uses the JS engine to calculate the correct month for February 29 for given year.
@Theriault :
Current timezone is Paris GMT+1 (winter / DST off)
Your variant works, provided you throw in a +1 :
z: function (){
return Math.round((new Date(f.Y(), f.n() - 1, f.j()) - new Date(f.Y(), 0, 1)) / 864e5) + 1;
}
Great work on an incredibly useful function, guys.
Seems like repeatedly declaring the regEx and all of those inner functions every time the date function is called would be pretty inefficient, though. Have you considered doing something like this?
var date = (function () {
function pad(n, c) {
...
}
var that = this,
formatChr = /\\?([a-z])/gi,
txt_words = [ ... ],
txt_ordin = { ... },
f = {
w : function (d) {
return d.getDay();
},
...
};
return function (format, timestamp) {
// Just for clarity :$
if (timestamp) {
jsdate = (timestamp instanceof Date) ? new Date(timestamp) : new Date(timestamp * 1000);
} else {
jsdate = new Date();
}
return format.replace(formatChr, function (t, s) {
return f[t] ? f[t](jsdate) : s;
});
};
}());
JT
@Felix: The 'W' function has been updated with a new algorithm. Thank you for your contribution.
@Thomas: I cannot seem to reproduce the bug you are experiencing. What is your system's current timezone offset and what browser are you using? Also, does the following code also fix the problem:
z: function () {
return Math.round((new Date(f.Y(), f.n() - 1, f.j()) - new Date(f.Y(), 0, 1)) / 864e5);
},
The "z" function is buggy.
It doesn't account for daylight saving time when doing :
(jsdate - new Date(jsdate.getFullYear() + "/1/1")) / 864e5
thus it returned 2 days more for '2009-10-25' than for '2009-10-24'.
My fixed function is :
z: function (){
var m = f.n();
var z = 0;
for (i=1; ireturn z + f.j();
}
Which uses an improved t function accepting a parameter :
t: function (n) {
if (n == undefined) n = jsdate.getMonth() + 1;
if ( n == 2 ) return 28 + f.L();
if ( n & 1 && n < 8 || !(n & 1) && n > 7 ) return 31;
return 30;
}
Thanks for the good work !
Sorry for repost: I mean 2nd january 2006 returns wrong week number.
php.date("W", new Date(2006,0,2)) // correct result would be "1"
The "W" function is wrong. For example for the 2nd january 2005 it returns the wrong weak number. I correct it myself with another algorithm:
// Week
W: function () {
var x = (new Date(jsdate.getFullYear(), 0, 4))
var a = new Date(jsdate.getFullYear(), 0, 4-(x.getDay()==0 ? 7:x.getDay()-1))
for (var w=0; w <= 53; w++) {
var b = new Date(a.getFullYear(), a.getMonth(), a.getDate()+(w-1)*7, 0,0,0,0)
var c = new Date(a.getFullYear(), a.getMonth(), a.getDate()+w*7, 0,0,0,0)
if (jsdate >= b && jsdate < c) {break;}
}
if (w >= 1 && w <= 52) {return w;}
if (w >= 52 && w != ((new Date(jsdate.getFullYear(),0,1)).getDay() == 4 ? 53 : 52)) {return 1;}
return ((new Date(jsdate.getFullYear(),0,1)).getDay() == 4 ? 53 : 52);
},
Hey there Theriault!
Blown away by your expertise & quality of code. Let me try to reach you by mail and see if you'd like to append the code another way ; )
If you haven't received my mail drop another line here, ok?
The return function at the bottom could be shortened to one line using a ternary operator:
return format.replace(/\\?([a-z])/gi, function (t, s) {return f[t] ? f[t]() : s;});
"I" could not rely on the _dst function up top and be shortened to one line:
return 0 + (t.getTimezoneOffset() < Math.max((new Date(d.Y(), 0, 1)).getTimezoneOffset(), (new Date(d.Y(), 6, 1)).getTimezoneOffset()));
And a bunch of little nitpicky fixes that I can suggest:
txt_weekdays at the top could remove the repeat of 'day' 7 times and just add 'day' to the 'l' (lowercase-L) function:
var txt_weekdays = ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur"]; return txt_weekdays[f.w()] + 'day';
'N' could be like 'g' and use the OR operator to make it a little shorter:
return f.w() || 7;
'S' could also use the OR operator to make it a bit shorter:
return txt_ordin[f.j()] || 'th';
'o' (lowercase O) could be shortened to one line:
return f.Y() + (f.n() == 12 && f.W() < 9 ? -1 : (f.n() == 1 && f.W() > 9 ? 1 : 0));
'M' could be one line:
return f.F().slice(0, 3);
'D' could be one line:
return f.l().slice(0, 3);
Thanks. Keep up the good work PHP.JS.
@Brett: I was unsure, but after reviewing ECMA-262, it is a part of the ECMA standards. The standards state that date arguments are to be treated as finite integers and they all support values outside the ranges (such as 13, 1000, or even -500 for the month). The date argument formula is:
Day(Result(7)) + Result(4) − 1.
Day(Result(7)) returns the computed days since Jan 1, 1970 for the current time's year and month, Result(7), plus Result(4) which is the integer date argument, so 0 would add no days to the first of the calculated month and year, then it subtracts one day to account for the first day of the month which was included in the calculation of Result(7), so that would be the previous month's last day.
I would have to say that the algorithm's that ECMA has laid out for date handling are the best I've seen out there; very flexible. To think that Date.setDate(Date.getDate() - 7) subtracts one week exactly, or Date.setMonth(Date.getMonth() - 6) can subtract half a year is fantastic, no matter the date.
However, the way I did it is incorrect. A string argument being passed to the Date constructor may be handled differently by all browsers. 't' should be changed to use 3 integers in the constructor instead:
return (new Date(f.Y(), f.n() + 1, 0).getDate();
I believe I have found the solution to 'W', also. The following should work after reviewing ISO-8601 algorithms for calculating the week. I have confirmed it works from Jan 1 1900 to Dec 32 2100, which is likely enough testing:
return 1 + Math.round(((c = new Date(d.Y(), d.n() - 1, d.j() - d.N() + 3)) - (new Date(c.getFullYear(), 0, 4))) / 864e5 / 7);
Does anyone know whether the technique of setting a date to '0' to get the last day of the month (as used in Theriault's 't' implementation) part of the ECMAScript spec or is it just a browser convention?
Hey Theriault, thanks for your improvements. I've just added them to the repo.
http://github.com/kvz/phpjs/commit/0a830484289ece0cebdbf6d2fafe849b9308284b
As for the W: issue, I've added a testcase (#8) that confirms we stray from PHP's behavior there () (but it seems PHP in turn strays from my System's calendar ; ), this will require a quiet sunday afternoon of tesing & fixing though..
If anyone is up for a challenge, that would rock! :D
I found a bug with 'W'. For 2010, week 52 runs from 12/27/2010 to 12/31/2010 (only 5 days), then 1/1/2011 is week 53, then 1/2/2011 to 1/3/2011 are the last two days of week 52. Then week 1 is 1/4/2011 to 1/9/2011 (only 6 days). It seems to happen on other dates, too, with some weeks having only 6 days and some having 8 days.
'B' could be simplified to:
return pad(Math.floor(((t.getUTCHours() * 36e2) + (t.getUTCMinutes() * 60) + t.getUTCSeconds() + 36e2) / 86.4) % 1e3, 3);
@Alex: The issue should be fixed now. Our date functions were only accepting "undefined" (or missing) timestamps, numeric timestamps, or JavaScript Date() object timestamps. If they were expressed as a string or other non-object types, there was no attempt to auto-convert them (as PHP does). It seems therefore that your JSON was returning timestamps as strings and not numbers, thus causing a mismatch. However, the latest version in git can handle the strings now too: http://github.com/kvz/phpjs/commits/master/functions/datetime/date.js/8a428dccc64253a59b84b692fbfe323f5e9d29c9 . FYI, you might want to check out https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Operators/Special_Operators#conditional_operator to understand what the code at the beginning of the function is doing when assigning timestamp to a Date object, if you were not clear. Have fun!
@Brett It was a standard unix timestamp in seconds. (meant to indicate that in my inital post). It appears that the original source code handled a conversion (line 39 in v909.322).
I imagine that was written this way in the first place to handle PHP defaulting to mktime() if the 2nd argument isn't set, but I don't see anywhere where that actually happens, thus if the typeof(timestamp) fails there is no value when the JS Date() methods are called.
@Alex: Thanks. Now, what data did you have in "data.ts" and what type (Number, Date object?). And though I don't think it would matter in this case, are you using a Unix timestamp as in seconds (as in PHP), or a JavaScript value in milliseconds?
I should mention that I first encountered this issue in Chrome 3, and tested my fix in Chrome 3, FF 3.5, IE8, Safari 3.2.2, and Opera 9.64 all on Windows XP.


Chris
29 Dec '11
date, W, o, o should be
2007-12-31, 52, 2006, 2008
2010-01-01, 52, 2011, 2009
2011-01-01, 52, 2012, 2010
2012-01-01, 52, 2013, 2011
2001-12-31, 1, 2000, 2002
Change function for 'o' to:
o: function () { // ISO-8601 year var n = f.n(), W = f.W(), Y = f.Y(); return Y + (n === 12 && W < 9 ? +1 : n === 1 && W > 9 ? -1 : 0); }