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 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
If you want something more robust try this:
const timeString = '1h 30m 1s';
const milliseconds = timeString.match(/\d+\s?\w/g)
.reduce((acc, cur, i) => {
var multiplier = 1000;
switch (cur.slice(-1)) {
case 'h':
multiplier *= 60;
case 'm':
multiplier *= 60;
case 's':
return ((parseInt(cur)?parseInt(cur):0) * multiplier) + acc;
}
return acc;
}, 0);
console.log(milliseconds);
This can handle time strings in any order like '12s 5m 1h' and will ignore extraneous elements and even handle strings like 'in 1 hour 24 minutes and 3 seconds'.
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), this may be an idea for that:
const toMS = ts => {
let raw = ts.split(` `);
const hms = `0h 0m 0s`.split(` `)
.map(v => raw.find(t => t.slice(-1) === v.slice(-1)) || v);
return hms.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`,
`30m 1s = ${toMS(`30m 1s`)}ms`,
`15s = ${toMS(`15s`)}ms`,
`1h = ${toMS(`1h`)}ms`,
`1m = ${toMS(`1m`)}ms`,
`1s = ${toMS(`1s`)}ms`,
`1h 2s = ${toMS(`1h 2s`)}ms`,
`2h 1s = ${toMS(`2h 1s`)}ms`,
`1s 6h 2m = ${toMS(`1s 6h 2m`)}ms` ].join(`\n`));
.as-console-wrapper {
max-height: 100% !important;
}
See Stackblitz snippet for both solutions.