A better way of entering dates
The CreativityGoblin dropped in on me today, and as a result I’ve been tackling the challenge of entering dates in to a web application. In the past, I’ve used DHTML calendar widgets for this purpose (my favourite is Mishoo’s highly configurable, standards compliant JS Calendar) but while widgets like this have a great deal of “wow” factor I’m not convinced that they are the best entry mechanism when it comes to raw user speed. Today’s experiment was partially inspired by PHP’s strtotime function, which accepts a string in a wide variety of formats and converts it in to a time.
I wanted the same thing but in Javascript, as interfaces like this are best carried out on the client without needing a round trip to the server to check any entered data. Here’s a demo of what I came up with (javascript code here). It accepts a number of different input formats and converts them to a standardised mm/dd/yyyy (American style dates because it’s for use in an American piece of software) when you move the focus away from the box. Importantly, the date is shown in two places: in the input box itself and in “Mon Oct 06 2003” format as text below the date entry field. This second display serves two purposes. Firstly, by displaying the date in an unambiguous format mistakes are easier to spot (especially important considering the American date format used in the main input). Secondly, it provides a useful place to display error messages should the script fail to parse some input.
The Javascript itself was quite fun to write, and uses a number of interesting idioms I’ve picked up over the past year. It adds a ’filter’ method to Javascript’s Array class to better support functional programming (in fact I use it to match partially entered month and weekday names) and an ’indexOf’ method identical to the one provided by the String class. The majority of the work is done by a data structure called dateParsePatterns, which defines a set of pairs of regular expressions and handler functions. The regular expressions match a n input style and extract any useful information; the handler functions then create a Date object from the extracted information and return it to the caller.
Finally, the code uses an error handling technique I picked up on Ward’s Wiki called the SamuraiPrinciple, which states you should either complete your contract and return a valid result, or throw an exception
. This is used by the handlers and the main date parsing function itself, with thrown exceptions only caught by the magicDate function attached directly to the onblur event of the input box.
There are still quite a few improvements that could be made to the code: more input styles (easily added by extending the main data structure), better planned functions and maybe a clean up to move more of the code out of the root Javascript namespace. For the moment though it serves my purpose just fine.
Update: It wasn’t the Creativity Goblin after all—it was the goblin of someone elses half remembered idea. It turns out my friend Andy wrote something very similar to this back in July. Thinking back, I can remember seeing it as well. Despite not being original it’s still a very useful piece of code.
Would it be possible to attach a license to the script ?
And random notes:
But it's a great idea.
Frederic Peters - 6th October 2003 21:09 - #
Josh - 6th October 2003 21:10 - #
Michael Z. - 6th October 2003 21:29 - #
Frederic that's not a bug, it's a feature :) It uses American style dates so 16/6/1979 means "the 6th day of the 16th month" - although to be honest it should probably throw an error rather than roll the months on a year and 4 months. 2003-10-06 isn't supported but it could be very easily by adding a new item to the dateParsePatterns array. In fact, the code would look something like this:
{re: /(\d{4})-(\d{2})-(\d{2})/,handler: function(bits) {var d = new Date();d.setYear(bits[1]);d.setDate(bits[3]);d.setMonth(parseInt(bits[2]) - 1);return d;}},(OK, I admit it, it sucks not having a pre tag)
Simon Willison - 6th October 2003 21:36 - #
Simon Willison - 6th October 2003 21:47 - #
Nice! I love the
dateParsePatternspiece -- that's a beautiful way of handling it.Adrian Holovaty - 6th October 2003 21:53 - #
Suggestion: It'd be cool if it detected whether \d{2}/\d{2}/\d\{4} was a mm/dd/yyyy or dd/mm/yyyy and handled it appropriately. You could only do that when the dd was unambiguously not a month (i.e., greater than 12), but it could be helpful.
Adrian Holovaty - 6th October 2003 21:59 - #
What a fantastic bit of javascript, I too have generally used a calendar type control in the past but this has really opened my eyes to this alternative.
One thing you might want to look at is leap years as different formats of entering the date yield different resulting dates (including the day of the week), '29 feb 2004' is converted to '03/01/2004', however '02/29/2004' seems to work correctly
Chris Alcock - 6th October 2003 22:13 - #
JD - 6th October 2003 22:32 - #
Damn,
I just read that newlines are not converted to breaks! Any particular reason for this??
JD
JD - 6th October 2003 22:34 - #
JD - yup, it's because I'm an evil XHTML facist. Some day I plan to revamp the comment system to be slightly more forgiving.
As for telling the user, this interface is designed for private systems that a group of people will be using on a regular basis. As such, makign an interface obvious to a first time user becomes less important than allowing an experienced user to enter data quickly and efficiently.
Simon Willison - 6th October 2003 23:08 - #
Scott Johnson - 6th October 2003 23:16 - #
rick - 7th October 2003 00:35 - #
Simon Willison - 7th October 2003 00:53 - #
Eric Scheid - 7th October 2003 07:14 - #
Simon Willison - 7th October 2003 07:42 - #
dvd - 7th October 2003 14:23 - #
Thanks for bringing this up, Simon. I'd completely forgotten about doing that. Anyway, you're as much the Creativity Goblin as I am - just been having a play with my original.
dvd - the deed is done!
For anyone who cares, I've got a demo of the results (script is here), but when I tried it originally it had the wonderful side effect of killing various browsers, so it's not my fault if your browser dies!
Andrew - 7th October 2003 20:38 - #
manmoth - 10th October 2003 16:49 - #
manmoth - 10th October 2003 16:53 - #
Simon Willison - 10th October 2003 17:22 - #
manmoth - 10th October 2003 22:15 - #
Wouldn't it just be a matter of datestring = datestring.replace(' of ', ' ') ?
Peter Bengtsson - 16th October 2003 14:50 - #
Tom Z - 17th October 2003 15:03 - #
Peter; that could be supported by modifying the regular expression used for identifying '12th October 2003' strings. Here's the updated regexp:
Simon Willison - 17th October 2003 15:10 - #
In the handler for "// 4th Jan 2003" Suppose you have the following
var d = new Date(); // d=2003-11-29
d.setYear(2003);
d.setDate(31); // d now = 2003-11-31, which doesn't exist!!
d.setDate(12); // d now = 2003-12-01, when you'd expect 2003-12-31
When the day 31 is applied to a November date, some other things change because as the date object is being modified it changes.
The solution is to do this instead
var d = new Date(2003, 11, 31);This solved my problem. Initial value of the input was
31 December 2003but as soon as magicDate had done its work, it changed to1 December 2003.Peter Bengtsson - 29th November 2003 17:20 - #
Stuey - 3rd December 2003 22:22 - #
Simon Willison - 3rd December 2003 22:53 - #
I wrote something similar for a client last year. I wanted to be able to handle people typing US date format where the month was unambiguously a month (as I'm in the UK, we wanted the rest of the world's format as default ;o)
I found this worked nicely:
// JavaScript's Date.parse() requires MDY, with a separator of / or - // Let's see if we can move things around to conform with this. var re = /(\d+)[\.\-\/\s]+(\d+)[\.\-\/\s]+(\d+)/; if (theValue.match(re)) { var part1 = RegExp.$1; var part2 = RegExp.$2; var part3 = RegExp.$3; if (part1 > 2000 && part2 <= 12 && part2 >= 1 && part3 <= 31 && part3 >= 1) { // Good grief, it's ISO-8601 format! tmpDate = new Date(part2 + '/' + part3 + '/' + part1); } else { if (part3 < 100) part3 = parseInt(part3, 10) + 2000; if (part2 > 12) { // Found a definite MDY date. tmpDate = new Date(part1 + '/' + part2 + '/' + part3); } else if(part1 > 12) { // Found a definite DMY date. tmpDate = new Date(part2 + '/' + part1 + '/' + part3); } else { // This date matches the regular date format, but we don't // know if it's DMY or MDY (or something more perverse). // We're gonna assume it's DMY, being British 'n' all. tmpDate = new Date(part2 + '/' + part1 + '/' + part3); } // if (part2 > 12) ... } // if (part1 > 2000 ...) if (debugging) alert("Extracted date as " + tmpDate.toString()); } else { // We can't parse that date, so we'll set it to NaN. tmpDate = NaN; } // if (theValue.match(re))I postprocessed to handle the
NaNvalue, but you don't need to see that. And please excuse the anal commenting... ;o)Owen Blacker - 23rd January 2004 12:30 - #
jhfjhf - 20th February 2004 01:17 - #
Kevin Guske - 14th April 2004 18:40 - #
Kevin Guske - 14th April 2004 19:07 - #
Kevin Guske - 14th April 2004 19:21 - #
// mm/dd/yyyy (American style)
{ re: /(\d{1,2})\/(\d{1,2})\/(\d{4})/,
handler: function(bits) {
var d = new Date();
d.setFullYear(bits[3]);
d.setMonth(parseInt(bits[1], 10) - 1); // Because months indexed from 0
d.setDate(parseInt(bits[2], 10));
return d;
}
},
Kevin Guske - 14th April 2004 19:28 - #
nizam - 10th June 2004 04:24 - #
aliya - 18th June 2004 21:53 - #
Joe - 22nd June 2004 22:21 - #
This is a fabulous idea! I'll be using this in a a project I'm working on right now. While playing with the demo, I found myself typing things like "a week from next tuesday." Is that a reasonable thing to expect the script to parse? I don't know. Something to think about...
Thanks for your contribution!
--johnt
John Tangney - 8th September 2004 17:04 - #
I know it might screw around with impartial parsing, but I always feel an onnchange event is better than an onblur, as people mightn't necessarily blur before submitting.
Perhaps to stop parsing for every letter typed a timeout could be imposed. So if a letter isn't typed within 0.5 seconds -- or some other period -- it attempts to parse the field.
Cameron Adams - 22nd September 2004 02:12 - #
Thanks for the script. I implemented the last tueday functionality and added some other stuff like short date entries. See the full script below. Simon, feel free to use it however you like.
// Date Box Control // // based on: // 'Magic' date parsing, by Simon Willison (6th October 2003) // http://simon.incutio.com/archive/2003/10/06/better DateInput // // Notes // To create a date box control, call the SetupDateBoxControl function. // It should be passed an input element with type of text. // This will first create a div after the input box. // Then it will associate the div with the input element. // The div will use the css classes: DateBoxControlMsg, DateBoxControlErrorMsg. // Then the div is associated with the input element. // Then the contents are validated so the div will get populated initially. // The onchange event of the input element will invoke the validation function. // The validation function populates the div. // If a successfully parsed date, the div gets a nicely formatted date. // If an unsuccessfully parse date, the div gets an error message. // // History // 02/03/2005 - WSR : modified for use as datebox control // hooks functionality up to given textbox function SetupDateBoxControl( ctlDateBox ) { // if a valid object was given if (ctlDateBox) { // add div after control for messages var divMessage = document.createElement('div'); divMessage.className = 'DateBoxControlMsg'; // if there is a next sibling if (ctlDateBox.nextSibling) { // insert before next sibling ctlDateBox.parentNode.insertBefore( divMessage, ctlDateBox.nextSibling ); } // if there is not a next sibling else { // append child to parent ctlDateBox.parentNode.appendChild( divMessage ); } // link message div to textbox for easy script access ctlDateBox.message = divMessage; // validate current contents DateBoxControl_Validate( ctlDateBox ); // hook up event handlers ctlDateBox.onchange = function () { DateBoxControl_Validate(this); }; } } // add indexOf function to Array type // finds the index of the first occurence of item in the array, or -1 if not found Array.prototype.indexOf = function(item) { for (var i = 0; i < this.length; i++) { if (this[i] == item) { return i; } } return -1; }; // add filter function to Array type // returns an array of items judged true by the passed in test function Array.prototype.filter = function(test) { var matches = []; for (var i = 0; i < this.length; i++) { if (test(this[i])) { matches[matches.length] = this[i]; } } return matches; }; // add right function to String type // returns the rightmost x characters String.prototype.right = function( intLength ) { if (intLength >= this.length) return this; else return this.substr( this.length - intLength, intLength ); }; // add trim function to String type // trims leading and trailing whitespace String.prototype.trim = function() { return this.replace(/^\s+|\s+$/, ''); }; // arrays for month and weekday names var monthNames = "January February March April May June July August September October November December".split(" "); var weekdayNames = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "); /* Takes a string, returns the index of the month matching that string, throws an error if 0 or more than 1 matches */ function parseMonth(month) { var matches = monthNames.filter(function(item) { return new RegExp("^" + month, "i").test(item); }); if (matches.length == 0) { throw new Error("Invalid month string"); } if (matches.length < 1) { throw new Error("Ambiguous month"); } return monthNames.indexOf(matches[0]); } /* Same as parseMonth but for days of the week */ function parseWeekday(weekday) { var matches = weekdayNames.filter(function(item) { return new RegExp("^" + weekday, "i").test(item); }); if (matches.length == 0) { throw new Error("Invalid day string"); } if (matches.length < 1) { throw new Error("Ambiguous weekday"); } return weekdayNames.indexOf(matches[0]); } function DateInRange( yyyy, mm, dd ) { // if month out of range if ( mm < 0 || mm > 11 ) throw new Error('Invalid month value. Valid months values are 1 to 12'); // get last day in month var d = (11 == mm) ? new Date(yyyy + 1, 0, 0) : new Date(yyyy, mm + 1, 0); // if date out of range if ( dd < 1 || dd > d.getDate() ) throw new Error('Invalid date value. Valid date values for ' + monthNames[mm] + ' are 1 to ' + d.getDate().toString()); return true; } /* Array of objects, each has 're', a regular expression and 'handler', a function for creating a date from something that matches the regular expression. Handlers may throw errors if string is unparseable. */ var dateParsePatterns = [ // Today { re: /^today/i, handler: function() { return new Date(); } }, // Tomorrow { re: /^tomorrow/i, handler: function() { var d = new Date(); d.setDate(d.getDate() + 1); return d; } }, // Yesterday { re: /^yesterday/i, handler: function() { var d = new Date(); d.setDate(d.getDate() - 1); return d; } }, // 4th { re: /^(\d{1,2})(st|nd|rd|th)?$/i, handler: function(bits) { var d = new Date(); var yyyy = d.getFullYear(); var dd = parseInt(bits[1], 10); var mm = d.getMonth(); if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, // 4th Jan { re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+)$/i, handler: function(bits) { var d = new Date(); var yyyy = d.getFullYear(); var dd = parseInt(bits[1], 10); var mm = parseMonth(bits[2]); if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, // 4th Jan 2003 { re: /^(\d{1,2})(?:st|nd|rd|th)? (\w+),? (\d{4})$/i, handler: function(bits) { var yyyy = parseInt(bits[3], 10); var dd = parseInt(bits[1], 10); var mm = parseMonth(bits[2]); if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, // Jan 4th { re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?$/i, handler: function(bits) { var d = new Date(); var yyyy = d.getFullYear(); var dd = parseInt(bits[2], 10); var mm = parseMonth(bits[1]); if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, // Jan 4th 2003 { re: /^(\w+) (\d{1,2})(?:st|nd|rd|th)?,? (\d{4})$/i, handler: function(bits) { var yyyy = parseInt(bits[3], 10); var dd = parseInt(bits[2], 10); var mm = parseMonth(bits[1]); if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, // next Tuesday - this is suspect due to weird meaning of "next" { re: /^next (\w+)$/i, handler: function(bits) { var d = new Date(); var day = d.getDay(); var newDay = parseWeekday(bits[1]); var addDays = newDay - day; if (newDay <= day) { addDays += 7; } d.setDate(d.getDate() + addDays); return d; } }, // last Tuesday { re: /^last (\w+)$/i, handler: function(bits) { var d = new Date(); var wd = d.getDay(); var nwd = parseWeekday(bits[1]); // determine the number of days to subtract to get last weekday var addDays = (-1 * (wd + 7 - nwd)) % 7; // above calculate 0 if weekdays are the same so we have to change this to 7 if (0 == addDays) addDays = -7; // adjust date and return d.setDate(d.getDate() + addDays); return d; } }, // mm/dd/yyyy (American style) { re: /(\d{1,2})\/(\d{1,2})\/(\d{4})/, handler: function(bits) { var yyyy = parseInt(bits[3], 10); var dd = parseInt(bits[2], 10); var mm = parseInt(bits[1], 10) - 1; if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, // mm/dd/yy (American style) short year { re: /(\d{1,2})\/(\d{1,2})\/(\d{1,2})/, handler: function(bits) { var d = new Date(); var yyyy = d.getFullYear() - (d.getFullYear() % 100) + parseInt(bits[3], 10); var dd = parseInt(bits[2], 10); var mm = parseInt(bits[1], 10) - 1; if ( DateInRange(yyyy, mm, dd) ) return new Date(yyyy, mm, dd); } }, // mm/dd (American style) omitted year { re: /(\d{1,2})\/(\d{1,2})/, handler: function(bits) { var d = new Date(); var yyyy = d.getFullYear(); var dd = parseInt(bits[2], 10); var mm = parseInt(bits[1], 10) - 1; if ( DateInRange(yyyy, mm, dd) ) return new Date(yyyy, mm, dd); } }, // yyyy-mm-dd (ISO style) { re: /(\d{4})-(\d{1,2})-(\d{1,2})/, handler: function(bits) { var yyyy = parseInt(bits[1], 10); var dd = parseInt(bits[3], 10); var mm = parseInt(bits[2], 10) - 1; if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, // yy-mm-dd (ISO style) short year { re: /(\d{1,2})-(\d{1,2})-(\d{1,2})/, handler: function(bits) { var d = new Date(); var yyyy = d.getFullYear() - (d.getFullYear() % 100) + parseInt(bits[1], 10); var dd = parseInt(bits[3], 10); var mm = parseInt(bits[2], 10) - 1; if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, // mm-dd (ISO style) omitted year { re: /(\d{1,2})-(\d{1,2})/, handler: function(bits) { var d = new Date(); var yyyy = d.getFullYear(); var dd = parseInt(bits[2], 10); var mm = parseInt(bits[1], 10) - 1; if ( DateInRange( yyyy, mm, dd ) ) return new Date(yyyy, mm, dd); } }, ]; // parses date string input function parseDateString( strDateInput ) { // cycle through date parse patterns for (var i = 0; i < dateParsePatterns.length; i++) { // get regular expression for this pattern var re = dateParsePatterns[i].re; // get handler function for this pattern var handler = dateParsePatterns[i].handler; // parse input using regular expression var bits = re.exec(strDateInput); // if there was a match if (bits) { // return the result of the handler function (which constitutes bits into a date) return handler(bits); } } // if no pattern matched - throw exception throw new Error("Invalid date string"); } // validates the input from datebox as a date function DateBoxControl_Validate( ctlDateBox ) { try { // parse input to get date (error is raised if it can't be parsed) var dtValue = parseDateString(ctlDateBox.value.trim()); // assign date in mm/dd/yyyy format to textbox ctlDateBox.value = ('0' + (dtValue.getMonth() + 1).toString()).right(2) + '/' + ('0' + dtValue.getDate().toString()).right(2) + '/' + dtValue.getFullYear().toString(); // add more formal date to message div associated with textbox if (!ctlDateBox.message.firstChild) ctlDateBox.message.appendChild(document.createText Node(dtValue.toDateString())); else ctlDateBox.message.firstChild.nodeValue = dtValue.toDateString(); // swith class name back to default so styling is changed ctlDateBox.message.className = 'DateBoxControlMsg'; } catch (e) { // use error message from exception var strMessage = e.message; // give a nicer message to built-in javascript exception message if (strMessage.indexOf('is null or not an object') < -1) strMessage = 'Invalid date string'; // add error message to message div associated with textbox if (!ctlDateBox.message.firstChild) ctlDateBox.message.appendChild(document.createText Node(strMessage)); else ctlDateBox.message.firstChild.nodeValue = strMessage; // switch class name to error so styling is changed ctlDateBox.message.className = 'DateBoxControlErrorMsg'; } }Will Rickards - 4th February 2005 15:39 - #
Tom Smith - 18th April 2005 13:30 - #
Simon Willison - 18th April 2005 14:47 - #
Tom Smith - 19th April 2005 09:20 - #
Darryl Havlicek - 25th April 2005 17:23 - #
paul vudmaska - 27th April 2005 02:21 - #
ctran - 30th April 2005 18:51 - #
Nick Johnson - 29th July 2005 22:52 - #
It could work as:
User clicks in or tabs into input box
Calendar appears (no button needed)
User begins typing something like "Wed"
On each key press the dateParsePattern() could fire, and if it returns something valid it could feed that to "The Coolest DHTML Calendar". If the user leaves the input box at any point, the most recent date displayed in the control is entered into the field.
No need to press enter, onblur() becomes a sensible event to the user, user gets context including answers like "What the heck is today anyway?" and "I'm thinking the 8th but is that a Wednesday?", etc, etc.
If this were open source it would be a nice derivative open source project to assemble from the 2... .
Chris Moschini - 8th August 2005 15:59 - #
Barry Staes - 17th September 2005 00:02 - #
Seth Thornberry - 19th September 2005 22:07 - #
var d = new Date();
d.setFullYear(1965);
d.setMonth(1);
d.setDate(23);
document.write(d);
this is what I get:
"Tue Mar 23 11:44:06 UTC+0800 1965"
it seem that setMonth() works fine for for all other months except february, namely the numbers 1, 13, 25 etc.
Any idea?
SongPerk Sem
songperk sem - 30th September 2005 04:52 - #
function handleKeyDown(input,e) {
var key = (window.Event) ? e.which : e.keyCode;
if ("" == input.value)
{
var d = new Date();
input.value = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
}
else switch(key)
{
case 38: // up
var d = parseDateString(input.value);
d.setDate(d.getDate() + 1);
input.value = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
break;
case 40: // down
var d = parseDateString(input.value);
d.setDate(d.getDate() - 1);
input.value = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
break;
}
}
jlampa - 6th October 2005 22:51 - #
bigD - 3rd November 2005 18:38 - #
hullio - 4th November 2005 18:28 - #
Graham Butcher - 21st December 2005 16:37 - #
I have just completed developing "the next generation of better way of entering dates" which includes the infamous JSCalendar DHTML popup calendar.
This combines all the various comments on this post including many of the fixes and patches, and feature requests people have mentioned above.
Come check it out the full demo at http://datebox.inimit.com.
All suggestions are welcome! Please email them to nshb@inimit.com
Nathaniel Brown - 11th January 2006 16:35 - #
I've used your program and Nathaniel Brown's adapted one, however, it seems that trying to select 31st Jan (now it is the month of Feb only 28 days) does not work correctly :(
I'm currently trailing through the code to try and find the fix ;) I'm doing this as I find this calendar GREAT!
Thanks Dominic
Dominic O'Sullivan - 1st February 2006 18:02 - #
Finally found it ;o)
All that is needed is to reorder the calls in getDateObj to setYear, setMonth and setDate and voila it works correctly:
There are also several other places in var parseDatePatterns that have this order incorrect too ;o)
N.B. It makes sense when you think about it in hindsight, we were trying to change the date first so we were trying to change it to 31st Feb!
Hope you can update your download file ;o)
Dominic O'Sullivan - 1st February 2006 18:25 - #
Robert Clancy - 28th February 2006 00:22 - #
Robert,
Glad you asked, try Date input and calendar popup.
I've applied Dominic O'Sullivan's fix as well as modified last and added this, next, first, second, third, fourth and fifth day to the parser. You can now enter a date in a different order (mdy or dmy) depending on a global format string.
Tanny O'Haley - 3rd March 2006 23:06 - #
Raaj - 8th March 2006 23:11 - #
OK, there seems to be a further issue with what I posted in that Feb cannot be selected when the current date is 29th, 30th or 31st. I fixed this by setting the date to the 1st of the month at the start of the function:
Dominic O'Sullivan - 30th March 2006 10:36 - #
Is there any objection to me (or anyone else) submitting code that uses these techniques and techniques based on these ideas to the dojo toolkit project (www.dojotoolkit.org)?
RickRick Morrison - 27th April 2006 19:19 - #
Simon Willison - 28th April 2006 12:51 - #
Nathaniel Brown - 13th May 2006 09:11 - #
Shaun Williams - 29th May 2006 12:59 - #
toArray.prototype.indexOf = function(item) {
And my problems when away. Is the former option really that much better?arrayIndexOf = function(arr, item) {Michael - 14th June 2006 06:25 - #
Your code suffers from a bug in the way the date object is created. Annoyingly, this bug only manifests itself on certain days of the month. Anyway, the solution is to update your getDateObj() function as follows:
function getDateObj(yyyy, mm, dd) { var obj = new Date(); // set year, then month, then date or the date object you get back won't be what you expect. obj.setYear(yyyy); obj.setMonth(mm); obj.setDate(dd); return obj; }Jeff Howden - 10th July 2006 23:47 - #
Vijay Santhanam - 24th August 2006 06:14 - #
Pozycjonowanie - 29th October 2006 12:30 - #