Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 70
  • Last Modified:

Calculate difference between 2 durations

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
ascendinternet
Asked:
ascendinternet
  • 5
  • 5
1 Solution
 
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
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
 
ascendinternetAuthor Commented:
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
 
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
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
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
ascendinternetAuthor Commented:
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
 
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
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
 
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
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
 
ascendinternetAuthor Commented:
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
 
ascendinternetAuthor Commented:
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
 
Scott Fell, EE MVEDeveloper & EE ModeratorCommented:
>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
 
Julian HansenCommented:
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
 
ascendinternetAuthor Commented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 5
  • 5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now