0

Trying to return the string representation of the timespan between two dates usind methods with needed format. But works with mistake (return 8 hours instead of 10 hours, all another OK). Maybe somebody can give me some advice of doing this?

function timeSpanToString(startDate, endDate) {
  const diff = endDate - startDate;
  const res = new Date(diff);
  console.log( `${res.getHours()}:${res.getMinutes()}:${res.getSeconds()}.${res.getMilliseconds()})`);
}
Input:
startDate: new Date(2000, 1, 1, 10, 0, 0),
endDate: new Date(2000, 1, 1, 15, 20, 10, 453),
Output expected: '05:20:10.453',

Thanks!

  • The problem arises because the difference is an interval, not a date. If you construct a Date from it, then it is interpreted relative to the epoch, 01 Jan 1970. While you can extract the hours from it, as soon as it is bigger than 24hrs, this will fail. EG a diff of 25hrs will become 02 Jan 1970 01:00:00:000 and so getHours will return 1, not 25. – sifriday Dec 22 '22 at 21:50
  • Once you have the difference between the two dates you need to do some maths on it to extract the data you want. EG the number of hours is `Math.floor((end - start) / 60 * 60 * 1000)` ... this is described well in the accepted answer here: https://stackoverflow.com/questions/3224834/get-difference-between-2-dates-in-javascript – sifriday Dec 22 '22 at 21:56

4 Answers4

1

you can use the toISOString method of the Date

function timeSpanToString(startDate, endDate) {
  const diff = endDate - startDate;
  const res = new Date(diff);
  const durationString = res.toISOString().substring(11);
  console.log(durationString);
}

var expected_output = timeSpanToString(new Date(2000, 1, 1, 10, 0, 0), new Date(2000, 1, 2, 15, 20, 10, 453));
console.log(expected_output);

This will print the duration in the format 'HH:mm:ss.SSS', where 'HH' is the number of hours, 'mm' is the number of minutes, 'ss' is the number of seconds, and 'SSS' is the number of milliseconds.

PicCOD_OFF
  • 51
  • 4
  • Won't this fail as soon as the dates are more than 24hrs apart? – sifriday Dec 22 '22 at 21:53
  • yes this is correctly my fault, I have edited it now – PicCOD_OFF Dec 22 '22 at 22:24
  • this possibly comes down to how you read the question, which is not very well worded. But in your updated example, the start date is Jan 1st 10:00 and the end date is Jan 2nd 15:20 (ignoring the seconds and milliseconds). I am assuming the question is asking us to compute the entire difference in hours, so (1 day + 5hrs 20) = 29hrs and 20 mins. But maybe not! Anway, we've closed it now as a dupe so prob not important to work it out. – sifriday Dec 23 '22 at 15:15
0

Maybe you meant to get the UTC time parts.

function timeSpanToString(startDate, endDate) {
  const diff = endDate - startDate;
  console.log(diff);
  const res = new Date(diff);
  console.log(res);
  const hrs = res.getUTCHours();
  const mins = res.getUTCMinutes();
  const secs = res.getUTCSeconds();
  const mills = res.getUTCMilliseconds();
  console.log(`${hrs}:${mins}:${secs}.${mills}`);
  console.log(`${res.getHours()}:${res.getMinutes()}:${res.getSeconds()}.${res.getMilliseconds()}`);
}

var startDate = new Date(2000, 1, 1, 10, 0, 0);
var endDate = new Date(2000, 1, 1, 15, 20, 10, 453);
console.log("S:", startDate);
console.log("E:", endDate);
timeSpanToString(startDate, endDate);
Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
  • Won't this fail as soon as the dates are more than 24hrs apart? – sifriday Dec 22 '22 at 21:53
  • @sifriday - This is not how I would recommend doing this but more to address the issue in the OP's code and why/how that can be directly addressed. The original post by the OP only had the hours/minutes and did not include days - so that would need to have 24* whatever that is for pure "hours" added yes. When you get into local time zone; daylight and actual it gets much more complicated (there are actually physical locations with two time zones at the same time that exist that differ etc.) – Mark Schultheiss Dec 28 '22 at 17:42
0

Use getTime() function in the subtraction

const diff = endDate.getTime() - startDate.getTime();
  • 1
    Date.getTime is equivalent to Date.valueOf, which is used when you do this calculation with two Date objects. ie, your code is equivalent to `endDate - startDate` – sifriday Dec 22 '22 at 21:52
0

The problem arises because the difference is an interval, not a date. If you construct a Date from it, then it is interpreted relative to the epoch, 01 Jan 1970. While you can extract the hours from it, as soon as it is bigger than 24hrs, this will fail. EG a diff of 25hrs will become 02 Jan 1970 01:00:00:000 and so getHours will return 1, not 25.

Once you have the difference between the two dates you need to do some maths on it to extract the data you want. EG the number of hours is Math.floor((end - start) / 60 * 60 * 1000)

let end = new Date(2000, 1, 1, 15, 20, 10, 453)
let start = new Date(2000, 1, 1, 10, 0, 0)
let diff = end - start
HH = Math.floor(diff / 3600000)
let remainder = diff - (HH * 3600000)
MM = Math.floor(remainder / 60000)
remainder = remainder - (MM * 60000)
SS = Math.floor(remainder / 1000)
remainder = remainder - (SS * 1000)
let sss = remainder
console.log(`${HH}:${MM}:${SS}:${sss}`)

This will print out 5:20:10:453 as required. However, it will also work with dates greater than 24hrs apart:

let end = new Date(2000, 1, 2, 16, 0, 0, 0)
let start = new Date(2000, 1, 1, 15, 0, 0)
let diff = end - start
HH = Math.floor(diff / 3600000)
let remainder = diff - (HH * 3600000)
MM = Math.floor(remainder / 60000)
remainder = remainder - (MM * 60000)
SS = Math.floor(remainder / 1000)
remainder = remainder - (SS * 1000)
let sss = remainder
console.log(`${HH}:${MM}:${SS}:${sss}`)

This prints 25:0:0:0.

sifriday
  • 4,342
  • 1
  • 13
  • 24
  • Note also that if the interval goes over a daylight saving boundary then one of the days won't be 24 hours long either. :-( – RobG Dec 23 '22 at 01:57
  • That is OK I think, there's no TZs in the Date constructor above so everything will be treated as UTC (or converted to your locale, but the maths will still happen as UTC milliseconds with respect to the epoch). EG here in the UK summer time will start on 26th March 2023 so if I set `let end = new Date (2023, 02, 26, 12, 0, 0, 0)` and `let start = new Date (2023, 02, 25, 12, 0, 0, 0)` (ie 1 nominal calenday apart) the code above will correctly print out 23 hours. – sifriday Dec 23 '22 at 15:23
  • tho I am sure you are onto something and there will be some edge case that confounds this... I was reading this the other day, coincidentally: https://gist.github.com/timvisee/fcda9bbdff88d45cc9061606b4b923ca – sifriday Dec 23 '22 at 15:23
  • The constructor assumes the current settings of the host when the *Date* is constructed, so `new Date(2000, 1, 2, 16, 0, 0, 0)` will create a different time value for each host with a different offset (i.e. a "local" *Date*). As long as the host doesn't observe DST, then everything works as if you'd used UTC. But DST muddies the waters as it's observed at different times in different places and has different offsets (1 hour or 30 minutes). – RobG Dec 24 '22 at 04:03