Solved

Calculate difference between 2 durations

Posted on 2016-08-18
11
33 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
  • 5
  • 5
11 Comments
 
LVL 52

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 52

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
 

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 52

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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 52

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 52

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 51

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

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
object passed as reference 1 14
javascript email link with image 2 19
Phone Dialer 5 36
Example unit tests with AngularJS 2 0
How to build a simple, quick and effective accordion menu using just 15 lines of jQuery and 2 css classes
Introduction JSON is an acronym for JavaScript Object Notation.  It is a text-string data transport mechanism, capable of representing simple or complex data structures in a consistent and easy-to-read manner.  Similar in concept to XML, but more e…
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…

760 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now