My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label Date. Show all posts
Showing posts with label Date. Show all posts

Wednesday, July 15, 2009

The Fastest Date toJSON and fromJSON?

I know yesterday post supposed to be the last 'till the the end of the month but I could not resits. Dustin Diaz twitted

anyone trying to parse our wonky rails dates in JS. do this: var date = Date.parse(str.replace(/( \+)/, ' UTC$1')); seems to fix it.

Again, I could not resist to create a toUTCString based function to create JSON strings and to parse them back. This is the result and apparently is both the fastest implementation I know and cross browser (Chrome, Firefox, Inernet Explorer, Safari).
This is a quick post so if you find some problem please let me know, thanks.

(function(){
// WebReflection Fast Date.prototype.toJSON and Date.fromJSON Suggestion
var rd = /^.{5}(\d{1,2}).(.{3}).(.{4}).(.{2}).(.{2}).(.{2}).+$/,
rs = /^(.{4}).(.{2}).(.{2}).(.{2}).(.{2}).(.{2}).+$/,
d = new Date,
f = /(GMT|UTC)$/.exec(d.toUTCString())[1], // cheers gazheyes
m = {},
i = 0,
s = ""
;
d.setUTCDate(1);
while(i < 12){
d.setUTCMonth(i);
m[s = /^.{5}(\d{1,2}).(.{3})/.exec(d.toUTCString())[2]] = ++i < 10 ? "0" + i : i;
m[m[s]] = s;
};
Date.prototype.toJSON = function(){
var e = rd.exec(this.toUTCString());
return e[3].concat("-", m[e[2]], "-", e[1], "T", e[4], ":", e[5], ":", e[6], "Z");
};
try{Date.fromJSON(d.toJSON());
Date.fromJSON = function(s){
var e = rs.exec(s);
return new Date(Date.parse(e[2].concat(" ", e[3], " ", e[1], " ", e[4], ":", e[5], ":", e[6], " ", f)));
};
}catch(e){
Date.fromJSON = function(s){
var e = rs.exec(s);
return new Date(Date.parse(e[3].concat(" ", m[e[2]], " ", e[1], " ", e[4], ":", e[5], ":", e[6], " ", f)));
};
}
})();

Basically everything is a shortcut and I am using only native methods ... is there anything faster except probably a substr based one?

Friday, July 10, 2009

ECMAScript 5 Full Specs String trim, trimLeft, and trimRight

During last evenings I have updated a little bit my vice-versa project.
Since vice-versa aim is to bring in every browser what is possible to implement and, in most of the cases, already defined as standard (from W3 or MSDN when it is worthy) I decided to get rid of the Ariel Flesler fast trim proposal to introduce my lightweight full specs String.prototype.trim, trimLeft, and trimRight.
For full specs I mean that vice-versa String.prototype.trim replace exactly same characters replaced by native Firefox 3.5 implementation, rather than only characters which code is less than 33 as is for Ariel proposal.

The good part of vice-versa ( to be honest I cannot find bad parts so far ;) ) is that every single file is stand-alone, so if you do not like benefits the entire "lib" could bring, you can always adopt only one of its files, for example the String one, the Array one, or the last full specs ECMAScript 5 Date constructor, compatible with ISO strings, new Date("2009-07-10") and with a complete toISOString method for each created Date instance (of course even if replaced, new Date will produce instances of Date and their constructor will be Date itself).

If you want to give vice-versa minified a try, a little monster which size is about 5Kb gzipped, please do not hesitate to download it.

Have fun with future standards and few MSDN standard coolness for every browser ;)

Saturday, July 04, 2009

ECMAScript ISO Date For Every Browser

One most than welcome new entry of ECMAScript 5 is the Date.prototype.toISOString function and ability for Date constructor to accept an ISO String and to generate a Date instance.
This feature will make JSON Date instances import/export extremely fast and simple, but why should we wait ES5 release when we can have both features now?

Full Specs ISO 8601 Parser Plus Unobtrusive toISOString Method


We all do not like that much to extend native JavaScript constructors, so here I am with a proposal that will not touch the Date prototype:

if(!Date.ISO)(function(){"use strict";
/** ES5 ISO Date Parser Plus toISOString Method
* @author Andrea Giammarchi
* @blog WebReflection
* @version 2009-07-04T11:36:25.123Z
* @compatibility Chrome, Firefox, IE 5+, Opera, Safari, WebKit, Others
*/
function ISO(s){
var m = /^(\d{4})(-(\d{2})(-(\d{2})(T(\d{2}):(\d{2})(:(\d{2})(\.(\d+))?)?(Z|((\+|-)(\d{2}):(\d{2}))))?)?)?$/.exec(s);
if(m === null)
throw new Error("Invalid ISO String");
var d = new Date;
d.setUTCFullYear(+m[1]);
d.setUTCMonth(m[3] ? (m[3] >> 0) - 1 : 0);
d.setUTCDate(m[5] >> 0);
d.setUTCHours(m[7] >> 0);
d.setUTCMinutes(m[8] >> 0);
d.setUTCSeconds(m[10] >> 0);
d.setUTCMilliseconds(m[12] >> 0);
if(m[13] && m[13] !== "Z"){
var h = m[16] >> 0,
i = m[17] >> 0,
s = m[15] === "+"
;
d.setUTCHours((m[7] >> 0) + s ? -h : h);
d.setUTCMinutes((m[8] >> 0) + s ? -i : i);
};
return toISOString(d);
};
var toISOString = Date.prototype.toISOString ?
function(d){return d}:
(function(){
function t(i){return i<10?"0"+i:i};
function h(i){return i.length<2?"00"+i:i.length<3?"0"+i:3<i.length?Math.round(i/Math.pow(10,i.length-3)):i};
function toISOString(){
return "".concat(
this.getUTCFullYear(), "-",
t(this.getUTCMonth() + 1), "-",
t(this.getUTCDate()), "T",
t(this.getUTCHours()), ":",
t(this.getUTCMinutes()), ":",
t(this.getUTCSeconds()), ".",
h("" + this.getUTCMilliseconds()), "Z"
);
};
return function(d){
d.toISOString = toISOString;
return d;
}
})()
;
Date.ISO = ISO;
})();

The public static ISO Date method accepts a valid ISO 8601 String compatible with W3 Draft:

Year:
YYYY (eg 1997)
Year and month:
YYYY-MM (eg 1997-07)
Complete date:
YYYY-MM-DD (eg 1997-07-16)
Complete date plus hours and minutes:
YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
Complete date plus hours, minutes and seconds:
YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
Complete date plus hours, minutes, seconds and a decimal fraction of a second
YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)

where:

YYYY = four-digit year
MM = two-digit month (01=January, etc.)
DD = two-digit day of month (01 through 31)
hh = two digits of hour (00 through 23) (am/pm NOT allowed)
mm = two digits of minute (00 through 59)
ss = two digits of second (00 through 59)
s = one or more digits representing a decimal fraction of a second
TZD = time zone designator (Z or +hh:mm or -hh:mm)

The only limit is about milliseconds and JavaScript Date itself, the latest parameter will be rounded if there are more than 3 digits (JS precision is up to a millisecond, no microsecond yet).
The toISOString method is created for every browser that does not support this prototype yet but it is simply assigned and compiled once to avoid Date prototype problems and to optimize memory and performances.
I interpreted ISO specs as Zulu default:

var normalDate = new Date(2009, 06, 04);
var ISODate = Date.ISO("2009-07-04");

normalDate.toISOString = ISODate.toISOString;

alert([ // being in UK ...

// 2009-07-03T23:00:00.000Z
normalDate.toISOString(),

// 2009-07-04T00:00:00.000Z
ISODate.toISOString()
].join("\n"));

Since solar time is +01 hour, if I create a Date with midnight time, the respective Zulu one (UTC) will be the day before at 23:00:00 while since ISO consider an unspecified Time Zone the Zulu one, +00:00, the created Date will be exactly the specified one but obviously if we try to get ISODate.getHours() it will be 01 and not 00, accordingly with my local settings.

This is a little function/proposal that has zero dependencies, is widely compatible, and could be a standard or a must for every library/framework. Waiting for your thoughts, have a nice we 8)