2

I'm trying to add hours to time in the format of 24 hours say '23:59:59'. I need to add, for example, 2.5 hours so the time should roll to the next day and be shown as '02:30:00'.

What I have tried so far works until it reaches '23:59:59'. I need to show the next day time if it exceeds '23:59:59'. Here is what I have tried so far:

var time = $('#starttime').val().split(':');
var d = new Date();
d.setHours(+time[0]);
d.setMinutes(time[1]);
d.setSeconds(time[2]);
var time2 = $('#endtime').val().split(':');
var endtimeval = new Date();
endtimeval.setHours(+time2[0]);
endtimeval.setMinutes(time2[1]);
endtimeval.setSeconds(time2[2]);
var str = d.getHours() + parseInt($('#noofhours').val()) + ":" + time2[1] + ":" + time2[2];
$('#endtime').val(str);
benvc
  • 14,448
  • 4
  • 33
  • 54
SPYder
  • 53
  • 10
  • 1
    Instead of doing things like that by hand, it might be worth your while to look into library options like [date-fns](https://date-fns.org/) for example – raphinesse Jan 24 '19 at 14:23
  • +1 for @raphinesse comment. I use Moment.js and it makes all of this type of stuff easy, and you'll be less likely to have errors or edge cases down the road – Alicia Sykes Jan 24 '19 at 14:26
  • 1
    Could you please help me to do same in plain javascript? . I'm not in state to use any third party js files and CDN's. Hope you have understood. – SPYder Jan 24 '19 at 14:28
  • Please at least create a [mcve] of your code. Right now I have for example no idea where exactly in this those 2.5 hours you are talking about are supposed to be hiding. – 04FS Jan 24 '19 at 14:29
  • Also, adding 2.5 hours should get you to `02:28:59`, no? Or are you talking about some special constellation around the dates where the switch between summer/winter time occurs? – 04FS Jan 24 '19 at 14:31
  • @04FS , I have explained clearly now.Please look in to it. – SPYder Jan 24 '19 at 14:35
  • The main problem here is that you are not letting the Date object itself handle adding of times (it can do that quite nicely, and handles overflows automatically), but that you are performing your own math here with `var str = d.getHours() + parseInt(...)` - you are in our normal decimal system here, so you can not expect that to handle overflows on more than 24 hours or 60 minutes on its own. https://stackoverflow.com/questions/563406/add-days-to-javascript-date explains the basic principle you should use here. – 04FS Jan 24 '19 at 14:36
  • 1
    (Although setHours might not handle a value such as 2.5 correctly - so it might be easier to use the method to set minutes instead, with 2.5 * 60 as the value.) – 04FS Jan 24 '19 at 14:38
  • +1 and more for the key point @04FS, I have created simple and useful code please look in answer..Thanks for your valuable point. – SPYder Jan 24 '19 at 15:05

4 Answers4

2

Using a Date Object here is possibly unnecessary, modulo arithmetic should suffice.

const pad = n => {
  const s = String(n);
  return s.length > 1 ? s : '0' + s;
};

const addHours = (timeVal, numHours) => {
  const [hr, min, sec] = timeVal.split(':').map(Number);
  const [,lefty, righty] = String(numHours).match(/(\d+)(?:(\.\d+))?/).map(Number);
  const hours = (hr + lefty) % 24;
  const minutes = righty === undefined ? 
    min : 
    ((righty * 60 | 0) + min) % 60;

  return [hours, minutes, sec].map(pad).join(':');  
};

addHours('23:59:59', 2.5) // "01:29:59"

Note that since there's no dates involved it will not accurately handle e.g. daylight savings time. Also note that minutes are in this example rounded down, you could repeat the logic for seconds if desired.

Note that your approach using Date objects will give different answers for the same inputs depending on when/where the logic runs, for the same reasons.

Jared Smith
  • 19,721
  • 5
  • 45
  • 83
0

Make a custom date adder?

const add = (time, hours) => {
  let [hh, mm, ss] = time.split(':');

  const seconds = hours * 60 * 60;

  ss = ss * 1 + seconds;
  if (ss >= 60) { 
      mm = mm * 1 + ss / 60; 
      ss = (ss % 60).toPrecision(2).padStart(2, '0');
  }

  if (mm >= 60) {
    hh = hh * 1 + mm / 60;
    mm = (mm % 60).toPrecision(2).padStart(2, '0');
  }

  hh = (Math.floor(hh) % 24).toString().padStart(2, '0');

  return hh + ':' + mm + ':' + ss;
}

console.log(add("23:59:59", 2.5));

you may apply DRY principle and refactor the code yourself. But it will get the job done according to your requirement.

Danyal Imran
  • 2,515
  • 13
  • 21
0

You can use vanilla JavaScript Date methods fairly easily here. Most of the work is parsing the time string inputs and then concatenating the time string output. For example:

const start = '23:59:59';
const add = '2.5';
const [hh, mm, ss] = start.split(':').map(x => parseInt(x));
const d = new Date(new Date().setHours(hh, mm + (add * 60), ss));
const end = `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`;
console.log(end);
// 2:29:59
benvc
  • 14,448
  • 4
  • 33
  • 54
  • @SPYder - I read the comments but not clear to me what you think I would see there that would change the answer. Feel free to elaborate. – benvc Jan 24 '19 at 15:11
  • Note that your approach using Date objects will give different answers for the same inputs depending on when/where the logic runs. – Jared Smith Jan 24 '19 at 15:12
  • 1
    @JaredSmith, Thanks for your comment. But this logic works as per the timezone that's the thing I needed. – SPYder Jan 24 '19 at 15:16
  • @benvc, the time which interms of hours, this might be in float value like 2.3, that's need to add with the string in the format of 24 hours like 'HH:MM:SS' say '23:59:59'. This is the thing i need to do and the same I explained in above. – SPYder Jan 24 '19 at 15:17
  • @SPYder - Unless I am misunderstanding you, the answer above handles the float values and converts them to minutes for the addition. Run the snippet and you will see what I mean. – benvc Jan 24 '19 at 15:19
  • @JaredSmith - you are absolutely correct. If you do not want this to account for local daylight savings then you could modify this using the various JavaScript Date UTC methods, or if the time input is relative to another date in the locale then you would need to modify the creation of the date object. – benvc Jan 24 '19 at 15:21
  • @SPYder that's cool, but you really should put that in the question itself. – Jared Smith Jan 24 '19 at 17:00
0

The simple trick that I did is just converted the hours entered as float/int to a minute value by multiplying to 60 and created a date, with this just added the time I already have. Here the solution with minimal steps:

var time = $('#endtime').val().split(':');
    var d = new Date(); 
    d.setHours(+time[0]); 
    d.setMinutes(time[1]); 
    d.setSeconds(time[2]);
    var addeddate = new Date();
    addeddate.setMinutes(parseFloat($('#noofhours').val()) * 60);
    $('#endtime').val(("0" + (addeddate.getHours())).slice(-2) + ":" + ("0" + (addeddate.getMinutes())).slice(-2) + ":" + ("0" + (addeddate.getSeconds())).slice(-2)); //The answer that I needed in endtime id value.
SPYder
  • 53
  • 10
  • Note that your approach using Date objects will give different answers for the same inputs depending on when/where the logic runs – Jared Smith Jan 24 '19 at 15:11