Raymond Camden's Blog Rss

Ask a Jedi: Formatting times client side

2

Posted in JavaScript | Posted on 10-27-2009 | 3,067 views

Patricks asks:

Having an interesting dilemma that I cannot seem to come up with a working solution to. I have a text box that we need people to enter a time into. I dont want it to be a mask but rather onBlur the string "completes" with the proper format. For example, the user enters 3:29.2 for their time, onBlur the result needs to be 00:03:29.20. Or the user enters 4.6, onblur should result in 00:00:04.60. Just curious if you could point me in the right direction or come up with a demo, I think this would be very useful to many folks as a blog entry.

So let me state right off - I really don't like formatting in JavaScript. If I'm doing any kind of Ajax development and need the data to look nice, I will almost always do the formatting in ColdFusion first. ColdFusion has spoiled me, what can I say? So please keep that in mind when reviewing my solution. There are probably a hundred different ways to do this (better) but hopefully this will be helpful anyway.

For my solution, I decided to do something a bit different. Instead of building a form and using the onblur as Patrick wanted, I thought I'd build something like a test script. The idea would be that I could provide an array of inputs and when the page loaded, it would run through them all and output the results. Here is what I came up with initially.

view plain print about
1<h2>Tests</h2>
2<div id="testDiv"></div>
3
4<script>
5var myarea = document.getElementById("testDiv")
6var tests = ["2.2","3:29.2"]
7
8for(var i=0;i<tests.length;i++) {
9    myarea.innerHTML += "<br/>" + tests[i] + " = " + formatTime(tests[i])    
10}
11
12function formatTime(t) {
13    return t
14}
15</script>

I create a simple div on top. The JavaScript section begins by creating a pointer to it. The tests array represent all my inputs. Next I loop over the inputs and add to the div the initial value and the result of the format. As you can see, the format does nothing now. I ran this and got the following output:

Nice and simple. But the point is - I can easily then add more inputs and test the output to ensure my function works correctly. So now for the actual formatting - and again - consider this code rough - I know it could be improved:

view plain print about
1function formatTime(t) {
2    //Desired result is hh:mm:ss.MM
3    //Check for ., if not dot, assume it is just the seconds or more portion
4    var ms = "00"
5    if(t.indexOf(".") != -1) ms = t.split(".")[1]
6
7    var time = t.split(".")[0]
8    //so ms should be ok as is, but time may not be
9    var items = time.split(":")
10    
11    //loop over length of size - 3
12    var toAdd = 3-items.length
13    for(var i=1; i <= toAdd; i++) {
14        items.unshift("00")
15    }
16
17    //now fix each item - if size of the item is 1, prepend with 0
18    for(var i=0; i < items.length; i++) {
19        if(items[i].length == 1) items[i] = "0" + items[i]
20    }
21
22    var timeStr = items.join(":")
23    return timeStr + "." + ms
24}

I begin by grabbing the millisecond portion of the input - if it exists. The split function is a nice way to treat a JavaScript string like a ColdFusion list. The right side portion of the input is the hours, minutes, and seconds. Since a user may enter only seconds, or maybe only minutes and seconds, I may need to "pad" my data. So I split that portion on the colon character and if the size is less than three, I enter some blank values into the array. By the way, don't make the mistake I did:

view plain print about
1for(var i=1; i <= (3-items.length); i++) {
2    items.unshift("00")
3}

Can you guess why that failed?

Anyway, the next step was to convert any single character value, like "3", into a fuller "03" string. Finally I can convert the array back into a string using join. Here is the complete test script with some additional inputs. As you can imagine, this version was not the first version I sent him. As he sent back bugs, I simply entered his inputs and updated the function:

view plain print about
1<h2>Tests</h2>
2<div id="testDiv"></div>
3
4<script>
5var myarea = document.getElementById("testDiv")
6var tests = ["2.2","3:29.2","4.6","3","03:22:10.4"]
7
8for(var i=0;i<tests.length;i++) {
9    myarea.innerHTML += "<br/>" + tests[i] + " = " + formatTime(tests[i])    
10}
11
12function formatTime(t) {
13    //Desired result is hh:mm:ss.MM
14    //Check for ., if not dot, assume it is just the seconds or more portion
15    var ms = "00"
16    if(t.indexOf(".") != -1) ms = t.split(".")[1]
17
18    var time = t.split(".")[0]
19    //so ms should be ok as is, but time may not be
20    var items = time.split(":")
21    
22    //loop over length of size - 3
23    var toAdd = 3-items.length
24    for(var i=1; i <= toAdd; i++) {
25        items.unshift("00")
26    }
27
28    //now fix each item - if size of the item is 1, prepend with 0
29    for(var i=0; i < items.length; i++) {
30        if(items[i].length == 1) items[i] = "0" + items[i]
31    }
32
33    var timeStr = items.join(":")
34    return timeStr + "." + ms
35}
36</script>

And the output:

Comments

[Add Comment] [Subscribe to Comments]

Matt Kruse also has some tried and true JS Date libraries that I've used for a few years and have served me well.

http://www.javascripttoolbox.com/
Another javascript date library: http://www.datejs.com