Home > Software design >  How can I convert human time strings into milliseconds?
How can I convert human time strings into milliseconds?

Time:02-12

Here's what I've tried from this question's's accepted answer

const timeString = '1h 30m 1s'
const milliseconds  = timeString.match(/\d /g)
       .reduce((acc, cur, idx) => acc   cur * (Math.pow(60, (2 - idx))) * 1000, 0)
console.log(milliseconds)
// result: 5401000
// expected result: 5401000

But, here's my the problem, if I only put 1m for instance, expected output should be 60000 milliseconds

const timeString = '1m'
const milliseconds  = timeString.match(/\d /g)
       .reduce((acc, cur, idx) => acc   cur * (Math.pow(60, (2 - idx))) * 1000, 0)
console.log(milliseconds)
// result: 3600000 
// expected result: 60000

It thinks that the first argument is an hour, then minute followed by second. No matter what I input. So when I put 1m, it thinks that it is an hour. It's a fixed h, m & s format and I am not able to interchange them.

The solution I want is that I should be able to interchange them parse h as hours, m for minutes, and s for seconds no matter what order and able to choose only h, m or s like

If I only output 1m, should output 1 minute only and so on

const timeString = '1m`
// should output 60000 
const timeString = '2h 1s`
// should output 7201000

If I interchange them, it should still output the same result since s is a second and h is an hour

const timeString = '1s 2h`
// should output 7201000
const timeString = '1s`
// should output 1000

or interchange them however I want no matter what format I use, and should still output the desired result in milliseconds

const timeString = '1s 6h 2m`
// should output 21721000 

CodePudding user response:

Split up the string (on spaces) and within the reducer determine what value to use, based on the value of the string (the 'hms' part). In that case you're not dependent on the order of hms and you're able to use 1, 2 or 3 values. Something like:

const toMilliSeconds = ts => ts.split(` `)
  .reduce((acc, cur, i) => {
    const num = parseInt(cur);
    const [isHour, isMinute] = [cur.endsWith(`h`), cur.endsWith(`m`)];
    return (num * (isHour ? 3600 : isMinute ? 60 : 1) * 1000)   acc;
  }, 0);
  
console.log(`1h 30m 1s = ${toMilliSeconds(`1h 30m 1s`)}ms`);
console.log(`30m 1s = ${toMilliSeconds(`30m 1s`)}ms`);
console.log(`15s = ${toMilliSeconds(`15s`)}ms`);
console.log(`1h = ${toMilliSeconds(`1h`)}ms`);
console.log(`1m = ${toMilliSeconds(`1m`)}ms`);
console.log(`1h 2s = ${toMilliSeconds(`1h 2s`)}ms`);
console.log(`2h 1s = ${toMilliSeconds(`2h 1s`)}ms`);
console.log(`1s 6h 2m = ${toMilliSeconds(`1s 6h 2m`)}ms`);
.as-console-wrapper {
    max-height: 100% !important;
}

If you want to use the original reducer (from the cited answer), sorting the string may be an idea:

const toMS = ts => 
    ts.split(` `)
    .sort( (a, b) => a.slice(-1).localeCompare(b.slice(-1)) )
    .join(``)
    .match(/\d /g)
    .reduce((acc, cur, idx) => acc   cur * (Math.pow(60, (2 - idx))) * 1000, 0);
    
console.log(`1h 30m 1s = ${toMS(`1h 30m 1s`)}ms`);
console.log(`30m 1s = ${toMS(`30m 1s`)}ms`);
console.log(`15s = ${toMS(`15s`)}ms`);
console.log(`1h = ${toMS(`1h`)}ms`);
console.log(`1m = ${toMS(`1m`)}ms`);
console.log(`1h 2s = ${toMS(`1h 2s`)}ms`);
console.log(`2h 1s = ${toMS(`2h 1s`)}ms`);
console.log(`1s 6h 2m = ${toMS(`1s 6h 2m`)}ms`);
.as-console-wrapper {
    max-height: 100% !important;
}

  • Related