PDA

View Full Version : [OPEN] Date.parseDate format code O doesn't work



CurtisDuhn
21 Jun 2007, 1:14 AM
I type this into my Firebug console:


Date.parseDate('2007-06-13T12:19:58-0700', 'Y-m-d\\TH:i:sO');

And it outputs this:


Wed Jun 13 2007 12:19:58 GMT-0400 (Eastern Daylight Time)

It uses the timezone for my browser's locale rather than parsing it out of the string.

Seeing this in Ext version 1.0.1

mystix
21 Jun 2007, 3:57 AM
While investigating, i found a bug in the Date object's getGMTOffset() method [1.0.1a / 1.1b1]:
Date.prototype.getGMTOffset = function() {
return (this.getTimezoneOffset() > 0 ? "-" : "+") // <-- leading + / - sign already handled here
+ String.leftPad(Math.floor(this.getTimezoneOffset() / 60), 2, "0") // <-- leading + / - sign is not removed before left-padding with zeroes
+ String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
};such that calling
(new Date()).getGMTOffset();will return a value like "+-800".


It should instead be
Date.prototype.getGMTOffset = function() {
return (this.getTimezoneOffset() > 0 ? "-" : "+")
+ String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
+ String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
};


i'm still investigating your problem though. will post back again if / when i find a solution :-?

[edit]
[1.0.1a / 1.1b1] Found another bug in the Date object's getTimezone() method:
Date.prototype.getTimezone = function() {
return this.toString().replace(
/^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace(
/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3");
};On my machine, running
(new Date()).getTimezone();in the Firebug console returns this string: "Thu Jun 21 2007 20:55:31 GMT+0800 (Malay Peninsula Standard Time)", which doesn't contain the timezone abbreviation "GMT".

Assuming the timezone abbreviation we're looking for is "GMT", and that timezone abbreviations can be 1 - 4 characters long (refer to this link (http://www.timeanddate.com/library/abbreviations/timezones/)), the code should instead be
Date.prototype.getTimezone = function() {
return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
};

mystix
21 Jun 2007, 9:18 AM
alritey, i've got a fix for your "Date.parseDate format code O" problem.

paste the following code into your overrides file (includes the getGMTOffset() fix listed above):
Date.prototype.getGMTOffset = function() {
return (this.getTimezoneOffset() > 0 ? "-" : "+")
+ String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
+ String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
};

Date.createParser = function(format) {
var funcName = "parse" + Date.parseFunctions.count++;
var regexNum = Date.parseRegexes.length;
var currentGroup = 1;
Date.parseFunctions[format] = funcName;

var code = "Date." + funcName + " = function(input){\n"
+ "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z;\n"
+ "var d = new Date();\n"
+ "y = d.getFullYear();\n"
+ "m = d.getMonth();\n"
+ "d = d.getDate();\n"
+ "var v = null, results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
+ "if (results && results.length > 0) {";
var regex = "";

var special = false;
var ch = '';
for (var i = 0; i < format.length; ++i) {
ch = format.charAt(i);
if (!special && ch == "\\") {
special = true;
}
else if (special) {
special = false;
regex += String.escape(ch);
}
else {
var obj = Date.formatCodeToRegex(ch, currentGroup);
currentGroup += obj.g;
regex += obj.s;
if (obj.g && obj.c) {
code += obj.c;
}
}
}

code += "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
+ "{v = new Date(y, m, d, h, i, s);}\n"
+ "else if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
+ "{v = new Date(y, m, d, h, i);}\n"
+ "else if (y > 0 && m >= 0 && d > 0 && h >= 0)\n"
+ "{v = new Date(y, m, d, h);}\n"
+ "else if (y > 0 && m >= 0 && d > 0)\n"
+ "{v = new Date(y, m, d);}\n"
+ "else if (y > 0 && m >= 0)\n"
+ "{v = new Date(y, m);}\n"
+ "else if (y > 0)\n"
+ "{v = new Date(y);}\n"
+ "}return (v && (z || o))?\n" // favour UTC offset over GMT offset if both are available
+ " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
+ " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
+ ";}";

Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
eval(code);
};

Date.formatCodeToRegex = function(character, currentGroup) {
switch (character) {
case "D":
return {g:0,
c:null,
s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
case "j":
case "d":
return {g:1,
c:"d = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{1,2})"};
case "l":
return {g:0,
c:null,
s:"(?:" + Date.dayNames.join("|") + ")"};
case "S":
return {g:0,
c:null,
s:"(?:st|nd|rd|th)"};
case "w":
return {g:0,
c:null,
s:"\\d"};
case "z":
return {g:0,
c:null,
s:"(?:\\d{1,3})"};
case "W":
return {g:0,
c:null,
s:"(?:\\d{2})"};
case "F":
return {g:1,
c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
s:"(" + Date.monthNames.join("|") + ")"};
case "M":
return {g:1,
c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
case "n":
case "m":
return {g:1,
c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
s:"(\\d{1,2})"};
case "t":
return {g:0,
c:null,
s:"\\d{1,2}"};
case "L":
return {g:0,
c:null,
s:"(?:1|0)"};
case "Y":
return {g:1,
c:"y = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{4})"};
case "y":
return {g:1,
c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
+ "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
s:"(\\d{1,2})"};
case "a":
return {g:1,
c:"if (results[" + currentGroup + "] == 'am') {\n"
+ "if (h == 12) { h = 0; }\n"
+ "} else { if (h < 12) { h += 12; }}",
s:"(am|pm)"};
case "A":
return {g:1,
c:"if (results[" + currentGroup + "] == 'AM') {\n"
+ "if (h == 12) { h = 0; }\n"
+ "} else { if (h < 12) { h += 12; }}",
s:"(AM|PM)"};
case "g":
case "G":
case "h":
case "H":
return {g:1,
c:"h = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{1,2})"};
case "i":
return {g:1,
c:"i = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{2})"};
case "s":
return {g:1,
c:"s = parseInt(results[" + currentGroup + "], 10);\n",
s:"(\\d{2})"};
case "O":
return {g:1,
c:[
"o = results[", currentGroup, "];\n",
"var sn = o.substring(0,1);\n", // get + / - sign
"var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
"var mn = o.substring(3,5) % 60;\n", // get minutes
"o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
" (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
].join(""),
s:"([+\-]\\d{4})"};
case "T":
return {g:0,
c:null,
s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
case "Z":
return {g:1,
c:"z = results[" + currentGroup + "];\n" // -43200 < UTC offset < 50400
+ "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for positive offsets
default:
return {g:0,
c:null,
s:String.escape(character)};
}
};

hope this helps.

[edit 1]
added checks for valid UTC / GMT offsets and timezone abbrev

[edit 2]
test case (based on my test PC's GMT+0800 timezone):
console.log(Date.parseDate('2007-06-13T12:19:58-0700', 'Y-m-d\\TH:i:sO')); // returns "Thu Jun 14 2007 03:19:58 GMT+0800 (Malay Peninsula Standard Time)"
console.log(Date.parseDate('2007-06-13T12:19:58-360', 'Y-m-d\\TH:i:sZ')); // returns " Wed Jun 13 2007 04:25:58 GMT+0800 (Malay Peninsula Standard Time)"
console.log(Date.parseDate('2007-06-13T12:19:58-0700-360', 'Y-m-d\\TH:i:sOZ')); // returns " Wed Jun 13 2007 04:25:58 GMT+0800 (Malay Peninsula Standard Time)"

[edit 3]
added this thread to the bug report in this thread (http://extjs.com/forum/showthread.php?p=40956#post40956)

[edit 4]
made leading '+' sign optional for UTC offsets

[edit 5]
fixed UTC offset calculation bug

[edit 6]
fixed variable leak

[edit 7]
fixed in Ext 1.1 beta 2 (http://extjs.com/deploy/ext-1.1-beta2.zip)