0

I converted an integer to a date format but the date object does not accept very large integers. The sample outputs show that the date could go even as far as '96 days, 11 hours, 31 minutes and 35 seconds' but the way I formatted it, only goes as far as 6 days. I tried using the BigInt method on the seconds but the date becomes invalid.

const formatDuration = seconds => {
   let str = "";

  let date = new Date(0, 0, 0, 0, 0, seconds, 0);
  if (seconds == 0) {
    str += "now";
  }
 if (date.getHours() == 0) {
    if (date.getDay() > 1) {
      str += date.getDay() + " " + "days";
    } else if (date.getDay() == 1) {
      str += date.getDay() + " " + "day";
    }
  } else if (date.getDay() > 1) {
    str += date.getDay() + " " + "days" + ", ";
  } else if (date.getDay() == 1) {
    str += date.getDay() + " " + "day" + ", ";
  }
 
  
  if(date.getMinutes() == 0) {
  if (date.getHours() > 1) {
    str += +date.getHours() + " " + "hours" ;
  } else if (date.getHours() == 1) {
    str += date.getHours() + " " + "hour";
  }
} else  if (date.getHours() > 1) {
    str += +date.getHours() + " " + "hours" + ", ";
  } else if (date.getHours() == 1) {
    str += date.getHours() + " " + "hour" + ", ";
  }
  
  if (date.getSeconds() == 0) {
    if (date.getMinutes() > 1) {
      str += date.getMinutes() + " " + "minutes";
    } else if (date.getMinutes() == 1) {
      str += date.getMinutes() + " " + "minute";
    }
  } else if (date.getMinutes() > 1) {
    str += date.getMinutes() + " " + "minutes" + " and ";
  } else if (date.getMinutes() == 1) {
    str += date.getMinutes() + " " + "minute" + " and ";
  } 
  if (date.getSeconds() > 1) {
    str += date.getSeconds() + " " + "seconds";
  } else if (date.getSeconds() == 1) {
    str += date.getSeconds() + " " + "second";
  }
 
  return str;
}

console.log(formatDuration(3600));
console.log(formatDuration(9829143));
Álvaro González
  • 142,137
  • 41
  • 261
  • 360
elenawq
  • 1
  • 1
  • What does `123456678902434` represents here? milliseconds? and how did you get this value? – palaѕн Apr 06 '20 at 13:20
  • If you can't pass a huge integer as seconds to the Date constructor, can't you just divide it by 60 as many times as necessary and pass hours, minutes, and seconds? – Aioros Apr 06 '20 at 13:24
  • 123456678902434 is a random number that represents the seconds given as the parameter. – elenawq Apr 06 '20 at 13:27
  • I will divide by 60 to convert it to hours, minutes, seconds. I am only two months into programming and I'm still learning :) Thank you so much! – elenawq Apr 06 '20 at 13:32
  • 1
    123456678902434 in seconds is about 3.9 million years, which is way beyond the [range of ECMAScript Date objects](http://ecma-international.org/ecma-262/10.0/#sec-time-values-and-time-range), which can represent about 274,000 years either side of 1970. 96 days, 11 hours, 31 minutes and 35 seconds is 8,335,895 seconds, which hugely less than the big integer. If you just want to convert seconds to Date, then `new Date(seconds * 1000)` will do. See [*Convert a Unix timestamp to time in JavaScript*](https://stackoverflow.com/questions/847185/convert-a-unix-timestamp-to-time-in-javascript). – RobG Apr 06 '20 at 14:52
  • @RobG: We're unlikely to get a better answer than your comment. Perhaps you can convert it to an answer? Maybe edit the title of the question to be something a little more useful, like "Limits to the range of Data objects", or "What is the maximum Date object". – President James K. Polk Apr 06 '20 at 15:28
  • 2
    What's the use case of displaying 3-million year intervals in days? My gut feeling is that you might be solving the wrong problem. – Álvaro González Apr 06 '20 at 15:58
  • Thank you, I managed to solve it. I provided a wrong example, but I corrected it. – elenawq Apr 06 '20 at 17:13
  • I've edited the snippet to include your new test case (please note that's something you can do yourself). So, in the end, this has nothing to do with large integers or, IMHO, with actual dates. An interval is not a date and using `Date` objects just make everything harder. – Álvaro González Apr 07 '20 at 07:44

1 Answers1

0

I converted an integer to a date format but the date object does not accept very large integers.

Your method:

let date = new Date(0, 0, 0, 0, 0, seconds, 0);

Is more concise if just a number is passed to the constructor:

let date = new Date(seconds * 1000);

It's treated as milliseconds since 1970-01-01T00:00:00Z (the ECMAScript epoch). See Convert a Unix timestamp to time in JavaScript.

The sample outputs show that the date could go even as far as '96 days, 11 hours, 31 minutes and 35 seconds' but the way I formatted it, only goes as far as 6 days.

A Date object can handle a range of exactly -100,000,000 days to 100,000,000 days from the epoch (±273,785 years approximately).

I tried using the BigInt method on the seconds but the date becomes invalid.

Your issue is that you're using Date methods incorrectly.

if (date.getDay() > 1) {
  str += date.getDay() + " " + "days";

The getDay method returns the day of the week, from 0 to 6 representing Sunday to the following Saturday.

To convert seconds to days, hours, etc. and assuming all days are exactly 24 hours long (i.e. ignoring daylight saving changeover days), divide successively by the various units, e.g.

// Convert seconds to [days,hours,minutes,seconds]
function secondsToDays(sec) {
  let d = sec/8.64e4 | 0;
  let h = (sec % 8.64e4) / 3.6e3 | 0;
  let m = (sec % 3.6e3) / 60 | 0;
  let s = sec % 60;  
  return [d,h,m,s];
}

// Covert d:h:m:s to seconds
function daysToSecs(s) {
  let b = s.split(':');
  return b[0]*8.64e4 + b[1]*3.6e3 + b[2]*60 + b[3]*1;
}

// Format time from array of [d,h,m,s]
function formatTime(parts) {
  let [d, h, m, s] = parts;
  let pl = (n, u) => u + (n == 1? '':'s');
  return [`${d? d.toLocaleString('en') + pl(d, ' day') : ''}`,
          `${h? h + pl(h, ' hour') : ''}`,
          `${m? m + pl(m, ' minute') : ''}`,
          `${s? s + pl(s, ' second') : ''}`].join(' ');
}

let secs = daysToSecs('1428:1:33:9');
console.log(`${secs} seconds is ${formatTime(secondsToDays(secs))}`);
RobG
  • 142,382
  • 31
  • 172
  • 209