/**
* JTSage-DateBox
* @fileOverview Parse dates
* @author J.T.Sage <jtsage+datebox@gmail.com>
* @author {@link https://github.com/jtsage/jtsage-datebox/contributors|GitHub Contributors}
* @license {@link https://github.com/jtsage/jtsage-datebox/blob/master/LICENSE.txt|MIT}
* @version 5.2.0
*
*/
// Custom Parser Definitions, single String argument provided.
/**
* Custom date parsers
*
* These recive the input value, and should return a date, or whatever the mode is
* expecting to be in the usual date object. It is possible for it to be another type,
* although most of the build in functions would not be useful on it any longer.
*
* Custom parsers need to be named for the mode they run on.
*
* @type {Object}
* @namespace JTSageDateBox._parser
*/
JTSageDateBox._parser = {};
/**
* Sample custom parser prototype
*
* @param {string} str Input value
* @return {*} Date object ideally, but whatever the mode file is expecting will work
* @memberOf JTSageDateBox._parser
*/
JTSageDateBox._parser.default = function ( str ) { return str; };
/**
* Attempt to parse a date string. Format is pulled from {@link JTSageDateBox.__fmt}
*
* @param {string} Date string to parse
* @param {boolean} When true, return an array instead with the status of the parse as arr[1]
* @return {object} JavaScript Date Object
*/
JTSageDateBox._makeDate = function ( str, extd ) {
// Date Parser
var i, exp_temp, exp_format, grbg,
w = this,
o = this.options,
defVal = this.options.defaultValue,
adv = w.__fmt(),
exp_input = null,
exp_names = [],
faildate = false,
date = new w._date(),
d = {
year : -1,
mont : -1,
date : -1,
hour : -1,
mins : -1,
secs : -1,
week : false,
wtyp : 4,
wday : false,
yday : false,
meri : 0
};
// Set a default, no extended data
if ( typeof extd === "undefined" ) { extd = false; }
// Convert indic numers t those we can deal with, also handle empty string.
str = ( typeof str === "undefined" ) ? "" : (
( w.__( "useArabicIndic" ) === true ) ?
w._dRep( str, -1 ) :
str
).trim();
// Do nothing if no mode loaded
if ( typeof o.mode === "undefined" ) { return date; }
// Run custom parser instead if it exists
if ( typeof w._parser[ o.mode ] !== "undefined" ) {
return w._parser[ o.mode ].call( w, str );
}
// Deal with duration mode.
if ( o.mode === "durationbox" || o.mode === "durationflipbox" ) {
adv = adv.replace(/%D([a-z])/gi, function( match, oper ) {
switch ( oper ) {
case "d":
case "l":
case "M":
case "S": return "(" + match + "|[0-9]+)";
default: return ".+?";
}
});
adv = new RegExp( "^" + adv + "$" );
exp_input = adv.exec(str);
exp_format = adv.exec(w.__fmt());
if ( exp_input === null || exp_input.length !== exp_format.length ) {
if ( typeof defVal === "number" && defVal > 0 ) {
// defaultValue is an integer
return new w._date(
( w.initDate.getEpoch() + parseInt( defVal,10 ) ) * 1000
);
}
// No default, use ZERO.
return new w._date( w.initDate.getTime() );
}
exp_temp = w.initDate.getEpoch();
for ( i=1; i<exp_input.length; i++ ) {
grbg = parseInt( exp_input[i], 10);
if ( exp_format[i].match( /^%Dd$/i ) ) {
exp_temp = exp_temp + ( grbg * 86400 );
}
if ( exp_format[i].match( /^%Dl$/i ) ) {
exp_temp = exp_temp + ( grbg * 3600 );
}
if ( exp_format[i].match( /^%DM$/i ) ) {
exp_temp = exp_temp + ( grbg * 60 );
}
if ( exp_format[i].match( /^%DS$/i ) ) {
exp_temp = exp_temp + ( grbg );
}
}
return new w._date( exp_temp * 1000 );
}
// JSON style dates are simple. Shortcut them
if ( adv === "%J" ) {
date = new w._date(str);
if ( isNaN(date.getDate()) ) { date = new w._date(); }
return date;
}
// Try to read it back in. We attempt to use the most granular option where possible
// as text options particularly can be unreliable. Some bits, like day name, we can
// hopefully just ignore.
adv = adv.replace( /%(0|-)*([a-z])/gi, function( match, pad, oper ) {
exp_names.push( oper );
switch ( oper ) {
case "p" :
case "P" :
case "b" :
case "B" : return "(" + match + "|.+?)";
case "H" :
case "k" :
case "I" :
case "l" :
case "m" :
case "M" :
case "S" :
case "V" :
case "U" :
case "u" :
case "W" :
case "d" :
return "(" + match + "|[0-9]{" +
(( pad === "-" ) ? "1," : "" ) + "2})";
case "j" : return "(" + match + "|[0-9]{3})";
case "s" : return "(" + match + "|[0-9]+)";
case "g" :
case "y" : return "(" + match + "|[0-9]{2})";
case "E" :
case "G" :
case "Y" : return "(" + match + "|[0-9]{1,4})";
default : exp_names.pop(); return ".+?";
}
});
adv = new RegExp( "^" + adv + "$" );
exp_input = adv.exec(str);
exp_format = adv.exec(w.__fmt());
if ( exp_input === null || exp_input.length !== exp_format.length ) {
if ( str !== "" ) { faildate = true; }
if ( defVal !== false && defVal !== "" ) {
switch ( typeof defVal ) {
case "object":
if ( typeof defVal.getDay === "function" ) {
// Default date import. Need to class it up here for #456
date = defVal;
} else {
if ( defVal.length === 3 ) {
date = w._pa(
defVal,
( o.mode.substr(0,4) === "time" ? date : false )
);
}
}
break;
case "number":
date = new w._date( defVal * 1000 ); break;
case "string":
if ( defVal.substr(0,1) === "+" ) {
date = new w._date().adj(5, parseInt(defVal.substr(1),10) );
} else if ( defVal.substr(0,1) === "-" ) {
date = new w._date().adj(5, -1 * parseInt(defVal.substr(1),10) );
} else {
if ( o.mode.substr(0,4) === "time" ) {
exp_temp = Object.assign([0,0,0], defVal.split(":",3));
date = w._pa( exp_temp, date );
} else {
exp_temp = Object.assign([0,0,0], defVal.split("-",3));
exp_temp[1]--;
date = w._pa( exp_temp, false );
}
} break;
}
}
if ( isNaN(date.getDate()) ) { date = new w._date(); }
} else {
for ( i=1; i<exp_input.length; i++ ) {
grbg = parseInt( exp_input[i], 10);
switch ( exp_names[i-1] ) {
case "s" : return new w._date( parseInt( exp_input[i], 10 ) * 1000 );
case "Y" :
case "G" : d.year = grbg; break;
case "E" : d.year = grbg - 543; break;
case "y" :
case "g" :
if ( o.afterToday || grbg < o.twoDigitYearCutoff ) {
d.year = 2000 + grbg;
} else {
d.year = 1900 + grbg;
} break;
case "m" : d.mont = grbg - 1; break;
case "d" : d.date = grbg; break;
case "H" :
case "k" :
case "I" :
case "l" : d.hour = grbg; break;
case "M" : d.mins = grbg; break;
case "S" : d.secs = grbg; break;
case "u" : d.wday = grbg - 1; break;
case "w" : d.wday = grbg; break;
case "j" : d.yday = grbg; break;
case "V" : d.week = grbg; d.wtyp = 4; break;
case "U" : d.week = grbg; d.wtyp = 0; break;
case "W" : d.week = grbg; d.wtyp = 1; break;
case "p" :
case "P" :
grbg = new RegExp("^" + exp_input[i] + "$", "i");
d.meri = ( grbg.test( w.__( "meridiem" )[0] ) ? -1 : 1 );
break;
case "b" :
exp_temp = w.__( "monthsOfYearShort" ).indexOf( exp_input[i] );
if ( exp_temp > -1 ) { d.mont = exp_temp; }
break;
case "B" :
exp_temp = w.__( "monthsOfYear" ).indexOf( exp_input[i] );
if ( exp_temp > -1 ) { d.mont = exp_temp; }
break;
}
}
if ( d.meri !== 0 ) {
if ( d.meri === -1 && d.hour === 12 ) { d.hour = 0; }
if ( d.meri === 1 && d.hour !== 12 ) { d.hour = d.hour + 12; }
}
date = new w._date(
w._n( d.year, 0 ),
w._n( d.mont, 0 ),
w._n( d.date, 1 ),
w._n( d.hour, 0 ),
w._n( d.mins, 0 ),
w._n( d.secs, 0 ),
0
);
if ( d.year < 100 && d.year !== -1 ) { date.setFullYear(d.year); }
if ( ( d.mont > -1 && d.date > -1 ) ||
( d.hour > -1 && d.mins > -1 && d.secs > -1 ) ) {
if ( extd === true ) { return [date, faildate]; } else { return date; }
}
if ( d.week !== false ) {
date.setDWeek( d.wtyp, d.week );
if ( d.date > -1 ) { date.setDate( d.date ); }
}
if ( d.yday !== false ) {
date.setD( 1, 0 ).setD( 2, 1 ).adj( 2, ( d.yday - 1 ) );
}
if ( d.wday !== false ) {
date.adj( 2 , ( d.wday - date.getDay() ) );
}
}
if ( extd === true ) {
return [date, faildate];
} else {
return date;
}
};