Skip to content

Commit e0cdb18

Browse files
Merge pull request trentrichardson#332 from aparshin/parseDateTime
Add $.datepicker.parseDateTime(), $.datepicker.parseTime() functions
2 parents a446965 + 0e00e8b commit e0cdb18

File tree

1 file changed

+187
-120
lines changed

1 file changed

+187
-120
lines changed

jquery-ui-timepicker-addon.js

+187-120
Original file line numberDiff line numberDiff line change
@@ -233,112 +233,28 @@ $.extend(Timepicker.prototype, {
233233
// parse the time string from input value or _setTime
234234
//########################################################################
235235
_parseTime: function(timeString, withDate) {
236-
var regstr = this._defaults.timeFormat.toString()
237-
.replace(/h{1,2}/ig, '(\\d?\\d)')
238-
.replace(/m{1,2}/ig, '(\\d?\\d)')
239-
.replace(/s{1,2}/ig, '(\\d?\\d)')
240-
.replace(/l{1}/ig, '(\\d?\\d?\\d)')
241-
.replace(/t{1,2}/ig, this._getPatternAmpm())
242-
.replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?')
243-
.replace(/\s/g, '\\s?') + this._defaults.timeSuffix + '$',
244-
order = this._getFormatPositions(),
245-
ampm = '',
246-
treg;
247-
248-
if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
249-
250-
if (withDate || !this._defaults.timeOnly) {
251-
// the time should come after x number of characters and a space.
252-
// x = at least the length of text specified by the date format
236+
if (withDate || !this._defaults.timeOnly)
237+
{
238+
if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
253239
var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
254-
// escape special regex characters in the seperator
255-
var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g");
256-
regstr = '^.{' + dp_dateFormat.length + ',}?' + this._defaults.separator.replace(specials, "\\$&") + regstr;
257-
}
258-
259-
treg = timeString.match(new RegExp(regstr, 'i'));
260-
261-
if (treg) {
262-
if (order.t !== -1) {
263-
if (treg[order.t] === undefined || treg[order.t].length === 0) {
264-
ampm = '';
265-
this.ampm = '';
266-
} else {
267-
ampm = $.inArray(treg[order.t].toUpperCase(), this.amNames) !== -1 ? 'AM' : 'PM';
268-
this.ampm = this._defaults[ampm == 'AM' ? 'amNames' : 'pmNames'][0];
269-
}
270-
}
271-
272-
if (order.h !== -1) {
273-
if (ampm == 'AM' && treg[order.h] == '12')
274-
this.hour = 0; // 12am = 0 hour
275-
else if (ampm == 'PM' && treg[order.h] != '12')
276-
this.hour = (parseFloat(treg[order.h]) + 12).toFixed(0); // 12pm = 12 hour, any other pm = hour + 12
277-
else this.hour = Number(treg[order.h]);
278-
}
279-
280-
if (order.m !== -1) this.minute = Number(treg[order.m]);
281-
if (order.s !== -1) this.second = Number(treg[order.s]);
282-
if (order.l !== -1) this.millisec = Number(treg[order.l]);
283-
if (order.z !== -1 && treg[order.z] !== undefined) {
284-
var tz = treg[order.z].toUpperCase();
285-
switch (tz.length) {
286-
case 1: // Z
287-
tz = this._defaults.timezoneIso8601 ? 'Z' : '+0000';
288-
break;
289-
case 5: // +hhmm
290-
if (this._defaults.timezoneIso8601)
291-
tz = tz.substring(1) == '0000'
292-
? 'Z'
293-
: tz.substring(0, 3) + ':' + tz.substring(3);
294-
break;
295-
case 6: // +hh:mm
296-
if (!this._defaults.timezoneIso8601)
297-
tz = tz == 'Z' || tz.substring(1) == '00:00'
298-
? '+0000'
299-
: tz.replace(/:/, '');
300-
else if (tz.substring(1) == '00:00')
301-
tz = 'Z';
302-
break;
303-
}
304-
this.timezone = tz;
305-
}
306-
307-
return true;
308-
309-
}
310-
return false;
311-
},
312-
313-
//########################################################################
314-
// pattern for standard and localized AM/PM markers
315-
//########################################################################
316-
_getPatternAmpm: function() {
317-
var markers = [],
318-
o = this._defaults;
319-
if (o.amNames)
320-
$.merge(markers, o.amNames);
321-
if (o.pmNames)
322-
$.merge(markers, o.pmNames);
323-
markers = $.map(markers, function(val) { return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&'); });
324-
return '(' + markers.join('|') + ')?';
325-
},
326-
327-
//########################################################################
328-
// figure out position of time elements.. cause js cant do named captures
329-
//########################################################################
330-
_getFormatPositions: function() {
331-
var finds = this._defaults.timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z)/g),
332-
orders = { h: -1, m: -1, s: -1, l: -1, t: -1, z: -1 };
333-
334-
if (finds)
335-
for (var i = 0; i < finds.length; i++)
336-
if (orders[finds[i].toString().charAt(0)] == -1)
337-
orders[finds[i].toString().charAt(0)] = i + 1;
338-
339-
return orders;
240+
try {
241+
var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
242+
if (!parseRes.timeObj) return false;
243+
$.extend(this, parseRes.timeObj);
244+
} catch (err)
245+
{
246+
return false;
247+
}
248+
return true;
249+
}
250+
else
251+
{
252+
var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
253+
$.extend(this, parseRes.timeObj);
254+
return true;
255+
}
340256
},
341-
257+
342258
//########################################################################
343259
// generate and inject html for timepicker into ui datepicker
344260
//########################################################################
@@ -934,6 +850,117 @@ $.fn.extend({
934850
}
935851
});
936852

853+
$.datepicker.parseDateTime = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
854+
var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
855+
if (parseRes.timeObj)
856+
{
857+
var t = parseRes.timeObj;
858+
parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
859+
}
860+
861+
return parseRes.date;
862+
}
863+
864+
$.datepicker.parseTime = function(timeFormat, timeString, options) {
865+
866+
//########################################################################
867+
// pattern for standard and localized AM/PM markers
868+
//########################################################################
869+
var getPatternAmpm = function(amNames, pmNames) {
870+
var markers = [];
871+
if (amNames)
872+
$.merge(markers, amNames);
873+
if (pmNames)
874+
$.merge(markers, pmNames);
875+
markers = $.map(markers, function(val) { return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&'); });
876+
return '(' + markers.join('|') + ')?';
877+
}
878+
879+
//########################################################################
880+
// figure out position of time elements.. cause js cant do named captures
881+
//########################################################################
882+
var getFormatPositions = function( timeFormat ) {
883+
var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z)/g),
884+
orders = { h: -1, m: -1, s: -1, l: -1, t: -1, z: -1 };
885+
886+
if (finds)
887+
for (var i = 0; i < finds.length; i++)
888+
if (orders[finds[i].toString().charAt(0)] == -1)
889+
orders[finds[i].toString().charAt(0)] = i + 1;
890+
891+
return orders;
892+
}
893+
894+
var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {});
895+
896+
var regstr = '^' + timeFormat.toString()
897+
.replace(/h{1,2}/ig, '(\\d?\\d)')
898+
.replace(/m{1,2}/ig, '(\\d?\\d)')
899+
.replace(/s{1,2}/ig, '(\\d?\\d)')
900+
.replace(/l{1}/ig, '(\\d?\\d?\\d)')
901+
.replace(/t{1,2}/ig, getPatternAmpm(o.amNames, o.pmNames))
902+
.replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?')
903+
.replace(/\s/g, '\\s?') + o.timeSuffix + '$',
904+
order = getFormatPositions(timeFormat),
905+
ampm = '',
906+
treg;
907+
908+
treg = timeString.match(new RegExp(regstr, 'i'));
909+
910+
var resTime = {hour: 0, minute: 0, second: 0, millisec: 0};
911+
912+
if (treg) {
913+
if (order.t !== -1) {
914+
if (treg[order.t] === undefined || treg[order.t].length === 0) {
915+
ampm = '';
916+
resTime.ampm = '';
917+
} else {
918+
ampm = $.inArray(treg[order.t], o.amNames) !== -1 ? 'AM' : 'PM';
919+
resTime.ampm = o[ampm == 'AM' ? 'amNames' : 'pmNames'][0];
920+
}
921+
}
922+
923+
if (order.h !== -1) {
924+
if (ampm == 'AM' && treg[order.h] == '12')
925+
resTime.hour = 0; // 12am = 0 hour
926+
else if (ampm == 'PM' && treg[order.h] != '12')
927+
resTime.hour = parseInt(treg[order.h],10) + 12; // 12pm = 12 hour, any other pm = hour + 12
928+
else resTime.hour = Number(treg[order.h]);
929+
}
930+
931+
if (order.m !== -1) resTime.minute = Number(treg[order.m]);
932+
if (order.s !== -1) resTime.second = Number(treg[order.s]);
933+
if (order.l !== -1) resTime.millisec = Number(treg[order.l]);
934+
if (order.z !== -1 && treg[order.z] !== undefined) {
935+
var tz = treg[order.z].toUpperCase();
936+
switch (tz.length) {
937+
case 1: // Z
938+
tz = o.timezoneIso8601 ? 'Z' : '+0000';
939+
break;
940+
case 5: // +hhmm
941+
if (o.timezoneIso8601)
942+
tz = tz.substring(1) == '0000'
943+
? 'Z'
944+
: tz.substring(0, 3) + ':' + tz.substring(3);
945+
break;
946+
case 6: // +hh:mm
947+
if (!o.timezoneIso8601)
948+
tz = tz == 'Z' || tz.substring(1) == '00:00'
949+
? '+0000'
950+
: tz.replace(/:/, '');
951+
else if (tz.substring(1) == '00:00')
952+
tz = 'Z';
953+
break;
954+
}
955+
resTime.timezone = tz;
956+
}
957+
958+
return resTime;
959+
960+
}
961+
return null;
962+
},
963+
937964
//########################################################################
938965
// format the time all pretty...
939966
// format = string format of the time
@@ -1240,21 +1267,8 @@ $.datepicker._getDateDatepicker = function(target, noDefault) {
12401267
//#######################################################################################
12411268
$.datepicker._base_parseDate = $.datepicker.parseDate;
12421269
$.datepicker.parseDate = function(format, value, settings) {
1243-
var date;
1244-
try {
1245-
date = this._base_parseDate(format, value, settings);
1246-
} catch (err) {
1247-
if (err.indexOf(":") >= 0) {
1248-
// Hack! The error message ends with a colon, a space, and
1249-
// the "extra" characters. We rely on that instead of
1250-
// attempting to perfectly reproduce the parsing algorithm.
1251-
date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings);
1252-
} else {
1253-
// The underlying error was not related to the time
1254-
throw err;
1255-
}
1256-
}
1257-
return date;
1270+
var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings);
1271+
return $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings);
12581272
};
12591273

12601274
//#######################################################################################
@@ -1332,7 +1346,60 @@ function extendRemove(target, props) {
13321346
return target;
13331347
};
13341348

1349+
//#######################################################################################
1350+
// Splits datetime string into date ans time substrings.
1351+
// Throws exception when date can't be parsed
1352+
// If only date is present, time substring eill be ''
1353+
//#######################################################################################
1354+
var splitDateTime = function(dateFormat, dateTimeString, dateSettings)
1355+
{
1356+
try {
1357+
var date = $.datepicker._base_parseDate(dateFormat, dateTimeString, dateSettings);
1358+
} catch (err) {
1359+
if (err.indexOf(":") >= 0) {
1360+
// Hack! The error message ends with a colon, a space, and
1361+
// the "extra" characters. We rely on that instead of
1362+
// attempting to perfectly reproduce the parsing algorithm.
1363+
var dateStringLength = dateTimeString.length-(err.length-err.indexOf(':')-2);
1364+
var timeString = dateTimeString.substring(dateStringLength);
1365+
1366+
return [dateTimeString.substring(0, dateStringLength), dateTimeString.substring(dateStringLength)]
1367+
1368+
} else {
1369+
throw err;
1370+
}
1371+
}
1372+
return [dateTimeString, ''];
1373+
}
1374+
1375+
//#######################################################################################
1376+
// Internal function to parse datetime interval
1377+
// Returns: {date: Date, timeObj: Object}, where
1378+
// date - parsed date without time (type Date)
1379+
// timeObj = {hour: , minute: , second: , millisec: } - parsed time. Optional
1380+
//#######################################################################################
1381+
var parseDateTimeInternal = function(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings)
1382+
{
1383+
var date;
1384+
var splitRes = splitDateTime(dateFormat, dateTimeString, dateSettings);
1385+
date = $.datepicker._base_parseDate(dateFormat, splitRes[0], dateSettings);
1386+
if (splitRes[1] != '')
1387+
{
1388+
var timeString = splitRes[1];
1389+
var separator = timeSettings && timeSettings.separator ? timeSettings.separator : $.timepicker._defaults.separator;
1390+
if ( timeString.indexOf(separator) != 0)
1391+
throw 'Missing time separator';
1392+
timeString = timeString.substring(separator.length);
1393+
var parsedTime = $.datepicker.parseTime(timeFormat, timeString, timeSettings);
1394+
if (parsedTime === null)
1395+
throw 'Wrong time format';
1396+
return {date: date, timeObj: parsedTime};
1397+
}
1398+
else
1399+
return {date: date};
1400+
}
1401+
13351402
$.timepicker = new Timepicker(); // singleton instance
13361403
$.timepicker.version = "1.0.1";
13371404

1338-
})(jQuery);
1405+
})(jQuery);

0 commit comments

Comments
 (0)