dojo.date.parse = function()

in tapestry-framework/src/js/dojo-0.4.3-custom-4.1.6/dojo2.js.uncompressed.js [2191:2414]


dojo.date.parse = function(/*String*/value, /*Object?*/options){
//
// summary:
//		Convert a properly formatted string to a primitive Date object,
//		using locale-specific settings.
//
// description:
//		Create a Date object from a string using a known localized pattern.
//		By default, this method parses looking for both date and time in the string.
//		Formatting patterns are chosen appropriate to the locale.  Different
//		formatting lengths may be chosen, with "full" used by default.
//		Custom patterns may be used or registered with translations using
//		the addCustomBundle method.
//		Formatting patterns are implemented using the syntax described at
//		http://www.unicode.org/reports/tr35/#Date_Format_Patterns
//
// value:
//		A string representation of a date
//
// options: object {selector: string, formatLength: string, datePattern: string, timePattern: string, locale: string, strict: boolean}
//		selector- choice of timeOnly, dateOnly, dateTime (default: dateOnly)
//		formatLength- choice of long, short, medium or full (plus any custom additions).  Defaults to 'full'
//		datePattern,timePattern- override pattern with this string
//		am,pm- override strings for am/pm in times
//		locale- override the locale used to determine formatting rules
//		strict- strict parsing, off by default
//

	options = options || {};
	var locale = dojo.hostenv.normalizeLocale(options.locale);
	var info = dojo.date._getGregorianBundle(locale);
	var formatLength = options.formatLength || 'full';
	if(!options.selector){ options.selector = 'dateOnly'; }
	var datePattern = options.datePattern || info["dateFormat-" + formatLength];
	var timePattern = options.timePattern || info["timeFormat-" + formatLength];

	var pattern;
	if(options.selector == 'dateOnly'){
		pattern = datePattern;
	}
	else if(options.selector == 'timeOnly'){
		pattern = timePattern;
	}else if(options.selector == 'dateTime'){
		pattern = datePattern + ' ' + timePattern; //TODO: use locale-specific pattern to assemble date + time
	}else{
		var msg = "dojo.date.parse: Unknown selector param passed: '" + options.selector + "'.";
		msg += " Defaulting to date pattern.";
		dojo.debug(msg);
		pattern = datePattern;
	}

	var groups = [];
	var dateREString = _processPattern(pattern, dojo.lang.curry(this, _buildDateTimeRE, groups, info, options));
	var dateRE = new RegExp("^" + dateREString + "$");

	var match = dateRE.exec(value);
	if(!match){
		return null;
	}

	var widthList = ['abbr', 'wide', 'narrow'];
	//1972 is a leap year.  We want to avoid Feb 29 rolling over into Mar 1,
	//in the cases where the year is parsed after the month and day.
	var result = new Date(1972, 0);
	var expected = {};
	for(var i=1; i<match.length; i++){
		var grp=groups[i-1];
		var l=grp.length;
		var v=match[i];
		switch(grp.charAt(0)){
			case 'y':
				if(l != 2){
					//interpret year literally, so '5' would be 5 A.D.
					result.setFullYear(v);
					expected.year = v;
				}else{
					if(v<100){
						v = Number(v);
						//choose century to apply, according to a sliding window
						//of 80 years before and 20 years after present year
						var year = '' + new Date().getFullYear();
						var century = year.substring(0, 2) * 100;
						var yearPart = Number(year.substring(2, 4));
						var cutoff = Math.min(yearPart + 20, 99);
						var num = (v < cutoff) ? century + v : century - 100 + v;
						result.setFullYear(num);
						expected.year = num;
					}else{
						//we expected 2 digits and got more...
						if(options.strict){
							return null;
						}
						//interpret literally, so '150' would be 150 A.D.
						//also tolerate '1950', if 'yyyy' input passed to 'yy' format
						result.setFullYear(v);
						expected.year = v;
					}
				}
				break;
			case 'M':
				if (l>2) {
					if(!options.strict){
						//Tolerate abbreviating period in month part
						v = v.replace(/\./g,'');
						//Case-insensitive
						v = v.toLowerCase();
					}
					var months = info['months-format-' + widthList[l-3]].concat();
					for (var j=0; j<months.length; j++){
						if(!options.strict){
							//Case-insensitive
							months[j] = months[j].toLowerCase();
						}
						if(v == months[j]){
							result.setMonth(j);
							expected.month = j;
							break;
						}
					}
					if(j==months.length){
						dojo.debug("dojo.date.parse: Could not parse month name: '" + v + "'.");
						return null;
					}
				}else{
					result.setMonth(v-1);
					expected.month = v-1;
				}
				break;
			case 'E':
			case 'e':
				if(!options.strict){
					//Case-insensitive
					v = v.toLowerCase();
				}
				var days = info['days-format-' + widthList[l-3]].concat();
				for (var j=0; j<days.length; j++){
					if(!options.strict){
						//Case-insensitive
						days[j] = days[j].toLowerCase();
					}
					if(v == days[j]){
						//TODO: not sure what to actually do with this input,
						//in terms of setting something on the Date obj...?
						//without more context, can't affect the actual date
						break;
					}
				}
				if(j==days.length){
					dojo.debug("dojo.date.parse: Could not parse weekday name: '" + v + "'.");
					return null;
				}
				break;	
			case 'd':
				result.setDate(v);
				expected.date = v;
				break;
			case 'a': //am/pm
				var am = options.am || info.am;
				var pm = options.pm || info.pm;
				if(!options.strict){
					v = v.replace(/\./g,'').toLowerCase();
					am = am.replace(/\./g,'').toLowerCase();
					pm = pm.replace(/\./g,'').toLowerCase();
				}
				if(options.strict && v != am && v != pm){
					dojo.debug("dojo.date.parse: Could not parse am/pm part.");
					return null;
				}
				var hours = result.getHours();
				if(v == pm && hours < 12){
					result.setHours(hours + 12); //e.g., 3pm -> 15
				} else if(v == am && hours == 12){
					result.setHours(0); //12am -> 0
				}
				break;
			case 'K': //hour (1-24)
				if(v==24){v=0;}
				// fallthrough...
			case 'h': //hour (1-12)
			case 'H': //hour (0-23)
			case 'k': //hour (0-11)
				//TODO: strict bounds checking, padding
				if(v>23){
					dojo.debug("dojo.date.parse: Illegal hours value");
					return null;
				}

				//in the 12-hour case, adjusting for am/pm requires the 'a' part
				//which for now we will assume always comes after the 'h' part
				result.setHours(v);
				break;
			case 'm': //minutes
				result.setMinutes(v);
				break;
			case 's': //seconds
				result.setSeconds(v);
				break;
			case 'S': //milliseconds
				result.setMilliseconds(v);
				break;
			default:
				dojo.unimplemented("dojo.date.parse: unsupported pattern char=" + grp.charAt(0));
		}
	}

	//validate parse date fields versus input date fields
	if(expected.year && result.getFullYear() != expected.year){
		dojo.debug("Parsed year: '" + result.getFullYear() + "' did not match input year: '" + expected.year + "'.");
		return null;
	}
	if(expected.month && result.getMonth() != expected.month){
		dojo.debug("Parsed month: '" + result.getMonth() + "' did not match input month: '" + expected.month + "'.");
		return null;
	}
	if(expected.date && result.getDate() != expected.date){
		dojo.debug("Parsed day of month: '" + result.getDate() + "' did not match input day of month: '" + expected.date + "'.");
		return null;
	}

	//TODO: implement a getWeekday() method in order to test 
	//validity of input strings containing 'EEE' or 'EEEE'...

	return result; /*Date*/
};