Solved

Calculate difference between 2 durations

Posted on 2016-08-18
11
55 Views
Last Modified: 2016-08-22
I have a web page where the user can enter times - such as "34.56" (34 seconds, 56 hundredths), "1:07.32" (1 minute, 7 seconds, 32 hundredths), up to 59:59.99.

For each input field there is a defined "Minimum" and "Maximum" allowed time, in the same format as above.

I want to validate that the entered time is within the Minimum / Maximum time range.

I am trying to use the "duration" feature in moment.js - but I can't get it to work, nor can I find enough information about "durations".

I have this:

        
$('.timeInput').blur(function () {
    var enteredVal = $(this).val();
    if (enteredVal == '') return;

    var mReq = moment.duration("40.99");
    var mEnteredVal = moment.duration(enteredVal);
    var timeDiff = mEnteredVal.asMilliseconds - mReq.asMilliseconds;

    if (timeDiff > 0) {
        alert("Greater than");
    } else {
        alert("Less Than");
    }
}

Open in new window


However, it doesn't work. The above is a test version that just checks if the entered time is greater than the mReq value. Once I've got that working, I will extend it to check the time is within the min / max values.

The min and max values will eventually come from hidden fields on the page.
0
Comment
Question by:ascendinternet
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
11 Comments
 
LVL 53

Expert Comment

by:Scott Fell, EE MVE
ID: 41762011
First, make sure your spelling is exact and also your closing brackets match.  I don't think yours did and that may be from copy/pasting.

  1. Convert input to a number
  2. Declare variable you want to test against
  3. Use duration of minutes
  4. Compare entered value against your test variable

http://jsbin.com/sozifuxavo/edit?html,output
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  <input class="timeInput" placeholder="TimeInput">
  <input>
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<script src="https://cdn.jsdelivr.net/momentjs/2.14.1/moment-with-locales.min.js"></script>
<script>
  $(function(){ 
  $('.timeInput').blur(function () {
    var enteredVal = $(this).val();
    enteredVal = Number(enteredVal); // convert tonumber
    var testVal = moment.duration(49.99, 'minutes');
    newEnteredVal=moment.duration(enteredVal,'minutes');
    alert(newEnteredVal + ' : '+ testVal);
    if(newEnteredVal > testVal){
      alert('greater than');
    } else {
      alert( 'less than');
    }
    
    });
    
});
  </script>
</body>
</html>

Open in new window

0
 

Author Comment

by:ascendinternet
ID: 41762052
Sorry, the code in my post was only part of the code I had, so I may have missed a bracket or two!

I don't understand why I should use a duration of minutes - the times entered might be minutes, seconds and hundredths (e.g. 1:07.43) - or might just be seconds and hundredths (e.g. 34.59)

Your sample works for seconds and hundredths (34.59) but not if it goes to minutes (1:07.43).
0
 
LVL 53

Accepted Solution

by:
Scott Fell,  EE MVE earned 500 total points
ID: 41762103
Using duration, you need to make sure your comparison matches.

http://jsbin.com/beyakixuca/1/edit?html,output
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>

  <div></div>
<script src="https://code.jquery.com/jquery-3.0.0.js"></script>
<script src="https://cdn.jsdelivr.net/momentjs/2.14.1/moment-with-locales.min.js"></script>
<script>
  $(function(){ 
    var x = moment.duration('23:59:30.2');
    var y = moment.duration('24:00:24.2');
    if (x > y){
      $('div').text('greater');
    } else {
       $('div').text('less');
    }

    
});
  </script>
</body>
</html>

Open in new window

0
Instantly Create Instructional Tutorials

Contextual Guidance at the moment of need helps your employees adopt to new software or processes instantly. Boost knowledge retention and employee engagement step-by-step with one easy solution.

 

Author Comment

by:ascendinternet
ID: 41762113
By "you need to make sure your comparison matches" - do you mean the format of the time needs to match?

Sometimes, the min / max values might only be seconds & hundredths, sometimes it will be minutes, second and hundredths - so the formatting needs to be dynamic / flexible!?

Is there another / easier way to do it, without using moment.js?
0
 
LVL 53

Expert Comment

by:Scott Fell, EE MVE
ID: 41762123
One way or another, you will need to know if "23" is an hour, minute, second or fraction or just a great center.

If you are presented with "21.5" you may assume that is 21 seconds and 5 tenths.  So format that as "0:00:21.5"

What you can't do is see a 1 and 21 and let the black box figure out the user meant the 1 as an hour and 21 as minutes.  It is up to you to format the data no matter if you use moment or pure javascript date.
0
 
LVL 53

Expert Comment

by:Scott Fell, EE MVE
ID: 41762129
To clarify,

<input value ="1">  then compare against 40.99 where the user meant 1 as an hour and your comparison is against 40 seconds and 99 tenths.
0
 

Author Comment

by:ascendinternet
ID: 41762222
Sorry, I have already dealt with formatting the input, so if you type 4099 it gets formatted as "40.99", if you type 10765 it gets formatted as "1:07.65".

I will need to deal with "stupid" inputs like "1" or "999999" but for now, I want to get it working for valid inputs.
0
 

Author Comment

by:ascendinternet
ID: 41762933
OK, I now have this which appears to be working:

        $('.timeInput')
            .blur(function () {
                var enteredVal = $(this).val().toString();
                if (enteredVal == '') return;

                var inputId = this.id;
                var fromVal = $('#from_' + inputId).val().toString();
                var toVal = $('#to_' + inputId).val().toString();

                var mReqFrom = moment.duration(PadString(fromVal));
                var mReqTo = moment.duration(PadString(toVal));
                var mEnteredVal = moment.duration(PadString(enteredVal));
                var statusIcon = $('#status_' + inputId);
                if (mEnteredVal >= mReqFrom && mEnteredVal <= mReqTo) {
                    statusIcon.attr("class", "fa fa-check");
                } else {
                    statusIcon.attr("class", "fa fa-times");
                }
            });

        function PadString(strTime) {
            var pattern = "00:00:00.00";

            var timeLen = strTime.length;

            return pattern.substr(0, pattern.length - timeLen) + strTime;
        }

Open in new window


The HTML input tag has a maxlength="8". Also the input is formatted using this plugin - http://igorescobar.github.io/jQuery-Mask-Plugin/ (code not shown).

Can the code be improved, for safety and/or performance and/or code reduction purposes?
0
 
LVL 53

Expert Comment

by:Scott Fell, EE MVE
ID: 41763323
>Can the code be improved, for safety

This is all client side.  If you are eventually going to use this to post data to your db, you want to make sure you scrub and check data server side even if you validate on the client.

>Can the code be improved, for performance and/or code reduction purposes
If it is working, go with it.  In production you will want to compress all your javascript/jquery code.  I'm sure there are some things that can be done to make this more efficient like using pure js.  For the the likes of Google and Facebook, small changes can make a very big difference.   For your purposes, you may find the page will load almost the same expanded like this or minified.
0
 
LVL 58

Expert Comment

by:Julian Hansen
ID: 41763624
You can also just use a custom function to convert to milliseconds - a lot smaller than including the entire moment.js library
function timeToMS(value) 
{
  var current = min = sec = 0;
  for(var i = 0; i < value.length; i++) {
    c = value[i];
    if (c == ':') {
      min = current;
      current = 0;
    }
    else if (c == '.') {
      sec = current;
      current = 0;
    }
    else {
	  current = current * 10 + c * 1;
    }
  }
  
  return (min*60000 + sec * 1000 + current);
}

Open in new window

Working sample here
0
 

Author Closing Comment

by:ascendinternet
ID: 41764861
The key issue turned out to be that the format of the comparisons needed to match. I ensured both values were formatted to "00:00:00.000".
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction Chart.js, used properly, can visually add a difference to your charting applications. It engages your visitors and allows them to interact with data they otherwise wouldn't be able to without expensive and complicated systems. For this…
How to build a simple, quick and effective accordion menu using just 15 lines of jQuery and 2 css classes
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…
Suggested Courses

635 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question