Using a jQuery UI Slider to Select a Time Range

Recently I was trying to create a web form where a user could enter a start time and end time to create a time window for a schedule. However, the easiest solution – having a user enter the times into two text boxes – seemed clunky and annoying to use. I wanted a better solution that was more intuitive so I decided to try using the jQuery UI Slider for a more visual experience with less typing. My goal was to have a slider with two points to represent the beginning and end of a scheduled time range and to display the value of each point as text.

If you haven’t used jQuery UI before, the slider itself is pretty simple to setup:

<div id="slider-range"></div>
<script type="text/javascript">
	$("#slider-range").slider({
		range: true,
		min: 0,
		max: 1439,
		values: [540, 1020],
		step:5
	});
</script>


View this demo in a new window


This sets a few options for the slider: it is a range between two points, has a value range from 0-1439 (which will later be converted to 12:00 AM to 11:59 PM), and initial values of 9:00 AM (540) and 5:00 PM (1020).

From this point, I needed to read the values from each slider, convert it to a time, and output it to the screen.

<div id="slider-range"></div>
<span id="time"></span>
</script>
<script type="text/javascript">
	$("#slider-range").slider({
		range: true,
		min: 0,
		max: 1439,
		values: [540, 1020],
		slide: slideTime
	});

Here I added a span element to display the time selected using the slider. Then I updated the slider initialization to include instructions on what to do when a slide event fires. A slide event fires for every mouse move during a slide, which is perfect for what I want.

	function slideTime(event, ui){
		var val0 = $("#slider-range").slider("values", 0),
			val1 = $("#slider-range").slider("values", 1),
			minutes0 = parseInt(val0 % 60, 10),
			hours0 = parseInt(val0 / 60 % 24, 10),
			minutes1 = parseInt(val1 % 60, 10),
			hours1 = parseInt(val1 / 60 % 24, 10);
		startTime = getTime(hours0, minutes0);
		endTime = getTime(hours1, minutes1);
		$("#time").text(startTime + ' - ' + endTime);
	}
	function getTime(hours, minutes) {
		var time = null;
		minutes = minutes + "";
		if (hours < 12) {
			time = "AM";
		}
		else {
			time = "PM";
		}
		if (hours == 0) {
			hours = 12;
		}
		if (hours > 12) {
			hours = hours - 12;
		}
		if (minutes.length == 1) {
			minutes = "0" + minutes;
		}
		return hours + ":" + minutes + " " + time;
	}
	slideTime();


View this demo in a new window

Next I added two JavaScript functions, getTime and slideTime. The function getTime grabs the values of each slider point and parses out the hours and minutes using either division or modulo. Those values are then passed to the getTime function. getTime uses some simple logic to format those times for output including recognizing AM vs PM and correcting minutes without a second digit (9:0 instead of 9:00). After the time is formatted correctly, I use the .text() function to set the value of the #time span element.

This worked great so far, but if I wanted to set a schedule it only allowed me to go in one direction (8:00 PM to 5:00 PM but not 5:00 PM to 8:00 AM). To fix this I doubled the length of the bar, but it also allowed the user to select a window of more than 24 hours. To prevent this from happening, I added a new function: checkMax.

<style>
	#slider-range,#SlideMax{width:400px;}
	#slider-range,#time, #SlideMax, table{margin:10px;display:block;}
</style>
<div id="slider-range"></div>
<span id="SlideMax"></span>
<br />
<span id="time"></span>
<input type="submit" name="scheduleSubmit" value="Submit" id="scheduleSubmit" class="ui-button ui-state-default ui-corner-all"/>
<table id="Schedule">
	<thead>
		<tr>
			<th>Start Time</th>
			<th>End Time</th>
			</tr>
	</thead>
	<tbody>
	</tbody>
</table>

I added a few new html elements here including #SlideMax, which is where the warnings will be displayed and the table #Schedule to display scheduled times, and the button #scheduleSubmit.

	var startTime;
	var endTime;
	$("#slider-range").slider({
		range: true, min: 0, max: 2879, values: [540, 1020], step:5, slide: slideTime, change: checkMax
	});

In the initialization, I changed the range to 0-2879 in order to account for two 24 hour periods, and I added a handler checkMax. Also, to make things a little simpler I added a step option so that the slider will move only in increments of 5 minutes

	function slideTime(event, ui){
		var val0 = $("#slider-range").slider("values", 0),
			val1 = $("#slider-range").slider("values", 1),
			minutes0 = parseInt(val0 % 60, 10),
			hours0 = parseInt(val0 / 60 % 24, 10),
			minutes1 = parseInt(val1 % 60, 10),
			hours1 = parseInt(val1 / 60 % 24, 10);
		startTime = getTime(hours0, minutes0);
		endTime = getTime(hours1, minutes1);
		$("#time").text(startTime + ' - ' + endTime);
	}
	function getTime(hours, minutes) {
		var time = null;
		minutes = minutes + "";
		if (hours < 12) {time = "AM";}
		else {	time = "PM";}
		if (hours == 0) {hours = 12;}
		if (hours > 12) {hours = hours - 12;	}
		if (minutes.length == 1) {minutes = "0" + minutes;}
		return hours + ":" + minutes + " " + time;
	}
	function checkMax() {
		var size = $("#slider-range").slider("values", 1) - $("#slider-range").slider("values", 0);
		if( size >= 1435) {
			$("#slider-range div")
				.addClass("ui-state-error")
				.removeClass("ui-widget-header");
			$("#scheduleSubmit")
				.attr("disabled","disabled")
				.addClass("ui-state-disabled")
				.removeClass("ui-state-default");
			$("#SlideMax").text("Cannot be more than 24 hours");
		}
		else {
			$("#slider-range div")
				.addClass("ui-widget-header")
				.removeClass("ui-state-error");
			$("#scheduleSubmit")
				.removeAttr("disabled")
				.addClass("ui-state-default")
				.removeClass("ui-state-disabled");
			$("#SlideMax").text("");
		}
	}
	$("#scheduleSubmit").on('click', function(){
		console.log(startTime);
		console.log(endTime);
		$('#Schedule tbody').append('<tr>' +
			'<td>' + startTime + '</td>' +
			'<td>' + endTime + '</td>' +
			'</tr>');
	});
	slideTime();


View this demo in a new window

At the end I added two more functions, add and checkMax. The function add simply adds a row to that table with the start and end times when the #scheduleSubmit button is clicked. A change event is fired whenever the slider stops moving, and then calls the function checkMax. In checkMax, the two values are subtracted to ensure that they are less than 24 hours apart. If they are too far apart, the #scheduleSubmit button is disabled and a message is displayed in #SlideMax. In addition, the css states are changed on the slider and #scheduleSubmit to let the user know something is different.

So that’s it, a simple solution to use the jQuery UI slider to display time ranges. This can be easily adapted to use for just a single time selection by just removing the “range: true” option from the initialization.

Edit – Continued with  Revisiting the jQuery UI Time Slider

32 thoughts on “Using a jQuery UI Slider to Select a Time Range

  1. Thanks just what I was looking for. Works a treat.

    I modified the getTime function to show the time in 24 hour format allowing for adding to date/time fields in a database.

    function getTime(hours, minutes) {
    var time = null;
    minutes = minutes + “”;

    return hours + “:” + minutes;
    }

  2. I think this is a better way for the slideTime function to retrieve accurate values:

    function slideTime(event, ui){
    var minutes0 = parseInt(ui.values[0] % 60);
    var hours0 = parseInt(ui.values[0] / 60 % 24);
    var minutes1 = parseInt(ui.values[1] % 60);
    var hours1 = parseInt(ui.values[1] / 60 % 24);
    startTime = getTime(hours0, minutes0);
    endTime = getTime(hours1, minutes1);
    $(“#time”).text(startTime + ‘ – ‘ + endTime);
    }

    $(“#slider-range”).slider(“values”, 0) replaced with ui.values[0]
    $(“#slider-range”).slider(“values”, 1) replaced with ui.values[1]

    Thanks for the post!

  3. Why not to simply convert the number of minutes into milliseconds (*60*1000) and create a native instance of a Date class.

    function formatTime(milliseconds)
    {
    var from = new Date(time);

    var hourTime = (from.getHours().toString().length == 1)?”0″ + from.getHours().toString():from.getHours().toString();
    var minuTime = (from.getMinutes().toString().length == 1)?”0″ + from.getMinutes().toString():from.getMinutes().toString();

    return hourTime + “:” + minuTime;
    }

  4. Thanks for this great example.

    Is there a way to make this draggable? Specifically, I’d like to be abel to grab the section of the timeline between the handles and drag both handles to a new location.

  5. Thanks for that.

    I’ve updated your 48h-source to a plugin: What is 1435 in line 51?

    Kind regards from Germany, icro.

  6. Hey icro,

    1435 = (24 hours * 60 minutes) – 5 minute interval. This is used to ensure that the time interval is less than 24 hours.

    Marc

  7. Everything I learned about web dev and programming I’ve learned from people like you who share their great work online. Thanks so much!!!!

  8. Pingback: Revisiting the jQuery UI Time Slider | Marc Neuwirth's Blog

  9. Pingback: Time span sliders in jQuery « David's Tech Blog

  10. Unfortunately the ability to drag the slider doesn’t work in IE9. Tried it on 2 different PCs running Win 7 64bit. :-(

  11. Found a bug… don’t know if it’s only my implementation, but solved by using ui.value into the function slideTime.

    I’m not using range, but my SOLVED code is this:
    $(“#slider-range”).slider({
    min: 450,
    value: 465,
    max: 990,
    step: 15,
    slide: function slideTime(event, ui){
    var minutes0 = parseInt(ui.value % 60);
    var hours0 = parseInt(ui.value / 60 % 24);
    Time = getTime(hours0, minutes0);
    $(“#time”).text(Time + ‘ – ‘ +ui.value);
    }
    });

  12. I updated the example code to the latest versions of jQuery and jQuery UI to 1.7.1 and 1.8.18 respectively. That seems to fix the ie9 issue for me, let me know if that helps

  13. Marc,

    When I’m trying the example above in Internet Explorer / Firefox I’m experiencing some problems. When I want to pick a time range for example:
    08.00 AM till 11.00 AM, first I select 08.00 AM
    After that I try to select 11.00 AM, however then my first slider moves till 8.10 AM?
    When I try to put it back then the 11.00 AM slider moves again.

    Is this a known bug or does anyone know a solution for this?

    Thanks in advance,
    Peter

  14. Have the same bug as Peter said.
    Found it in IE10.0.8250.0, Opera 12.02 and Chrome 21.0.1180.89 m – other words, in all browsers.

    wrong values come from:
    $(“#slider-range”).slider(“values”, 0)
    $(“#slider-range”).slider(“values”, 1)

    But the bug is still going on, if I update jQuery to 1.8.0 and jQuery-UI to 1.8.23

    When I stop drag first slider and making first drag step on second slider – jQuery tells me that I`m still dragging the first one. May be it is a bug in JQuery-UI Slider?

  15. Thanks for the code. by the way does anyone know how to directly save the start time and end time to my sql database?
    All I know is php and I’m very new to jquery

  16. This is awesome, but I have a problem in the slider range .. the 2 buttons that increment or decrements the value is too big “width” it fills the slider .. ???
    Please help, and thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *