Fast Time conversion
I'm trying to write a very fast time-to-string and string-to-time function.
I noticed that on low CPU mobile devices this function has, even if minimal, impact on the performance of the overall canvas animation.
Milliseconds to Time string (HH:MM:SS.mss)
In this function: is there a shorter & faster way to pad the numbers?
function ms2TimeString(a,ms,s,m,h){// time(ms) return ms=a%1e3|0, s=a/1e3%60|0, m=a/6e4%60|0, h=a/36e5%24|0, (h>0?(h<10?'0'+h:h)+':':'')+ //display hours only if necessary (m<10?'0'+m:m)+':'+ (s<10?'0'+s:s)+'.'+ (ms<100?(ms<10?'00'+ms:'0'+ms):ms) } Here are some other ways to pad the numbers, but I guess executing new array,join,slice or substr has more impact on the performance than (m<10?'0'+m:m).
function padL2(a){//number or string return a+='','00'.substr(0,2-a.length)+a; } function padL(a,b,c){//string,length=2,char=0 return (new Array(b||2).join(c||0)+a).slice(-b); } Time string (HH:MM:SS.mss) to Milliseconds
This function uses 2 split and the array a is not cached.
function timeString2ms(a,b,c){// time(HH:MM:SS.mss) return c=0, a=a.split('.'), !a[1]||(c+=a[1]*1), a=a[0].split(':'),b=a.length, c+=(b==3?a[0]*3600+a[1]*60+a[2]*1:b==2?a[0]*60+a[1]*1:s=a[0]*1)*1e3, c } UPDATE
the first most important part of this function should be the performance, the second is to have a very short code. it should be a one line function.
ms2TimeString (4 updates)
function ms2TimeString(a,k,s,m,h){ return k=a%1e3, // optimized by konijn s=a/1e3%60|0, m=a/6e4%60|0, h=a/36e5%24|0, (h?(h<10?'0'+h:h)+':':'')+ // optimized (m<10?0:'')+m+':'+ // optimized (s<10?0:'')+s+'.'+ // optimized (k<100?k<10?'00':0:'')+k // optimized } Description:
function ms2TimeString(inputInMilliseconds,milliseconds,seconds,minutes,hours){ The milliseconds, seconds, minutes, hours are just placeholders. They are undefined variables which I set inside the function before I need them. Sometimes they are really useful so you don't have to write multiple times var.
return I start with return (another point why I don't want use var) as this function is meant to be a one-line-function, even if it's a long function.
milliseconds=inputInMilliseconds%1e3, I removed the unecessary |0.
The strange number 1e3 means 1000.
1e7 means that the first number is followed by 7 zeros
seconds=inputInMilliseconds/1e3%60|0, To get only the seconds I need to divide the milliseconds per 1000 (so 1e3) then apply the modulo calculation and finally floor the number.
But there is a trick. Using the bitwise operator | or >>, you can floor numbers up to 32bit, so numbers up to 10 decimal digits. As this function is meant to be for a a/v player that's enough. And the cool thing is that this bitwise operator is much much faster than the Math.floor function.
minutes=inputInMilliseconds/6e4%60|0, Same as above, ms/60000%60|0 gives you the seconds. You will notice the , as I started with return the comma allows me to apply some calculations before I output the final result.
hours=inputInMilliseconds/36e5%24|0, to get the hours 60*60*1000=3600000=36e5 .....Math.floor(ms/3600000%24) in this case we have 24 hours max.
(hours?(hours<10?'0'+hours:hours)+':':'')+ Now if you look at the first function, I made some optimizations. As hours>0 and hours will give you the same value, I removed those 2 chars. If hours is bigger than 0, then it's true, else false, same as hours is 0 it will return 0 which is false or null. It works like a charm and it does not have to check with another value which in this case is 0.
(minutes<10?0:'')+minutes+':'+ (seconds<10?0:'')+seconds+'.'+ Also in these two lines I optimized the code a little. As we already appending to a string, I can pass 0 as number, and don't need the ''. I also don't need to write 3 times minutes or seconds. I saved a char, but also added performance as when compiling the var s(seconds) appears 2 times vs 3.
(milliseconds<100?milliseconds<10?'00':0:'')+milliseconds I can't apply the above number trick because 00 is always 0 if interpreted as a number.
} Usage:
console.log(ms2timeString(89754)); // milliseconds timeString2ms (3 updates)
function timeString2ms(a,b){// time(HH:MM:SS.mss) // optimized return a=a.split('.'), // optimized b=a[1]*1||0, // optimized a=a[0].split(':'), b+(a[2]?a[0]*3600+a[1]*60+a[2]*1:a[1]?a[0]*60+a[1]*1:a[0]*1)*1e3 // optimized } Description
function timeString2ms(a,b){ At the moment a is the input as a Time String HH:MM:SS.mss and b is a placeholder. I don't give special names to this 2 variables as they change the role inside the function. These are just 2 temp variables. If you prefer, I can call them temp1 and temp2.
return a=a.split('.'), Here I split the string in 2 pieces where the first is HH:MM:SS and the second is milliseconds.
b=a[1]*1||0, If the input contains milliseconds I multiply them by one to avoid the slow parseInt function and set b the first temp variable to the milliseconds, else I set it to 0.
a=a[0].split(':'), Here I reuse a which is the input string as an array where I store hours, minutes and seconds.
b+ add my milliseconds with
(a[2]? if the array length is 3, and so I have hours, minutes and seconds
a[0]*3600+a[1]*60+a[2]*1 I multiply the hours with 3600 add them to minutes multiplied with 60 add seconds multiplied with 1 (to avoid parseInt). In this case a contains hours, minutes, seconds, b milliseconds.
:a[1]? else if no hours. In this case a contains minutes,seconds,b milliseconds
a[0]*60+a[1]*1 minutes multiplied with 60 add seconds multiplied with 1 (to avoid parseInt)
: else. In this case a contains only seconds,b milliseconds
a[0]*1 I multiplied the seconds with 1 (to avoid parseInt)
)*1e3 and finally multiply everything with 1000
} Usage:
console.log(timeString2ms('10:21:32.093')); // hh:mm:ss.mss console.log(timeString2ms('21:32.093')); // mm:ss.mss console.log(timeString2ms('21:32')); // mm:ss console.log(timeString2ms('32.093')); // ss.mss console.log(timeString2ms('32')); // ss console.log(timeString2ms('32467.784')); // seconds.ms console.log(timeString2ms(32467.784+'')); // seconds.ms Extra
Notes
I did not use any minifier or compressor. The purpose of this code is already explained in the first lines of the post (performance and byte-saving).
Using bitwise operators and shorthand makes this function faster in the real world (if you don't think so create your own function and show me a jsperf). If you don't understand, ask.
No memoization.
Executing/initializing functions inside other functions is slower.
http://jsperf.com/multiple-functions
Accessing objects is slower than arrays or single vars.
http://jsperf.com/store-array-vs-obj
Maybe the result between every second would be more fluid, but I would see a higher performance loss when the second value changes. So in this case, I prefer some random lag that every second a fixed lag.