1 /*! jQuery Timepicker Addon - v1.4.5 - 2014-05-26
2 * http://trentrichardson.com/examples/timepicker
3 * Copyright (c) 2014 Trent Richardson; Licensed MIT */
7 * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
9 $.ui
.timepicker
= $.ui
.timepicker
|| {};
10 if ($.ui
.timepicker
.version
) {
15 * Extend jQueryUI, get it started with our version number
25 * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
26 * Settings for (groups of) time pickers are maintained in an instance object,
27 * allowing multiple different settings on the same page.
29 var Timepicker = function () {
30 this.regional
= []; // Available regional settings, indexed by language code
31 this.regional
[''] = { // Default regional settings
38 timeOnlyTitle
: 'Choose Time',
43 millisecText
: 'Millisecond',
44 microsecText
: 'Microsecond',
45 timezoneText
: 'Time Zone',
48 this._defaults
= { // Global defaults for all the datetime picker instances
49 showButtonPanel
: true,
51 timeOnlyShowDate
: false,
92 altFieldTimeOnly
: true,
96 altRedirectFocus
: true,
97 pickerTimeFormat
: null,
98 pickerTimeSuffix
: null,
101 addSliderAccess
: false,
102 sliderAccessArgs
: null,
103 controlType
: 'slider',
107 $.extend(this._defaults
, this.regional
['']);
110 $.extend(Timepicker
.prototype, {
118 millisec_slider
: null,
119 microsec_slider
: null,
120 timezone_select
: null,
129 hourMinOriginal
: null,
130 minuteMinOriginal
: null,
131 secondMinOriginal
: null,
132 millisecMinOriginal
: null,
133 microsecMinOriginal
: null,
134 hourMaxOriginal
: null,
135 minuteMaxOriginal
: null,
136 secondMaxOriginal
: null,
137 millisecMaxOriginal
: null,
138 microsecMaxOriginal
: null,
142 formattedDateTime
: '',
144 //units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
145 units
: ['hour', 'minute', 'second'], // WoltLab modification: milisec and microsec waste around 650ms creating 1k option-elements each
150 * Override the default settings for all instances of the time picker.
151 * @param {Object} settings object - the new settings to use as defaults (anonymous object)
152 * @return {Object} the manager object
154 setDefaults: function (settings
) {
155 extendRemove(this._defaults
, settings
|| {});
160 * Create a new Timepicker instance
162 _newInst: function ($input
, opts
) {
163 var tp_inst
= new Timepicker(),
168 for (var attrName
in this._defaults
) {
169 if (this._defaults
.hasOwnProperty(attrName
)) {
170 var attrValue
= $input
.attr('time:' + attrName
);
173 inlineSettings
[attrName
] = eval(attrValue
);
175 inlineSettings
[attrName
] = attrValue
;
182 beforeShow: function (input
, dp_inst
) {
183 if ($.isFunction(tp_inst
._defaults
.evnts
.beforeShow
)) {
184 return tp_inst
._defaults
.evnts
.beforeShow
.call($input
[0], input
, dp_inst
, tp_inst
);
187 onChangeMonthYear: function (year
, month
, dp_inst
) {
188 // Update the time as well : this prevents the time from disappearing from the $input field.
189 tp_inst
._updateDateTime(dp_inst
);
190 if ($.isFunction(tp_inst
._defaults
.evnts
.onChangeMonthYear
)) {
191 tp_inst
._defaults
.evnts
.onChangeMonthYear
.call($input
[0], year
, month
, dp_inst
, tp_inst
);
194 onClose: function (dateText
, dp_inst
) {
195 if (tp_inst
.timeDefined
=== true && $input
.val() !== '') {
196 tp_inst
._updateDateTime(dp_inst
);
198 if ($.isFunction(tp_inst
._defaults
.evnts
.onClose
)) {
199 tp_inst
._defaults
.evnts
.onClose
.call($input
[0], dateText
, dp_inst
, tp_inst
);
203 for (i
in overrides
) {
204 if (overrides
.hasOwnProperty(i
)) {
205 fns
[i
] = opts
[i
] || null;
209 tp_inst
._defaults
= $.extend({}, this._defaults
, inlineSettings
, opts
, overrides
, {
211 timepicker
: tp_inst
// add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
213 tp_inst
.amNames
= $.map(tp_inst
._defaults
.amNames
, function (val
) {
214 return val
.toUpperCase();
216 tp_inst
.pmNames
= $.map(tp_inst
._defaults
.pmNames
, function (val
) {
217 return val
.toUpperCase();
220 // detect which units are supported
221 tp_inst
.support
= detectSupport(
222 tp_inst
._defaults
.timeFormat
+
223 (tp_inst
._defaults
.pickerTimeFormat
? tp_inst
._defaults
.pickerTimeFormat
: '') +
224 (tp_inst
._defaults
.altTimeFormat
? tp_inst
._defaults
.altTimeFormat
: ''));
226 // controlType is string - key to our this._controls
227 if (typeof(tp_inst
._defaults
.controlType
) === 'string') {
228 if (tp_inst
._defaults
.controlType
=== 'slider' && typeof($.ui
.slider
) === 'undefined') {
229 tp_inst
._defaults
.controlType
= 'select';
231 tp_inst
.control
= tp_inst
._controls
[tp_inst
._defaults
.controlType
];
233 // controlType is an object and must implement create, options, value methods
235 tp_inst
.control
= tp_inst
._defaults
.controlType
;
238 // prep the timezone options
239 var timezoneList
= [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
240 0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
241 if (tp_inst
._defaults
.timezoneList
!== null) {
242 timezoneList
= tp_inst
._defaults
.timezoneList
;
244 var tzl
= timezoneList
.length
, tzi
= 0, tzv
= null;
245 if (tzl
> 0 && typeof timezoneList
[0] !== 'object') {
246 for (; tzi
< tzl
; tzi
++) {
247 tzv
= timezoneList
[tzi
];
248 timezoneList
[tzi
] = { value
: tzv
, label
: $.timepicker
.timezoneOffsetString(tzv
, tp_inst
.support
.iso8601
) };
251 tp_inst
._defaults
.timezoneList
= timezoneList
;
253 // set the default units
254 tp_inst
.timezone
= tp_inst
._defaults
.timezone
!== null ? $.timepicker
.timezoneOffsetNumber(tp_inst
._defaults
.timezone
) :
255 ((new Date()).getTimezoneOffset() * -1);
256 tp_inst
.hour
= tp_inst
._defaults
.hour
< tp_inst
._defaults
.hourMin
? tp_inst
._defaults
.hourMin
:
257 tp_inst
._defaults
.hour
> tp_inst
._defaults
.hourMax
? tp_inst
._defaults
.hourMax
: tp_inst
._defaults
.hour
;
258 tp_inst
.minute
= tp_inst
._defaults
.minute
< tp_inst
._defaults
.minuteMin
? tp_inst
._defaults
.minuteMin
:
259 tp_inst
._defaults
.minute
> tp_inst
._defaults
.minuteMax
? tp_inst
._defaults
.minuteMax
: tp_inst
._defaults
.minute
;
260 tp_inst
.second
= tp_inst
._defaults
.second
< tp_inst
._defaults
.secondMin
? tp_inst
._defaults
.secondMin
:
261 tp_inst
._defaults
.second
> tp_inst
._defaults
.secondMax
? tp_inst
._defaults
.secondMax
: tp_inst
._defaults
.second
;
262 tp_inst
.millisec
= tp_inst
._defaults
.millisec
< tp_inst
._defaults
.millisecMin
? tp_inst
._defaults
.millisecMin
:
263 tp_inst
._defaults
.millisec
> tp_inst
._defaults
.millisecMax
? tp_inst
._defaults
.millisecMax
: tp_inst
._defaults
.millisec
;
264 tp_inst
.microsec
= tp_inst
._defaults
.microsec
< tp_inst
._defaults
.microsecMin
? tp_inst
._defaults
.microsecMin
:
265 tp_inst
._defaults
.microsec
> tp_inst
._defaults
.microsecMax
? tp_inst
._defaults
.microsecMax
: tp_inst
._defaults
.microsec
;
267 tp_inst
.$input
= $input
;
269 if (tp_inst
._defaults
.altField
) {
270 tp_inst
.$altInput
= $(tp_inst
._defaults
.altField
);
271 if (tp_inst
._defaults
.altRedirectFocus
=== true) {
272 tp_inst
.$altInput
.css({
274 }).focus(function () {
275 $input
.trigger("focus");
280 if (tp_inst
._defaults
.minDate
=== 0 || tp_inst
._defaults
.minDateTime
=== 0) {
281 tp_inst
._defaults
.minDate
= new Date();
283 if (tp_inst
._defaults
.maxDate
=== 0 || tp_inst
._defaults
.maxDateTime
=== 0) {
284 tp_inst
._defaults
.maxDate
= new Date();
287 // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
288 if (tp_inst
._defaults
.minDate
!== undefined && tp_inst
._defaults
.minDate
instanceof Date
) {
289 tp_inst
._defaults
.minDateTime
= new Date(tp_inst
._defaults
.minDate
.getTime());
291 if (tp_inst
._defaults
.minDateTime
!== undefined && tp_inst
._defaults
.minDateTime
instanceof Date
) {
292 tp_inst
._defaults
.minDate
= new Date(tp_inst
._defaults
.minDateTime
.getTime());
294 if (tp_inst
._defaults
.maxDate
!== undefined && tp_inst
._defaults
.maxDate
instanceof Date
) {
295 tp_inst
._defaults
.maxDateTime
= new Date(tp_inst
._defaults
.maxDate
.getTime());
297 if (tp_inst
._defaults
.maxDateTime
!== undefined && tp_inst
._defaults
.maxDateTime
instanceof Date
) {
298 tp_inst
._defaults
.maxDate
= new Date(tp_inst
._defaults
.maxDateTime
.getTime());
300 tp_inst
.$input
.bind('focus', function () {
308 * add our sliders to the calendar
310 _addTimePicker: function (dp_inst
) {
311 var currDT
= (this.$altInput
&& this._defaults
.altFieldTimeOnly
) ? this.$input
.val() + ' ' + this.$altInput
.val() : this.$input
.val();
313 this.timeDefined
= this._parseTime(currDT
);
314 this._limitMinMaxDateTime(dp_inst
, false);
315 this._injectTimePicker();
319 * parse the time string from input value or _setTime
321 _parseTime: function (timeString
, withDate
) {
323 this.inst
= $.datepicker
._getInst(this.$input
[0]);
326 if (withDate
|| !this._defaults
.timeOnly
) {
327 var dp_dateFormat
= $.datepicker
._get(this.inst
, 'dateFormat');
329 var parseRes
= parseDateTimeInternal(dp_dateFormat
, this._defaults
.timeFormat
, timeString
, $.datepicker
._getFormatConfig(this.inst
), this._defaults
);
330 if (!parseRes
.timeObj
) {
333 $.extend(this, parseRes
.timeObj
);
335 $.timepicker
.log("Error parsing the date/time string: " + err
+
336 "\ndate/time string = " + timeString
+
337 "\ntimeFormat = " + this._defaults
.timeFormat
+
338 "\ndateFormat = " + dp_dateFormat
);
343 var timeObj
= $.datepicker
.parseTime(this._defaults
.timeFormat
, timeString
, this._defaults
);
347 $.extend(this, timeObj
);
353 * generate and inject html for timepicker into ui datepicker
355 _injectTimePicker: function () {
356 var $dp
= this.inst
.dpDiv
,
357 o
= this.inst
.settings
,
368 // Prevent displaying twice
369 if ($dp
.find("div.ui-timepicker-div").length
=== 0 && o
.showTimepicker
) {
370 var noDisplay
= ' style="display:none;"',
371 html
= '<div class="ui-timepicker-div' + (o
.isRTL
? ' ui-timepicker-rtl' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o
.showTime
) ? '' : noDisplay
) + '>' + o
.timeText
+ '</dt>' +
372 '<dd class="ui_tpicker_time"' + ((o
.showTime
) ? '' : noDisplay
) + '></dd>';
375 for (i
= 0, l
= this.units
.length
; i
< l
; i
++) {
376 litem
= this.units
[i
];
377 uitem
= litem
.substr(0, 1).toUpperCase() + litem
.substr(1);
378 show
= o
['show' + uitem
] !== null ? o
['show' + uitem
] : this.support
[litem
];
380 // Added by Peter Medeiros:
381 // - Figure out what the hour/minute/second max should be based on the step values.
382 // - Example: if stepMinute is 15, then minMax is 45.
383 max
[litem
] = parseInt((o
[litem
+ 'Max'] - ((o
[litem
+ 'Max'] - o
[litem
+ 'Min']) % o
['step' + uitem
])), 10);
386 html
+= '<dt class="ui_tpicker_' + litem
+ '_label"' + (show
? '' : noDisplay
) + '>' + o
[litem
+ 'Text'] + '</dt>' +
387 '<dd class="ui_tpicker_' + litem
+ '"><div class="ui_tpicker_' + litem
+ '_slider"' + (show
? '' : noDisplay
) + '></div>';
389 if (show
&& o
[litem
+ 'Grid'] > 0) {
390 html
+= '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
392 if (litem
=== 'hour') {
393 for (var h
= o
[litem
+ 'Min']; h
<= max
[litem
]; h
+= parseInt(o
[litem
+ 'Grid'], 10)) {
395 var tmph
= $.datepicker
.formatTime(this.support
.ampm
? 'hht' : 'HH', {hour
: h
}, o
);
396 html
+= '<td data-for="' + litem
+ '">' + tmph
+ '</td>';
400 for (var m
= o
[litem
+ 'Min']; m
<= max
[litem
]; m
+= parseInt(o
[litem
+ 'Grid'], 10)) {
402 html
+= '<td data-for="' + litem
+ '">' + ((m
< 10) ? '0' : '') + m
+ '</td>';
406 html
+= '</tr></table></div>';
412 var showTz
= o
.showTimezone
!== null ? o
.showTimezone
: this.support
.timezone
;
413 html
+= '<dt class="ui_tpicker_timezone_label"' + (showTz
? '' : noDisplay
) + '>' + o
.timezoneText
+ '</dt>';
414 html
+= '<dd class="ui_tpicker_timezone" ' + (showTz
? '' : noDisplay
) + '></dd>';
416 // Create the elements from string
417 html
+= '</dl></div>';
420 // if we only want time picker...
421 if (o
.timeOnly
=== true) {
422 $tp
.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o
.timeOnlyTitle
+ '</div>' + '</div>');
423 $dp
.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
426 // add sliders, adjust grids, add events
427 for (i
= 0, l
= tp_inst
.units
.length
; i
< l
; i
++) {
428 litem
= tp_inst
.units
[i
];
429 uitem
= litem
.substr(0, 1).toUpperCase() + litem
.substr(1);
430 show
= o
['show' + uitem
] !== null ? o
['show' + uitem
] : this.support
[litem
];
433 tp_inst
[litem
+ '_slider'] = tp_inst
.control
.create(tp_inst
, $tp
.find('.ui_tpicker_' + litem
+ '_slider'), litem
, tp_inst
[litem
], o
[litem
+ 'Min'], max
[litem
], o
['step' + uitem
]);
435 // adjust the grid and add click event
436 if (show
&& o
[litem
+ 'Grid'] > 0) {
437 size
= 100 * gridSize
[litem
] * o
[litem
+ 'Grid'] / (max
[litem
] - o
[litem
+ 'Min']);
438 $tp
.find('.ui_tpicker_' + litem
+ ' table').css({
440 marginLeft
: o
.isRTL
? '0' : ((size
/ (-2 * gridSize
[litem
])) + "%"),
441 marginRight
: o
.isRTL
? ((size
/ (-2 * gridSize
[litem
])) + "%") : '0',
442 borderCollapse
: 'collapse'
443 }).find("td").click(function (e
) {
446 n
= parseInt(h
.replace(/[^0-9]/g), 10),
447 ap
= h
.replace(/[^apm]/ig),
448 f
= $t
.data('for'); // loses scope, so we use data-for
451 if (ap
.indexOf('p') !== -1 && n
< 12) {
455 if (ap
.indexOf('a') !== -1 && n
=== 12) {
461 tp_inst
.control
.value(tp_inst
, tp_inst
[f
+ '_slider'], litem
, n
);
463 tp_inst
._onTimeChange();
464 tp_inst
._onSelectHandler();
467 width
: (100 / gridSize
[litem
]) + '%',
474 // Add timezone options
475 this.timezone_select
= $tp
.find('.ui_tpicker_timezone').append('<select></select>').find("select");
476 $.fn
.append
.apply(this.timezone_select
,
477 $.map(o
.timezoneList
, function (val
, idx
) {
478 return $("<option />").val(typeof val
=== "object" ? val
.value
: val
).text(typeof val
=== "object" ? val
.label
: val
);
480 if (typeof(this.timezone
) !== "undefined" && this.timezone
!== null && this.timezone
!== "") {
481 var local_timezone
= (new Date(this.inst
.selectedYear
, this.inst
.selectedMonth
, this.inst
.selectedDay
, 12)).getTimezoneOffset() * -1;
482 if (local_timezone
=== this.timezone
) {
483 selectLocalTimezone(tp_inst
);
485 this.timezone_select
.val(this.timezone
);
488 if (typeof(this.hour
) !== "undefined" && this.hour
!== null && this.hour
!== "") {
489 this.timezone_select
.val(o
.timezone
);
491 selectLocalTimezone(tp_inst
);
494 this.timezone_select
.change(function () {
495 tp_inst
._onTimeChange();
496 tp_inst
._onSelectHandler();
498 // End timezone options
500 // inject timepicker into datepicker
501 var $buttonPanel
= $dp
.find('.ui-datepicker-buttonpane');
502 if ($buttonPanel
.length
) {
503 $buttonPanel
.before($tp
);
508 this.$timeObj
= $tp
.find('.ui_tpicker_time');
510 if (this.inst
!== null) {
511 var timeDefined
= this.timeDefined
;
512 this._onTimeChange();
513 this.timeDefined
= timeDefined
;
516 // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
517 if (this._defaults
.addSliderAccess
) {
518 var sliderAccessArgs
= this._defaults
.sliderAccessArgs
,
519 rtl
= this._defaults
.isRTL
;
520 sliderAccessArgs
.isRTL
= rtl
;
522 setTimeout(function () { // fix for inline mode
523 if ($tp
.find('.ui-slider-access').length
=== 0) {
524 $tp
.find('.ui-slider:visible').sliderAccess(sliderAccessArgs
);
526 // fix any grids since sliders are shorter
527 var sliderAccessWidth
= $tp
.find('.ui-slider-access:eq(0)').outerWidth(true);
528 if (sliderAccessWidth
) {
529 $tp
.find('table:visible').each(function () {
531 oldWidth
= $g
.outerWidth(),
532 oldMarginLeft
= $g
.css(rtl
? 'marginRight' : 'marginLeft').toString().replace('%', ''),
533 newWidth
= oldWidth
- sliderAccessWidth
,
534 newMarginLeft
= ((oldMarginLeft
* newWidth
) / oldWidth
) + '%',
535 css
= { width
: newWidth
, marginRight
: 0, marginLeft
: 0 };
536 css
[rtl
? 'marginRight' : 'marginLeft'] = newMarginLeft
;
543 // end slideAccess integration
545 tp_inst
._limitMinMaxDateTime(this.inst
, true);
550 * This function tries to limit the ability to go outside the
553 _limitMinMaxDateTime: function (dp_inst
, adjustSliders
) {
554 var o
= this._defaults
,
555 dp_date
= new Date(dp_inst
.selectedYear
, dp_inst
.selectedMonth
, dp_inst
.selectedDay
);
557 if (!this._defaults
.showTimepicker
) {
559 } // No time so nothing to check here
561 if ($.datepicker
._get(dp_inst
, 'minDateTime') !== null && $.datepicker
._get(dp_inst
, 'minDateTime') !== undefined && dp_date
) {
562 var minDateTime
= $.datepicker
._get(dp_inst
, 'minDateTime'),
563 minDateTimeDate
= new Date(minDateTime
.getFullYear(), minDateTime
.getMonth(), minDateTime
.getDate(), 0, 0, 0, 0);
565 if (this.hourMinOriginal
=== null || this.minuteMinOriginal
=== null || this.secondMinOriginal
=== null || this.millisecMinOriginal
=== null || this.microsecMinOriginal
=== null) {
566 this.hourMinOriginal
= o
.hourMin
;
567 this.minuteMinOriginal
= o
.minuteMin
;
568 this.secondMinOriginal
= o
.secondMin
;
569 this.millisecMinOriginal
= o
.millisecMin
;
570 this.microsecMinOriginal
= o
.microsecMin
;
573 if (dp_inst
.settings
.timeOnly
|| minDateTimeDate
.getTime() === dp_date
.getTime()) {
574 this._defaults
.hourMin
= minDateTime
.getHours();
575 if (this.hour
<= this._defaults
.hourMin
) {
576 this.hour
= this._defaults
.hourMin
;
577 this._defaults
.minuteMin
= minDateTime
.getMinutes();
578 if (this.minute
<= this._defaults
.minuteMin
) {
579 this.minute
= this._defaults
.minuteMin
;
580 this._defaults
.secondMin
= minDateTime
.getSeconds();
581 if (this.second
<= this._defaults
.secondMin
) {
582 this.second
= this._defaults
.secondMin
;
583 this._defaults
.millisecMin
= minDateTime
.getMilliseconds();
584 if (this.millisec
<= this._defaults
.millisecMin
) {
585 this.millisec
= this._defaults
.millisecMin
;
586 this._defaults
.microsecMin
= minDateTime
.getMicroseconds();
588 if (this.microsec
< this._defaults
.microsecMin
) {
589 this.microsec
= this._defaults
.microsecMin
;
591 this._defaults
.microsecMin
= this.microsecMinOriginal
;
594 this._defaults
.millisecMin
= this.millisecMinOriginal
;
595 this._defaults
.microsecMin
= this.microsecMinOriginal
;
598 this._defaults
.secondMin
= this.secondMinOriginal
;
599 this._defaults
.millisecMin
= this.millisecMinOriginal
;
600 this._defaults
.microsecMin
= this.microsecMinOriginal
;
603 this._defaults
.minuteMin
= this.minuteMinOriginal
;
604 this._defaults
.secondMin
= this.secondMinOriginal
;
605 this._defaults
.millisecMin
= this.millisecMinOriginal
;
606 this._defaults
.microsecMin
= this.microsecMinOriginal
;
609 this._defaults
.hourMin
= this.hourMinOriginal
;
610 this._defaults
.minuteMin
= this.minuteMinOriginal
;
611 this._defaults
.secondMin
= this.secondMinOriginal
;
612 this._defaults
.millisecMin
= this.millisecMinOriginal
;
613 this._defaults
.microsecMin
= this.microsecMinOriginal
;
617 if ($.datepicker
._get(dp_inst
, 'maxDateTime') !== null && $.datepicker
._get(dp_inst
, 'maxDateTime') !== undefined && dp_date
) {
618 var maxDateTime
= $.datepicker
._get(dp_inst
, 'maxDateTime'),
619 maxDateTimeDate
= new Date(maxDateTime
.getFullYear(), maxDateTime
.getMonth(), maxDateTime
.getDate(), 0, 0, 0, 0);
621 if (this.hourMaxOriginal
=== null || this.minuteMaxOriginal
=== null || this.secondMaxOriginal
=== null || this.millisecMaxOriginal
=== null) {
622 this.hourMaxOriginal
= o
.hourMax
;
623 this.minuteMaxOriginal
= o
.minuteMax
;
624 this.secondMaxOriginal
= o
.secondMax
;
625 this.millisecMaxOriginal
= o
.millisecMax
;
626 this.microsecMaxOriginal
= o
.microsecMax
;
629 if (dp_inst
.settings
.timeOnly
|| maxDateTimeDate
.getTime() === dp_date
.getTime()) {
630 this._defaults
.hourMax
= maxDateTime
.getHours();
631 if (this.hour
>= this._defaults
.hourMax
) {
632 this.hour
= this._defaults
.hourMax
;
633 this._defaults
.minuteMax
= maxDateTime
.getMinutes();
634 if (this.minute
>= this._defaults
.minuteMax
) {
635 this.minute
= this._defaults
.minuteMax
;
636 this._defaults
.secondMax
= maxDateTime
.getSeconds();
637 if (this.second
>= this._defaults
.secondMax
) {
638 this.second
= this._defaults
.secondMax
;
639 this._defaults
.millisecMax
= maxDateTime
.getMilliseconds();
640 if (this.millisec
>= this._defaults
.millisecMax
) {
641 this.millisec
= this._defaults
.millisecMax
;
642 this._defaults
.microsecMax
= maxDateTime
.getMicroseconds();
644 if (this.microsec
> this._defaults
.microsecMax
) {
645 this.microsec
= this._defaults
.microsecMax
;
647 this._defaults
.microsecMax
= this.microsecMaxOriginal
;
650 this._defaults
.millisecMax
= this.millisecMaxOriginal
;
651 this._defaults
.microsecMax
= this.microsecMaxOriginal
;
654 this._defaults
.secondMax
= this.secondMaxOriginal
;
655 this._defaults
.millisecMax
= this.millisecMaxOriginal
;
656 this._defaults
.microsecMax
= this.microsecMaxOriginal
;
659 this._defaults
.minuteMax
= this.minuteMaxOriginal
;
660 this._defaults
.secondMax
= this.secondMaxOriginal
;
661 this._defaults
.millisecMax
= this.millisecMaxOriginal
;
662 this._defaults
.microsecMax
= this.microsecMaxOriginal
;
665 this._defaults
.hourMax
= this.hourMaxOriginal
;
666 this._defaults
.minuteMax
= this.minuteMaxOriginal
;
667 this._defaults
.secondMax
= this.secondMaxOriginal
;
668 this._defaults
.millisecMax
= this.millisecMaxOriginal
;
669 this._defaults
.microsecMax
= this.microsecMaxOriginal
;
673 if (dp_inst
.settings
.minTime
!==null) {
674 var tempMinTime
=new Date("01/01/1970 " + dp_inst
.settings
.minTime
);
675 if (this.hour
<tempMinTime
.getHours()) {
676 this.hour
=this._defaults
.hourMin
=tempMinTime
.getHours();
677 this.minute
=this._defaults
.minuteMin
=tempMinTime
.getMinutes();
678 } else if (this.hour
===tempMinTime
.getHours() && this.minute
<tempMinTime
.getMinutes()) {
679 this.minute
=this._defaults
.minuteMin
=tempMinTime
.getMinutes();
681 if (this._defaults
.hourMin
<tempMinTime
.getHours()) {
682 this._defaults
.hourMin
=tempMinTime
.getHours();
683 this._defaults
.minuteMin
=tempMinTime
.getMinutes();
684 } else if (this._defaults
.hourMin
===tempMinTime
.getHours()===this.hour
&& this._defaults
.minuteMin
<tempMinTime
.getMinutes()) {
685 this._defaults
.minuteMin
=tempMinTime
.getMinutes();
687 this._defaults
.minuteMin
=0;
692 if (dp_inst
.settings
.maxTime
!==null) {
693 var tempMaxTime
=new Date("01/01/1970 " + dp_inst
.settings
.maxTime
);
694 if (this.hour
>tempMaxTime
.getHours()) {
695 this.hour
=this._defaults
.hourMax
=tempMaxTime
.getHours();
696 this.minute
=this._defaults
.minuteMax
=tempMaxTime
.getMinutes();
697 } else if (this.hour
===tempMaxTime
.getHours() && this.minute
>tempMaxTime
.getMinutes()) {
698 this.minute
=this._defaults
.minuteMax
=tempMaxTime
.getMinutes();
700 if (this._defaults
.hourMax
>tempMaxTime
.getHours()) {
701 this._defaults
.hourMax
=tempMaxTime
.getHours();
702 this._defaults
.minuteMax
=tempMaxTime
.getMinutes();
703 } else if (this._defaults
.hourMax
===tempMaxTime
.getHours()===this.hour
&& this._defaults
.minuteMax
>tempMaxTime
.getMinutes()) {
704 this._defaults
.minuteMax
=tempMaxTime
.getMinutes();
706 this._defaults
.minuteMax
=59;
711 if (adjustSliders
!== undefined && adjustSliders
=== true) {
712 var hourMax
= parseInt((this._defaults
.hourMax
- ((this._defaults
.hourMax
- this._defaults
.hourMin
) % this._defaults
.stepHour
)), 10),
713 minMax
= parseInt((this._defaults
.minuteMax
- ((this._defaults
.minuteMax
- this._defaults
.minuteMin
) % this._defaults
.stepMinute
)), 10),
714 secMax
= parseInt((this._defaults
.secondMax
- ((this._defaults
.secondMax
- this._defaults
.secondMin
) % this._defaults
.stepSecond
)), 10),
715 millisecMax
= parseInt((this._defaults
.millisecMax
- ((this._defaults
.millisecMax
- this._defaults
.millisecMin
) % this._defaults
.stepMillisec
)), 10),
716 microsecMax
= parseInt((this._defaults
.microsecMax
- ((this._defaults
.microsecMax
- this._defaults
.microsecMin
) % this._defaults
.stepMicrosec
)), 10);
718 if (this.hour_slider
) {
719 this.control
.options(this, this.hour_slider
, 'hour', { min
: this._defaults
.hourMin
, max
: hourMax
, step
: this._defaults
.stepHour
});
720 this.control
.value(this, this.hour_slider
, 'hour', this.hour
- (this.hour
% this._defaults
.stepHour
));
722 if (this.minute_slider
) {
723 this.control
.options(this, this.minute_slider
, 'minute', { min
: this._defaults
.minuteMin
, max
: minMax
, step
: this._defaults
.stepMinute
});
724 this.control
.value(this, this.minute_slider
, 'minute', this.minute
- (this.minute
% this._defaults
.stepMinute
));
726 if (this.second_slider
) {
727 this.control
.options(this, this.second_slider
, 'second', { min
: this._defaults
.secondMin
, max
: secMax
, step
: this._defaults
.stepSecond
});
728 this.control
.value(this, this.second_slider
, 'second', this.second
- (this.second
% this._defaults
.stepSecond
));
730 if (this.millisec_slider
) {
731 this.control
.options(this, this.millisec_slider
, 'millisec', { min
: this._defaults
.millisecMin
, max
: millisecMax
, step
: this._defaults
.stepMillisec
});
732 this.control
.value(this, this.millisec_slider
, 'millisec', this.millisec
- (this.millisec
% this._defaults
.stepMillisec
));
734 if (this.microsec_slider
) {
735 this.control
.options(this, this.microsec_slider
, 'microsec', { min
: this._defaults
.microsecMin
, max
: microsecMax
, step
: this._defaults
.stepMicrosec
});
736 this.control
.value(this, this.microsec_slider
, 'microsec', this.microsec
- (this.microsec
% this._defaults
.stepMicrosec
));
743 * when a slider moves, set the internal time...
744 * on time change is also called when the time is updated in the text field
746 _onTimeChange: function () {
747 if (!this._defaults
.showTimepicker
) {
750 var hour
= (this.hour_slider
) ? this.control
.value(this, this.hour_slider
, 'hour') : false,
751 minute
= (this.minute_slider
) ? this.control
.value(this, this.minute_slider
, 'minute') : false,
752 second
= (this.second_slider
) ? this.control
.value(this, this.second_slider
, 'second') : false,
753 millisec
= (this.millisec_slider
) ? this.control
.value(this, this.millisec_slider
, 'millisec') : false,
754 microsec
= (this.microsec_slider
) ? this.control
.value(this, this.microsec_slider
, 'microsec') : false,
755 timezone
= (this.timezone_select
) ? this.timezone_select
.val() : false,
757 pickerTimeFormat
= o
.pickerTimeFormat
|| o
.timeFormat
,
758 pickerTimeSuffix
= o
.pickerTimeSuffix
|| o
.timeSuffix
;
760 if (typeof(hour
) === 'object') {
763 if (typeof(minute
) === 'object') {
766 if (typeof(second
) === 'object') {
769 if (typeof(millisec
) === 'object') {
772 if (typeof(microsec
) === 'object') {
775 if (typeof(timezone
) === 'object') {
779 if (hour
!== false) {
780 hour
= parseInt(hour
, 10);
782 if (minute
!== false) {
783 minute
= parseInt(minute
, 10);
785 if (second
!== false) {
786 second
= parseInt(second
, 10);
788 if (millisec
!== false) {
789 millisec
= parseInt(millisec
, 10);
791 if (microsec
!== false) {
792 microsec
= parseInt(microsec
, 10);
794 if (timezone
!== false) {
795 timezone
= timezone
.toString();
798 var ampm
= o
[hour
< 12 ? 'amNames' : 'pmNames'][0];
800 // If the update was done in the input field, the input field should not be updated.
801 // If the update was done using the sliders, update the input field.
803 hour
!== parseInt(this.hour
,10) || // sliders should all be numeric
804 minute
!== parseInt(this.minute
,10) ||
805 second
!== parseInt(this.second
,10) ||
806 millisec
!== parseInt(this.millisec
,10) ||
807 microsec
!== parseInt(this.microsec
,10) ||
808 (this.ampm
.length
> 0 && (hour
< 12) !== ($.inArray(this.ampm
.toUpperCase(), this.amNames
) !== -1)) ||
809 (this.timezone
!== null && timezone
!== this.timezone
.toString()) // could be numeric or "EST" format, so use toString()
814 if (hour
!== false) {
817 if (minute
!== false) {
818 this.minute
= minute
;
820 if (second
!== false) {
821 this.second
= second
;
823 if (millisec
!== false) {
824 this.millisec
= millisec
;
826 if (microsec
!== false) {
827 this.microsec
= microsec
;
829 if (timezone
!== false) {
830 this.timezone
= timezone
;
834 this.inst
= $.datepicker
._getInst(this.$input
[0]);
837 this._limitMinMaxDateTime(this.inst
, true);
839 if (this.support
.ampm
) {
843 // Updates the time within the timepicker
844 this.formattedTime
= $.datepicker
.formatTime(o
.timeFormat
, this, o
);
846 if (pickerTimeFormat
=== o
.timeFormat
) {
847 this.$timeObj
.text(this.formattedTime
+ pickerTimeSuffix
);
850 this.$timeObj
.text($.datepicker
.formatTime(pickerTimeFormat
, this, o
) + pickerTimeSuffix
);
854 this.timeDefined
= true;
856 this._updateDateTime();
857 //this.$input.focus(); // may automatically open the picker on setDate
862 * call custom onSelect.
863 * bind to sliders slidestop, and grid click.
865 _onSelectHandler: function () {
866 var onSelect
= this._defaults
.onSelect
|| this.inst
.settings
.onSelect
;
867 var inputEl
= this.$input
? this.$input
[0] : null;
868 if (onSelect
&& inputEl
) {
869 onSelect
.apply(inputEl
, [this.formattedDateTime
, this]);
874 * update our input with the new date time..
876 _updateDateTime: function (dp_inst
) {
877 dp_inst
= this.inst
|| dp_inst
;
878 var dtTmp
= (dp_inst
.currentYear
> 0?
879 new Date(dp_inst
.currentYear
, dp_inst
.currentMonth
, dp_inst
.currentDay
) :
880 new Date(dp_inst
.selectedYear
, dp_inst
.selectedMonth
, dp_inst
.selectedDay
)),
881 dt
= $.datepicker
._daylightSavingAdjust(dtTmp
),
882 //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
883 //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
884 dateFmt
= $.datepicker
._get(dp_inst
, 'dateFormat'),
885 formatCfg
= $.datepicker
._getFormatConfig(dp_inst
),
886 timeAvailable
= dt
!== null && this.timeDefined
;
887 this.formattedDate
= $.datepicker
.formatDate(dateFmt
, (dt
=== null ? new Date() : dt
), formatCfg
);
888 var formattedDateTime
= this.formattedDate
;
890 // if a slider was changed but datepicker doesn't have a value yet, set it
891 if (dp_inst
.lastVal
=== "") {
892 dp_inst
.currentYear
= dp_inst
.selectedYear
;
893 dp_inst
.currentMonth
= dp_inst
.selectedMonth
;
894 dp_inst
.currentDay
= dp_inst
.selectedDay
;
898 * remove following lines to force every changes in date picker to change the input value
899 * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
900 * If the user manually empty the value in the input field, the date picker will never change selected value.
902 //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
906 if (this._defaults
.timeOnly
=== true && this._defaults
.timeOnlyShowDate
=== false) {
907 formattedDateTime
= this.formattedTime
;
908 } else if ((this._defaults
.timeOnly
!== true && (this._defaults
.alwaysSetTime
|| timeAvailable
)) || (this._defaults
.timeOnly
=== true && this._defaults
.timeOnlyShowDate
=== true)) {
909 formattedDateTime
+= this._defaults
.separator
+ this.formattedTime
+ this._defaults
.timeSuffix
;
912 this.formattedDateTime
= formattedDateTime
;
914 if (!this._defaults
.showTimepicker
) {
915 this.$input
.val(this.formattedDate
);
916 } else if (this.$altInput
&& this._defaults
.timeOnly
=== false && this._defaults
.altFieldTimeOnly
=== true) {
917 this.$altInput
.val(this.formattedTime
);
918 this.$input
.val(this.formattedDate
);
919 } else if (this.$altInput
) {
920 this.$input
.val(formattedDateTime
);
921 var altFormattedDateTime
= '',
922 altSeparator
= this._defaults
.altSeparator
!== null ? this._defaults
.altSeparator
: this._defaults
.separator
,
923 altTimeSuffix
= this._defaults
.altTimeSuffix
!== null ? this._defaults
.altTimeSuffix
: this._defaults
.timeSuffix
;
925 if (!this._defaults
.timeOnly
) {
926 if (this._defaults
.altFormat
) {
927 altFormattedDateTime
= $.datepicker
.formatDate(this._defaults
.altFormat
, (dt
=== null ? new Date() : dt
), formatCfg
);
930 altFormattedDateTime
= this.formattedDate
;
933 if (altFormattedDateTime
) {
934 altFormattedDateTime
+= altSeparator
;
938 if (this._defaults
.altTimeFormat
!== null) {
939 altFormattedDateTime
+= $.datepicker
.formatTime(this._defaults
.altTimeFormat
, this, this._defaults
) + altTimeSuffix
;
942 altFormattedDateTime
+= this.formattedTime
+ altTimeSuffix
;
944 this.$altInput
.val(altFormattedDateTime
);
946 this.$input
.val(formattedDateTime
);
949 this.$input
.trigger("change");
952 _onFocus: function () {
953 if (!this.$input
.val() && this._defaults
.defaultValue
) {
954 this.$input
.val(this._defaults
.defaultValue
);
955 var inst
= $.datepicker
._getInst(this.$input
.get(0)),
956 tp_inst
= $.datepicker
._get(inst
, 'timepicker');
958 if (tp_inst
._defaults
.timeOnly
&& (inst
.input
.val() !== inst
.lastVal
)) {
960 $.datepicker
._updateDatepicker(inst
);
962 $.timepicker
.log(err
);
970 * Small abstraction to control types
971 * We can add more, just be sure to follow the pattern: create, options, value
976 create: function (tp_inst
, obj
, unit
, val
, min
, max
, step
) {
977 var rtl
= tp_inst
._defaults
.isRTL
; // if rtl go -60->0 instead of 0->60
978 return obj
.prop('slide', null).slider({
979 orientation
: "horizontal",
980 value
: rtl
? val
* -1 : val
,
981 min
: rtl
? max
* -1 : min
,
982 max
: rtl
? min
* -1 : max
,
984 slide: function (event
, ui
) {
985 tp_inst
.control
.value(tp_inst
, $(this), unit
, rtl
? ui
.value
* -1 : ui
.value
);
986 tp_inst
._onTimeChange();
988 stop: function (event
, ui
) {
989 tp_inst
._onSelectHandler();
993 options: function (tp_inst
, obj
, unit
, opts
, val
) {
994 if (tp_inst
._defaults
.isRTL
) {
995 if (typeof(opts
) === 'string') {
996 if (opts
=== 'min' || opts
=== 'max') {
997 if (val
!== undefined) {
998 return obj
.slider(opts
, val
* -1);
1000 return Math
.abs(obj
.slider(opts
));
1002 return obj
.slider(opts
);
1006 opts
.min
= opts
.max
= null;
1007 if (min
!== undefined) {
1008 opts
.max
= min
* -1;
1010 if (max
!== undefined) {
1011 opts
.min
= max
* -1;
1013 return obj
.slider(opts
);
1015 if (typeof(opts
) === 'string' && val
!== undefined) {
1016 return obj
.slider(opts
, val
);
1018 return obj
.slider(opts
);
1020 value: function (tp_inst
, obj
, unit
, val
) {
1021 if (tp_inst
._defaults
.isRTL
) {
1022 if (val
!== undefined) {
1023 return obj
.slider('value', val
* -1);
1025 return Math
.abs(obj
.slider('value'));
1027 if (val
!== undefined) {
1028 return obj
.slider('value', val
);
1030 return obj
.slider('value');
1035 create: function (tp_inst
, obj
, unit
, val
, min
, max
, step
) {
1036 var sel
= '<select class="ui-timepicker-select" data-unit="' + unit
+ '" data-min="' + min
+ '" data-max="' + max
+ '" data-step="' + step
+ '">',
1037 format
= tp_inst
._defaults
.pickerTimeFormat
|| tp_inst
._defaults
.timeFormat
;
1039 for (var i
= min
; i
<= max
; i
+= step
) {
1040 sel
+= '<option value="' + i
+ '"' + (i
=== val
? ' selected' : '') + '>';
1041 if (unit
=== 'hour') {
1042 sel
+= $.datepicker
.formatTime($.trim(format
.replace(/[^ht ]/ig, '')), {hour
: i
}, tp_inst
._defaults
);
1044 else if (unit
=== 'millisec' || unit
=== 'microsec' || i
>= 10) { sel
+= i
; }
1045 else {sel
+= '0' + i
.toString(); }
1050 obj
.children('select').remove();
1052 $(sel
).appendTo(obj
).change(function (e
) {
1053 tp_inst
._onTimeChange();
1054 tp_inst
._onSelectHandler();
1059 options: function (tp_inst
, obj
, unit
, opts
, val
) {
1061 $t
= obj
.children('select');
1062 if (typeof(opts
) === 'string') {
1063 if (val
=== undefined) {
1064 return $t
.data(opts
);
1069 return tp_inst
.control
.create(tp_inst
, obj
, $t
.data('unit'), $t
.val(), o
.min
|| $t
.data('min'), o
.max
|| $t
.data('max'), o
.step
|| $t
.data('step'));
1071 value: function (tp_inst
, obj
, unit
, val
) {
1072 var $t
= obj
.children('select');
1073 if (val
!== undefined) {
1085 * shorthand just to use timepicker.
1087 timepicker: function (o
) {
1089 var tmp_args
= Array
.prototype.slice
.call(arguments
);
1091 if (typeof o
=== 'object') {
1092 tmp_args
[0] = $.extend(o
, {
1097 return $(this).each(function () {
1098 $.fn
.datetimepicker
.apply($(this), tmp_args
);
1103 * extend timepicker to datepicker
1105 datetimepicker: function (o
) {
1107 var tmp_args
= arguments
;
1109 if (typeof(o
) === 'string') {
1110 if (o
=== 'getDate' || (o
=== 'option' && tmp_args
.length
=== 2 && typeof (tmp_args
[1]) === 'string')) {
1111 return $.fn
.datepicker
.apply($(this[0]), tmp_args
);
1113 return this.each(function () {
1115 $t
.datepicker
.apply($t
, tmp_args
);
1119 return this.each(function () {
1121 $t
.datepicker($.timepicker
._newInst($t
, o
)._defaults
);
1128 * Public Utility to parse date and time
1130 $.datepicker
.parseDateTime = function (dateFormat
, timeFormat
, dateTimeString
, dateSettings
, timeSettings
) {
1131 var parseRes
= parseDateTimeInternal(dateFormat
, timeFormat
, dateTimeString
, dateSettings
, timeSettings
);
1132 if (parseRes
.timeObj
) {
1133 var t
= parseRes
.timeObj
;
1134 parseRes
.date
.setHours(t
.hour
, t
.minute
, t
.second
, t
.millisec
);
1135 parseRes
.date
.setMicroseconds(t
.microsec
);
1138 return parseRes
.date
;
1142 * Public utility to parse time
1144 $.datepicker
.parseTime = function (timeFormat
, timeString
, options
) {
1145 var o
= extendRemove(extendRemove({}, $.timepicker
._defaults
), options
|| {}),
1146 iso8601
= (timeFormat
.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
1148 // Strict parse requires the timeString to match the timeFormat exactly
1149 var strictParse = function (f
, s
, o
) {
1151 // pattern for standard and localized AM/PM markers
1152 var getPatternAmpm = function (amNames
, pmNames
) {
1155 $.merge(markers
, amNames
);
1158 $.merge(markers
, pmNames
);
1160 markers
= $.map(markers
, function (val
) {
1161 return val
.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
1163 return '(' + markers
.join('|') + ')?';
1166 // figure out position of time elements.. cause js cant do named captures
1167 var getFormatPositions = function (timeFormat
) {
1168 var finds
= timeFormat
.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
1180 for (var i
= 0; i
< finds
.length
; i
++) {
1181 if (orders
[finds
[i
].toString().charAt(0)] === -1) {
1182 orders
[finds
[i
].toString().charAt(0)] = i
+ 1;
1189 var regstr
= '^' + f
.toString()
1190 .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match
) {
1191 var ml
= match
.length
;
1192 switch (match
.charAt(0).toLowerCase()) {
1194 return ml
=== 1 ? '(\\d?\\d)' : '(\\d{' + ml
+ '})';
1196 return ml
=== 1 ? '(\\d?\\d)' : '(\\d{' + ml
+ '})';
1198 return ml
=== 1 ? '(\\d?\\d)' : '(\\d{' + ml
+ '})';
1200 return '(\\d?\\d?\\d)';
1202 return '(\\d?\\d?\\d)';
1204 return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
1206 return getPatternAmpm(o
.amNames
, o
.pmNames
);
1207 default: // literal escaped in quotes
1208 return '(' + match
.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m
) { return "\\" + m
; }) + ')?';
1211 .replace(/\s/g, '\\s?') +
1213 order
= getFormatPositions(f
),
1217 treg
= s
.match(new RegExp(regstr
, 'i'));
1228 if (order
.t
!== -1) {
1229 if (treg
[order
.t
] === undefined || treg
[order
.t
].length
=== 0) {
1233 ampm
= $.inArray(treg
[order
.t
].toUpperCase(), o
.amNames
) !== -1 ? 'AM' : 'PM';
1234 resTime
.ampm
= o
[ampm
=== 'AM' ? 'amNames' : 'pmNames'][0];
1238 if (order
.h
!== -1) {
1239 if (ampm
=== 'AM' && treg
[order
.h
] === '12') {
1240 resTime
.hour
= 0; // 12am = 0 hour
1242 if (ampm
=== 'PM' && treg
[order
.h
] !== '12') {
1243 resTime
.hour
= parseInt(treg
[order
.h
], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
1245 resTime
.hour
= Number(treg
[order
.h
]);
1250 if (order
.m
!== -1) {
1251 resTime
.minute
= Number(treg
[order
.m
]);
1253 if (order
.s
!== -1) {
1254 resTime
.second
= Number(treg
[order
.s
]);
1256 if (order
.l
!== -1) {
1257 resTime
.millisec
= Number(treg
[order
.l
]);
1259 if (order
.c
!== -1) {
1260 resTime
.microsec
= Number(treg
[order
.c
]);
1262 if (order
.z
!== -1 && treg
[order
.z
] !== undefined) {
1263 resTime
.timezone
= $.timepicker
.timezoneOffsetNumber(treg
[order
.z
]);
1270 };// end strictParse
1272 // First try JS Date, if that fails, use strictParse
1273 var looseParse = function (f
, s
, o
) {
1275 var d
= new Date('2012-01-01 ' + s
);
1276 if (isNaN(d
.getTime())) {
1277 d
= new Date('2012-01-01T' + s
);
1278 if (isNaN(d
.getTime())) {
1279 d
= new Date('01/01/2012 ' + s
);
1280 if (isNaN(d
.getTime())) {
1281 throw "Unable to parse time with native Date: " + s
;
1288 minute
: d
.getMinutes(),
1289 second
: d
.getSeconds(),
1290 millisec
: d
.getMilliseconds(),
1291 microsec
: d
.getMicroseconds(),
1292 timezone
: d
.getTimezoneOffset() * -1
1297 return strictParse(f
, s
, o
);
1300 $.timepicker
.log("Unable to parse \ntimeString: " + s
+ "\ntimeFormat: " + f
);
1304 }; // end looseParse
1306 if (typeof o
.parse
=== "function") {
1307 return o
.parse(timeFormat
, timeString
, o
);
1309 if (o
.parse
=== 'loose') {
1310 return looseParse(timeFormat
, timeString
, o
);
1312 return strictParse(timeFormat
, timeString
, o
);
1316 * Public utility to format the time
1317 * @param {string} format format of the time
1318 * @param {Object} time Object not a Date for timezones
1319 * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
1320 * @returns {string} the formatted time
1322 $.datepicker
.formatTime = function (format
, time
, options
) {
1323 options
= options
|| {};
1324 options
= $.extend({}, $.timepicker
._defaults
, options
);
1334 var tmptime
= format
,
1335 ampmName
= options
.amNames
[0],
1336 hour
= parseInt(time
.hour
, 10);
1339 ampmName
= options
.pmNames
[0];
1342 tmptime
= tmptime
.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match
) {
1345 return ('0' + hour
).slice(-2);
1349 return ('0' + convert24to12(hour
)).slice(-2);
1351 return convert24to12(hour
);
1353 return ('0' + time
.minute
).slice(-2);
1357 return ('0' + time
.second
).slice(-2);
1361 return ('00' + time
.millisec
).slice(-3);
1363 return ('00' + time
.microsec
).slice(-3);
1365 return $.timepicker
.timezoneOffsetString(time
.timezone
=== null ? options
.timezone
: time
.timezone
, false);
1367 return $.timepicker
.timezoneOffsetString(time
.timezone
=== null ? options
.timezone
: time
.timezone
, true);
1369 return ampmName
.charAt(0).toUpperCase();
1371 return ampmName
.toUpperCase();
1373 return ampmName
.charAt(0).toLowerCase();
1375 return ampmName
.toLowerCase();
1377 return match
.replace(/'/g, "");
1385 * the bad hack :/ override datepicker so it doesn't close on select
1386 // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
1388 $.datepicker
._base_selectDate
= $.datepicker
._selectDate
;
1389 $.datepicker
._selectDate = function (id
, dateStr
) {
1390 var inst
= this._getInst($(id
)[0]),
1391 tp_inst
= this._get(inst
, 'timepicker');
1393 if (tp_inst
&& inst
.settings
.showTimepicker
) {
1394 tp_inst
._limitMinMaxDateTime(inst
, true);
1395 inst
.inline
= inst
.stay_open
= true;
1396 //This way the onSelect handler called from calendarpicker get the full dateTime
1397 this._base_selectDate(id
, dateStr
);
1398 inst
.inline
= inst
.stay_open
= false;
1399 this._notifyChange(inst
);
1400 this._updateDatepicker(inst
);
1402 this._base_selectDate(id
, dateStr
);
1407 * second bad hack :/ override datepicker so it triggers an event when changing the input field
1408 * and does not redraw the datepicker on every selectDate event
1410 $.datepicker
._base_updateDatepicker
= $.datepicker
._updateDatepicker
;
1411 $.datepicker
._updateDatepicker = function (inst
) {
1413 // don't popup the datepicker if there is another instance already opened
1414 var input
= inst
.input
[0];
1415 if ($.datepicker
._curInst
&& $.datepicker
._curInst
!== inst
&& $.datepicker
._datepickerShowing
&& $.datepicker
._lastInput
!== input
) {
1419 if (typeof(inst
.stay_open
) !== 'boolean' || inst
.stay_open
=== false) {
1421 this._base_updateDatepicker(inst
);
1423 // Reload the time control when changing something in the input text field.
1424 var tp_inst
= this._get(inst
, 'timepicker');
1426 tp_inst
._addTimePicker(inst
);
1432 * third bad hack :/ override datepicker so it allows spaces and colon in the input field
1434 $.datepicker
._base_doKeyPress
= $.datepicker
._doKeyPress
;
1435 $.datepicker
._doKeyPress = function (event
) {
1436 var inst
= $.datepicker
._getInst(event
.target
),
1437 tp_inst
= $.datepicker
._get(inst
, 'timepicker');
1440 if ($.datepicker
._get(inst
, 'constrainInput')) {
1441 var ampm
= tp_inst
.support
.ampm
,
1442 tz
= tp_inst
._defaults
.showTimezone
!== null ? tp_inst
._defaults
.showTimezone
: tp_inst
.support
.timezone
,
1443 dateChars
= $.datepicker
._possibleChars($.datepicker
._get(inst
, 'dateFormat')),
1444 datetimeChars
= tp_inst
._defaults
.timeFormat
.toString()
1445 .replace(/[hms]/g, '')
1446 .replace(/TT/g, ampm
? 'APM' : '')
1447 .replace(/Tt/g, ampm
? 'AaPpMm' : '')
1448 .replace(/tT/g, ampm
? 'AaPpMm' : '')
1449 .replace(/T
/g
, ampm
? 'AP' : '')
1450 .replace(/tt/g, ampm
? 'apm' : '')
1451 .replace(/t
/g
, ampm
? 'ap' : '') +
1452 " " + tp_inst
._defaults
.separator
+
1453 tp_inst
._defaults
.timeSuffix
+
1454 (tz
? tp_inst
._defaults
.timezoneList
.join('') : '') +
1455 (tp_inst
._defaults
.amNames
.join('')) + (tp_inst
._defaults
.pmNames
.join('')) +
1457 chr
= String
.fromCharCode(event
.charCode
=== undefined ? event
.keyCode
: event
.charCode
);
1458 return event
.ctrlKey
|| (chr
< ' ' || !dateChars
|| datetimeChars
.indexOf(chr
) > -1);
1462 return $.datepicker
._base_doKeyPress(event
);
1466 * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
1467 * Update any alternate field to synchronise with the main field.
1469 $.datepicker
._base_updateAlternate
= $.datepicker
._updateAlternate
;
1470 $.datepicker
._updateAlternate = function (inst
) {
1471 var tp_inst
= this._get(inst
, 'timepicker');
1473 var altField
= tp_inst
._defaults
.altField
;
1474 if (altField
) { // update alternate field too
1475 var altFormat
= tp_inst
._defaults
.altFormat
|| tp_inst
._defaults
.dateFormat
,
1476 date
= this._getDate(inst
),
1477 formatCfg
= $.datepicker
._getFormatConfig(inst
),
1478 altFormattedDateTime
= '',
1479 altSeparator
= tp_inst
._defaults
.altSeparator
? tp_inst
._defaults
.altSeparator
: tp_inst
._defaults
.separator
,
1480 altTimeSuffix
= tp_inst
._defaults
.altTimeSuffix
? tp_inst
._defaults
.altTimeSuffix
: tp_inst
._defaults
.timeSuffix
,
1481 altTimeFormat
= tp_inst
._defaults
.altTimeFormat
!== null ? tp_inst
._defaults
.altTimeFormat
: tp_inst
._defaults
.timeFormat
;
1483 altFormattedDateTime
+= $.datepicker
.formatTime(altTimeFormat
, tp_inst
, tp_inst
._defaults
) + altTimeSuffix
;
1484 if (!tp_inst
._defaults
.timeOnly
&& !tp_inst
._defaults
.altFieldTimeOnly
&& date
!== null) {
1485 if (tp_inst
._defaults
.altFormat
) {
1486 altFormattedDateTime
= $.datepicker
.formatDate(tp_inst
._defaults
.altFormat
, date
, formatCfg
) + altSeparator
+ altFormattedDateTime
;
1489 altFormattedDateTime
= tp_inst
.formattedDate
+ altSeparator
+ altFormattedDateTime
;
1492 $(altField
).val( inst
.input
.val() ? altFormattedDateTime
: "");
1496 $.datepicker
._base_updateAlternate(inst
);
1501 * Override key up event to sync manual input changes.
1503 $.datepicker
._base_doKeyUp
= $.datepicker
._doKeyUp
;
1504 $.datepicker
._doKeyUp = function (event
) {
1505 var inst
= $.datepicker
._getInst(event
.target
),
1506 tp_inst
= $.datepicker
._get(inst
, 'timepicker');
1509 if (tp_inst
._defaults
.timeOnly
&& (inst
.input
.val() !== inst
.lastVal
)) {
1511 $.datepicker
._updateDatepicker(inst
);
1513 $.timepicker
.log(err
);
1518 return $.datepicker
._base_doKeyUp(event
);
1522 * override "Today" button to also grab the time.
1524 $.datepicker
._base_gotoToday
= $.datepicker
._gotoToday
;
1525 $.datepicker
._gotoToday = function (id
) {
1526 var inst
= this._getInst($(id
)[0]),
1528 this._base_gotoToday(id
);
1529 var tp_inst
= this._get(inst
, 'timepicker');
1530 selectLocalTimezone(tp_inst
);
1531 var now
= new Date();
1532 this._setTime(inst
, now
);
1533 $('.ui-datepicker-today', $dp
).click();
1537 * Disable & enable the Time in the datetimepicker
1539 $.datepicker
._disableTimepickerDatepicker = function (target
) {
1540 var inst
= this._getInst(target
);
1545 var tp_inst
= this._get(inst
, 'timepicker');
1546 $(target
).datepicker('getDate'); // Init selected[Year|Month|Day]
1548 inst
.settings
.showTimepicker
= false;
1549 tp_inst
._defaults
.showTimepicker
= false;
1550 tp_inst
._updateDateTime(inst
);
1554 $.datepicker
._enableTimepickerDatepicker = function (target
) {
1555 var inst
= this._getInst(target
);
1560 var tp_inst
= this._get(inst
, 'timepicker');
1561 $(target
).datepicker('getDate'); // Init selected[Year|Month|Day]
1563 inst
.settings
.showTimepicker
= true;
1564 tp_inst
._defaults
.showTimepicker
= true;
1565 tp_inst
._addTimePicker(inst
); // Could be disabled on page load
1566 tp_inst
._updateDateTime(inst
);
1571 * Create our own set time function
1573 $.datepicker
._setTime = function (inst
, date
) {
1574 var tp_inst
= this._get(inst
, 'timepicker');
1576 var defaults
= tp_inst
._defaults
;
1578 // calling _setTime with no date sets time to defaults
1579 tp_inst
.hour
= date
? date
.getHours() : defaults
.hour
;
1580 tp_inst
.minute
= date
? date
.getMinutes() : defaults
.minute
;
1581 tp_inst
.second
= date
? date
.getSeconds() : defaults
.second
;
1582 tp_inst
.millisec
= date
? date
.getMilliseconds() : defaults
.millisec
;
1583 tp_inst
.microsec
= date
? date
.getMicroseconds() : defaults
.microsec
;
1585 //check if within min/max times..
1586 tp_inst
._limitMinMaxDateTime(inst
, true);
1588 tp_inst
._onTimeChange();
1589 tp_inst
._updateDateTime(inst
);
1594 * Create new public method to set only time, callable as $().datepicker('setTime', date)
1596 $.datepicker
._setTimeDatepicker = function (target
, date
, withDate
) {
1597 var inst
= this._getInst(target
);
1602 var tp_inst
= this._get(inst
, 'timepicker');
1605 this._setDateFromField(inst
);
1608 if (typeof date
=== "string") {
1609 tp_inst
._parseTime(date
, withDate
);
1610 tp_date
= new Date();
1611 tp_date
.setHours(tp_inst
.hour
, tp_inst
.minute
, tp_inst
.second
, tp_inst
.millisec
);
1612 tp_date
.setMicroseconds(tp_inst
.microsec
);
1614 tp_date
= new Date(date
.getTime());
1615 tp_date
.setMicroseconds(date
.getMicroseconds());
1617 if (tp_date
.toString() === 'Invalid Date') {
1618 tp_date
= undefined;
1620 this._setTime(inst
, tp_date
);
1627 * override setDate() to allow setting time too within Date object
1629 $.datepicker
._base_setDateDatepicker
= $.datepicker
._setDateDatepicker
;
1630 $.datepicker
._setDateDatepicker = function (target
, _date
) {
1631 var inst
= this._getInst(target
);
1637 if (typeof(_date
) === 'string') {
1638 date
= new Date(_date
);
1639 if (!date
.getTime()) {
1640 this._base_setDateDatepicker
.apply(this, arguments
);
1641 date
= $(target
).datepicker('getDate');
1645 var tp_inst
= this._get(inst
, 'timepicker');
1647 if (date
instanceof Date
) {
1648 tp_date
= new Date(date
.getTime());
1649 tp_date
.setMicroseconds(date
.getMicroseconds());
1654 // This is important if you are using the timezone option, javascript's Date
1655 // object will only return the timezone offset for the current locale, so we
1656 // adjust it accordingly. If not using timezone option this won't matter..
1657 // If a timezone is different in tp, keep the timezone as is
1658 if (tp_inst
&& tp_date
) {
1659 // look out for DST if tz wasn't specified
1660 if (!tp_inst
.support
.timezone
&& tp_inst
._defaults
.timezone
=== null) {
1661 tp_inst
.timezone
= tp_date
.getTimezoneOffset() * -1;
1663 date
= $.timepicker
.timezoneAdjust(date
, tp_inst
.timezone
);
1664 tp_date
= $.timepicker
.timezoneAdjust(tp_date
, tp_inst
.timezone
);
1667 this._updateDatepicker(inst
);
1668 this._base_setDateDatepicker
.apply(this, arguments
);
1669 this._setTimeDatepicker(target
, tp_date
, true);
1673 * override getDate() to allow getting time too within Date object
1675 $.datepicker
._base_getDateDatepicker
= $.datepicker
._getDateDatepicker
;
1676 $.datepicker
._getDateDatepicker = function (target
, noDefault
) {
1677 var inst
= this._getInst(target
);
1682 var tp_inst
= this._get(inst
, 'timepicker');
1685 // if it hasn't yet been defined, grab from field
1686 if (inst
.lastVal
=== undefined) {
1687 this._setDateFromField(inst
, noDefault
);
1690 var date
= this._getDate(inst
);
1691 if (date
&& tp_inst
._parseTime($(target
).val(), tp_inst
.timeOnly
)) {
1692 date
.setHours(tp_inst
.hour
, tp_inst
.minute
, tp_inst
.second
, tp_inst
.millisec
);
1693 date
.setMicroseconds(tp_inst
.microsec
);
1695 // This is important if you are using the timezone option, javascript's Date
1696 // object will only return the timezone offset for the current locale, so we
1697 // adjust it accordingly. If not using timezone option this won't matter..
1698 if (tp_inst
.timezone
!= null) {
1699 // look out for DST if tz wasn't specified
1700 if (!tp_inst
.support
.timezone
&& tp_inst
._defaults
.timezone
=== null) {
1701 tp_inst
.timezone
= date
.getTimezoneOffset() * -1;
1703 date
= $.timepicker
.timezoneAdjust(date
, tp_inst
.timezone
);
1708 return this._base_getDateDatepicker(target
, noDefault
);
1712 * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
1713 * An option in datapicker to ignore extra format characters would be nicer.
1715 $.datepicker
._base_parseDate
= $.datepicker
.parseDate
;
1716 $.datepicker
.parseDate = function (format
, value
, settings
) {
1719 date
= this._base_parseDate(format
, value
, settings
);
1721 // Hack! The error message ends with a colon, a space, and
1722 // the "extra" characters. We rely on that instead of
1723 // attempting to perfectly reproduce the parsing algorithm.
1724 if (err
.indexOf(":") >= 0) {
1725 date
= this._base_parseDate(format
, value
.substring(0, value
.length
- (err
.length
- err
.indexOf(':') - 2)), settings
);
1726 $.timepicker
.log("Error parsing the date string: " + err
+ "\ndate string = " + value
+ "\ndate format = " + format
);
1735 * override formatDate to set date with time to the input
1737 $.datepicker
._base_formatDate
= $.datepicker
._formatDate
;
1738 $.datepicker
._formatDate = function (inst
, day
, month
, year
) {
1739 var tp_inst
= this._get(inst
, 'timepicker');
1741 tp_inst
._updateDateTime(inst
);
1742 return tp_inst
.$input
.val();
1744 return this._base_formatDate(inst
);
1748 * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
1750 $.datepicker
._base_optionDatepicker
= $.datepicker
._optionDatepicker
;
1751 $.datepicker
._optionDatepicker = function (target
, name
, value
) {
1752 var inst
= this._getInst(target
),
1758 var tp_inst
= this._get(inst
, 'timepicker');
1763 overrides
= tp_inst
._defaults
.evnts
,
1766 if (typeof name
=== 'string') { // if min/max was set with the string
1767 if (name
=== 'minDate' || name
=== 'minDateTime') {
1769 } else if (name
=== 'maxDate' || name
=== 'maxDateTime') {
1771 } else if (name
=== 'onSelect') {
1773 } else if (overrides
.hasOwnProperty(name
)) {
1774 if (typeof (value
) === 'undefined') {
1775 return overrides
[name
];
1778 name_clone
= {}; //empty results in exiting function after overrides updated
1780 } else if (typeof name
=== 'object') { //if min/max was set with the JSON
1783 } else if (name
.minDateTime
) {
1784 min
= name
.minDateTime
;
1785 } else if (name
.maxDate
) {
1787 } else if (name
.maxDateTime
) {
1788 max
= name
.maxDateTime
;
1790 for (prop
in overrides
) {
1791 if (overrides
.hasOwnProperty(prop
) && name
[prop
]) {
1792 fns
[prop
] = name
[prop
];
1797 if (fns
.hasOwnProperty(prop
)) {
1798 overrides
[prop
] = fns
[prop
];
1799 if (!name_clone
) { name_clone
= $.extend({}, name
); }
1800 delete name_clone
[prop
];
1803 if (name_clone
&& isEmptyObject(name_clone
)) { return; }
1804 if (min
) { //if min was set
1808 min
= new Date(min
);
1810 tp_inst
._defaults
.minDate
= min
;
1811 tp_inst
._defaults
.minDateTime
= min
;
1812 } else if (max
) { //if max was set
1816 max
= new Date(max
);
1818 tp_inst
._defaults
.maxDate
= max
;
1819 tp_inst
._defaults
.maxDateTime
= max
;
1820 } else if (onselect
) {
1821 tp_inst
._defaults
.onSelect
= onselect
;
1824 if (value
=== undefined) {
1825 return this._base_optionDatepicker
.call($.datepicker
, target
, name
);
1827 return this._base_optionDatepicker
.call($.datepicker
, target
, name_clone
|| name
, value
);
1831 * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
1832 * it will return false for all objects
1834 var isEmptyObject = function (obj
) {
1837 if (obj
.hasOwnProperty(prop
)) {
1845 * jQuery extend now ignores nulls!
1847 var extendRemove = function (target
, props
) {
1848 $.extend(target
, props
);
1849 for (var name
in props
) {
1850 if (props
[name
] === null || props
[name
] === undefined) {
1851 target
[name
] = props
[name
];
1858 * Determine by the time format which units are supported
1859 * Returns an object of booleans for each unit
1861 var detectSupport = function (timeFormat
) {
1862 var tf
= timeFormat
.replace(/'.*?'/g, '').toLowerCase(), // removes literals
1863 isIn = function (f
, t
) { // does the format contain the token?
1864 return f
.indexOf(t
) !== -1 ? true : false;
1867 hour
: isIn(tf
, 'h'),
1868 minute
: isIn(tf
, 'm'),
1869 second
: isIn(tf
, 's'),
1870 millisec
: isIn(tf
, 'l'),
1871 microsec
: isIn(tf
, 'c'),
1872 timezone
: isIn(tf
, 'z'),
1873 ampm
: isIn(tf
, 't') && isIn(timeFormat
, 'h'),
1874 iso8601
: isIn(timeFormat
, 'Z')
1879 * Converts 24 hour format into 12 hour
1880 * Returns 12 hour without leading 0
1882 var convert24to12 = function (hour
) {
1889 return String(hour
);
1892 var computeEffectiveSetting = function (settings
, property
) {
1893 return settings
&& settings
[property
] ? settings
[property
] : $.timepicker
._defaults
[property
];
1897 * Splits datetime string into date and time substrings.
1898 * Throws exception when date can't be parsed
1899 * Returns {dateString: dateString, timeString: timeString}
1901 var splitDateTime = function (dateTimeString
, timeSettings
) {
1902 // The idea is to get the number separator occurrences in datetime and the time format requested (since time has
1903 // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
1904 var separator
= computeEffectiveSetting(timeSettings
, 'separator'),
1905 format
= computeEffectiveSetting(timeSettings
, 'timeFormat'),
1906 timeParts
= format
.split(separator
), // how many occurrences of separator may be in our format?
1907 timePartsLen
= timeParts
.length
,
1908 allParts
= dateTimeString
.split(separator
),
1909 allPartsLen
= allParts
.length
;
1911 if (allPartsLen
> 1) {
1913 dateString
: allParts
.splice(0, allPartsLen
- timePartsLen
).join(separator
),
1914 timeString
: allParts
.splice(0, timePartsLen
).join(separator
)
1919 dateString
: dateTimeString
,
1925 * Internal function to parse datetime interval
1926 * Returns: {date: Date, timeObj: Object}, where
1927 * date - parsed date without time (type Date)
1928 * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
1930 var parseDateTimeInternal = function (dateFormat
, timeFormat
, dateTimeString
, dateSettings
, timeSettings
) {
1935 parts
= splitDateTime(dateTimeString
, timeSettings
);
1936 date
= $.datepicker
._base_parseDate(dateFormat
, parts
.dateString
, dateSettings
);
1938 if (parts
.timeString
=== '') {
1944 parsedTime
= $.datepicker
.parseTime(timeFormat
, parts
.timeString
, timeSettings
);
1947 throw 'Wrong time format';
1957 * Internal function to set timezone_select to the local timezone
1959 var selectLocalTimezone = function (tp_inst
, date
) {
1960 if (tp_inst
&& tp_inst
.timezone_select
) {
1961 var now
= date
|| new Date();
1962 tp_inst
.timezone_select
.val(-now
.getTimezoneOffset());
1967 * Create a Singleton Instance
1969 $.timepicker
= new Timepicker();
1972 * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
1973 * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
1974 * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
1977 $.timepicker
.timezoneOffsetString = function (tzMinutes
, iso8601
) {
1978 if (isNaN(tzMinutes
) || tzMinutes
> 840 || tzMinutes
< -720) {
1982 var off
= tzMinutes
,
1984 hours
= (off
- minutes
) / 60,
1985 iso
= iso8601
? ':' : '',
1986 tz
= (off
>= 0 ? '+' : '-') + ('0' + Math
.abs(hours
)).slice(-2) + iso
+ ('0' + Math
.abs(minutes
)).slice(-2);
1988 if (tz
=== '+00:00') {
1995 * Get the number in minutes that represents a timezone string
1996 * @param {string} tzString formatted like "+0500", "-1245", "Z"
1997 * @return {number} the offset minutes or the original string if it doesn't match expectations
1999 $.timepicker
.timezoneOffsetNumber = function (tzString
) {
2000 var normalized
= tzString
.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
2002 if (normalized
.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
2006 if (!/^(\-|\+)\d{4}$/.test(normalized
)) { // possibly a user defined tz, so just give it back
2010 return ((normalized
.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
2011 ((parseInt(normalized
.substr(1, 2), 10) * 60) + // hours (converted to minutes)
2012 parseInt(normalized
.substr(3, 2), 10))); // minutes
2016 * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
2017 * @param {Date} date
2018 * @param {string} toTimezone formatted like "+0500", "-1245"
2021 $.timepicker
.timezoneAdjust = function (date
, toTimezone
) {
2022 var toTz
= $.timepicker
.timezoneOffsetNumber(toTimezone
);
2024 date
.setMinutes(date
.getMinutes() + -date
.getTimezoneOffset() - toTz
);
2030 * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
2031 * enforce date range limits.
2032 * n.b. The input value must be correctly formatted (reformatting is not supported)
2033 * @param {Element} startTime
2034 * @param {Element} endTime
2035 * @param {Object} options Options for the timepicker() call
2038 $.timepicker
.timeRange = function (startTime
, endTime
, options
) {
2039 return $.timepicker
.handleRange('timepicker', startTime
, endTime
, options
);
2043 * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
2044 * enforce date range limits.
2045 * @param {Element} startTime
2046 * @param {Element} endTime
2047 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2048 * a boolean value that can be used to reformat the input values to the `dateFormat`.
2049 * @param {string} method Can be used to specify the type of picker to be added
2052 $.timepicker
.datetimeRange = function (startTime
, endTime
, options
) {
2053 $.timepicker
.handleRange('datetimepicker', startTime
, endTime
, options
);
2057 * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
2058 * enforce date range limits.
2059 * @param {Element} startTime
2060 * @param {Element} endTime
2061 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2062 * a boolean value that can be used to reformat the input values to the `dateFormat`.
2065 $.timepicker
.dateRange = function (startTime
, endTime
, options
) {
2066 $.timepicker
.handleRange('datepicker', startTime
, endTime
, options
);
2070 * Calls `method` on the `startTime` and `endTime` elements, and configures them to
2071 * enforce date range limits.
2072 * @param {string} method Can be used to specify the type of picker to be added
2073 * @param {Element} startTime
2074 * @param {Element} endTime
2075 * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
2076 * a boolean value that can be used to reformat the input values to the `dateFormat`.
2079 $.timepicker
.handleRange = function (method
, startTime
, endTime
, options
) {
2080 options
= $.extend({}, {
2081 minInterval
: 0, // min allowed interval in milliseconds
2082 maxInterval
: 0, // max allowed interval in milliseconds
2083 start
: {}, // options for start picker
2084 end
: {} // options for end picker
2087 // for the mean time this fixes an issue with calling getDate with timepicker()
2088 var timeOnly
= false;
2089 if(method
=== 'timepicker'){
2091 method
= 'datetimepicker';
2094 function checkDates(changed
, other
) {
2095 var startdt
= startTime
[method
]('getDate'),
2096 enddt
= endTime
[method
]('getDate'),
2097 changeddt
= changed
[method
]('getDate');
2099 if (startdt
!== null) {
2100 var minDate
= new Date(startdt
.getTime()),
2101 maxDate
= new Date(startdt
.getTime());
2103 minDate
.setMilliseconds(minDate
.getMilliseconds() + options
.minInterval
);
2104 maxDate
.setMilliseconds(maxDate
.getMilliseconds() + options
.maxInterval
);
2106 if (options
.minInterval
> 0 && minDate
> enddt
) { // minInterval check
2107 endTime
[method
]('setDate', minDate
);
2109 else if (options
.maxInterval
> 0 && maxDate
< enddt
) { // max interval check
2110 endTime
[method
]('setDate', maxDate
);
2112 else if (startdt
> enddt
) {
2113 other
[method
]('setDate', changeddt
);
2118 function selected(changed
, other
, option
) {
2119 if (!changed
.val()) {
2122 var date
= changed
[method
].call(changed
, 'getDate');
2123 if (date
!== null && options
.minInterval
> 0) {
2124 if (option
=== 'minDate') {
2125 date
.setMilliseconds(date
.getMilliseconds() + options
.minInterval
);
2127 if (option
=== 'maxDate') {
2128 date
.setMilliseconds(date
.getMilliseconds() - options
.minInterval
);
2132 other
[method
].call(other
, 'option', option
, date
);
2136 $.fn
[method
].call(startTime
, $.extend({
2138 onClose: function (dateText
, inst
) {
2139 checkDates($(this), endTime
);
2141 onSelect: function (selectedDateTime
) {
2142 selected($(this), endTime
, 'minDate');
2144 }, options
, options
.start
));
2145 $.fn
[method
].call(endTime
, $.extend({
2147 onClose: function (dateText
, inst
) {
2148 checkDates($(this), startTime
);
2150 onSelect: function (selectedDateTime
) {
2151 selected($(this), startTime
, 'maxDate');
2153 }, options
, options
.end
));
2155 checkDates(startTime
, endTime
);
2156 selected(startTime
, endTime
, 'minDate');
2157 selected(endTime
, startTime
, 'maxDate');
2158 return $([startTime
.get(0), endTime
.get(0)]);
2162 * Log error or data to the console during error or debugging
2163 * @param {Object} err pass any type object to log to the console during error or debugging
2166 $.timepicker
.log = function (err
) {
2167 if (window
.console
) {
2168 window
.console
.log(err
);
2173 * Add util object to allow access to private methods for testability.
2175 $.timepicker
._util
= {
2176 _extendRemove
: extendRemove
,
2177 _isEmptyObject
: isEmptyObject
,
2178 _convert24to12
: convert24to12
,
2179 _detectSupport
: detectSupport
,
2180 _selectLocalTimezone
: selectLocalTimezone
,
2181 _computeEffectiveSetting
: computeEffectiveSetting
,
2182 _splitDateTime
: splitDateTime
,
2183 _parseDateTimeInternal
: parseDateTimeInternal
2187 * Microsecond support
2189 if (!Date
.prototype.getMicroseconds
) {
2190 Date
.prototype.microseconds
= 0;
2191 Date
.prototype.getMicroseconds = function () { return this.microseconds
; };
2192 Date
.prototype.setMicroseconds = function (m
) {
2193 this.setMilliseconds(this.getMilliseconds() + Math
.floor(m
/ 1000));
2194 this.microseconds
= m
% 1000;
2200 * Keep up with the version
2202 $.timepicker
.version
= "1.4.5";