Changing milliseconds from 3 digits to 2 digits - javascript

I am having trouble making a stopwatch that only uses 2 digits for the milliseconds part. I have the full JSFiddle here. The function I could use some help with is the formatter() method.
Right now, the method looks like this:
formatter(timeInMilliseconds) {
const padZero = (time) => {
while (time.length < 2) {
time = '0' + time;
}
return time;
}
let time = new Date(timeInMilliseconds);
let minutes = padZero(time.getMinutes().toString());
let seconds = padZero(time.getSeconds().toString());
let milliseconds = padZero((time.getMilliseconds() / 10).toFixed(0));
let output = `${minutes} : ${seconds} . ${milliseconds}`;
console.log(output);
return output;
}
For the most part, it works. The problem though is very visible if you look at the console of my JSFiddle while the timer is running. For example, if the stopwatch is currently at something like 00 : 15 . 99, it will become 00 : 15 . 100 at the next tick instead of 00 : 16 . 00.
Any help would be appreciated.

toFixed rounds rather than truncating, so 995 milliseconds and up will become 99.5 and be formatted to 100 by toFixed. You can convert it to an integer and then to a string instead to truncate it:
let milliseconds = padZero('' + (time.getMilliseconds() / 10 | 0));
It might also be a nice simplification to make padZero accept a number rather than a string:
function padZero(time) {
return time < 10 ? '0' + time : '' + time;
}
let time = new Date(timeInMilliseconds);
let minutes = padZero(time.getMinutes());
let seconds = padZero(time.getSeconds());
let milliseconds = padZero(time.getMilliseconds() / 10 | 0);
let output = `${minutes} : ${seconds} . ${milliseconds}`;
Finally, if timeInMilliseconds isn’t a timestamp in milliseconds since 1970-01-01 00:00:00 UTC and is instead a duration, it’s inappropriate to convert it to a Date. Just do some math:
const minutes = padZero(timeInMilliseconds / 60000 | 0);
const seconds = padZero((timeInMilliseconds / 1000 | 0) % 60);
const centiseconds = padZero((timeInMilliseconds / 10 | 0) % 100);

Your problem is that .toFixed() rounds instead of truncating.
(99.4).toFixed(0) == '99'
(99.5).toFixed(0) == '100'
All you need to do is replace
(time.getMilliseconds() / 10).toFixed(0)
with
Math.floor(time.getMilliseconds() / 10).toFixed(0)
and it'll work.

You can use substring()
let milliseconds = padZero((time.getMilliseconds() / 10).toFixed(0)).substr(0, 2);

Related

how to create a countdown that repeats every 48 or 72 hours

I'm trying to create a countdown that repeats every 24, 48 or 72 hours at midnight without moment.js
For example (example for 48 hours):
10-12-22 00:00 -> start countdown -> 47:59:59
11-12-22 22:30 -> countdown = 1:30:00
12-12-22 00:00 -> the countdown restart -> 47:59:59
I try solution only for 24 hours
I try this:
setInterval(function time() {
var d = new Date();
var hours = 24 - d.getHours();
var min = 60 - d.getMinutes();
if ((min + '').length == 1) {
min = '0' + min;
}
var sec = 60 - d.getSeconds();
if ((sec + '').length == 1) {
sec = '0' + sec;
},
1000);
There are a huge number of questions and answers already about timers and countdowns. Pick one.
The only point of interest here is that it should to restart when the remainder gets to zero, e.g.:
// Counts down period milliseconds, then restarts
function timer(period) {
let start = new Date();
let z = n => ('0'+n).slice(-2);
let zz = n => ('00'+n).slice(-3);
let f = ms => {
let day = (ms / 8.64e7) | 0;
let hr = (ms % 8.64e7) / 3.6e6 | 0;
let min = (ms % 3.6e6) / 6e4 | 0;
let sec = (ms % 6e4) /1e3 | 0;
let mil = (ms % 1e3);
return `${day} days, ${z(hr)}:${z(min)}:${z(sec)}.${zz(mil)}`;
}
setInterval(() => {
console.log(f(period - (Date.now() - start) % period));
}, 1000);
}
timer(1000*5);
Format the output however you want, maybe floor the seconds and ditch the milliseconds.
BTW, setInterval is not a good way to run a timer. Use successive calls to setTimelout with the lag set to about 10ms longer than the time to the next full second, minute or whatever. That way it won't be seen to miss a second (which happens with setInteval because it may slowly drift, as can be seen in the ms part of the above, there is always at least 1e3 ms between logs, usually more and sometimes a lot more, depending on how busy the system is with other tasks).
I don't really get the question but perhaps try setInterval?
//this will log to console after 2 days
setInterval(() => {
console.log("Ding Dong");
},
2*24*60*60*1000);

Converting to duration from milliseconds

I am trying to convert time duration from the format of mm:ss.mss to entirely milliseconds and back.
I've already have a working function for converting from milliseconds to duration but I cannot seem to get it the other way around.
Lets say for instance that I have the duration 32:29.060, I want to convert it to milliseconds. For that I use this function:
function millisecondsToTime(ms, digits) {
digits = digits || 12;
return new Date(ms).toISOString().slice(23-digits, -1);
}
var a = millisecondsToTime(5549060, 9);
but whenever I try to convert back to time duration, I fail. I've tried parsing individually the minutes, seconds and milliseconds but it doesn't seem to work.
Here is the code that I've used for it:
var firstSplit = a.split(':')
var minutes = firstSplit[0]; //1
var secondSplit = firstSplit[1].split('.');
var seconds = secondSplit[0]; //2
var millisec = secondSplit[1]; //3
var conversion = ((+minutes) * 60 + (+seconds) * 60 + (+millisec))*1000;
I have an input bar which takes the format of mm:ss.mss and I need to convert it to milliseconds. How can I do that?
you can just return a
new Date(ms)
to get a date from ms.
And to get the same date as ms,
date.getTime() // returns ms from date object
Full example:
const ms = 5549060
const date = new Date(ms) // get a date from ms
console.log(date.getTime) // logs 5569060
If your input is a string in the format of mm:ss.mss, and you want to get a date from it, you can use moment.
const moment = require('moment')
const date = moment('22:15.143', 'mm:ss.SSS') // get date from pre specified format
You can use the string methods indexOf() and substr() to get the individual numbers out of your string and calculate the time accordingly.
I'm afraid though your millisecondsToTime() function isn't working properly.
5549060 milliseconds are roughly 92 minutes and it's returning 32:29.060
function backToTime(time) {
var index = time.indexOf(":");
var minutes = time.substr(0, index);
var seconds = time.substr(index + 1, time.indexOf(".") - (index + 1));
var milliseconds = time.substr(time.indexOf(".") + 1, time.length);
return parseInt(minutes * 60 * 1000) + parseInt(seconds * 1000) + parseInt(milliseconds);
}
console.log(backToTime("32:29.060"));
Your conversion to milliseconds is not working, this is basic math approach to both conversions:
let input = 5549060
//toDuration
let seconds = Math.floor(input / 1000);
let ms = input - seconds*1000;
let m = Math.floor(seconds / 60);
let s = seconds - m*60;
duration = m + ":" + s + "." + ms
console.log(duration)
//toMilliseconds
let holder = duration.split(":");
m = parseInt(holder[0]);
holder = holder[1].split(".");
s = parseInt(holder[0]);
ms = parseInt(holder[1]);
milliseconds = (m*60 + s)*1000 + ms
console.log(milliseconds)
If needed add check for ms length to add 0s, if you need it to have length of 3
I think your milliseconds to duration converter will be broken for durations above 60 minutes. This is because using Date the minutes field will wrap over into the minutes after 59 seconds have passed. If you want to get good support for values beyond 59 in your first field, I think maybe moving to a regex-based parser and using multiplication and addition, division and modulo to extract and reduce the fields manually might be nice. Something like this maybe:
var duration = ms => `${(ms / 60000) | 0}`.padStart(2, '0') + `:` + `${ms % 60000 / 1000 | 0}`.padStart(2, '0') + `.` + `${ms % 1000}`.padStart(3, '0')
var millisec = durat => (match => match && Number(match[1]) * 60000 + Number(match[2]) * 1000 + Number(match[3]))(/^([0-9]+)\:([0-5][0-9])\.([0-9]{3})$/.exec(durat))
You can see given the input 5549060, this function provides output 92:29.60, which is exactly 60 seconds greater than your own, and I believe to be correct. Maybe it's intentional for your usecase, but I can't imagine that being so desirable generally...

How to replace time stamp in the string and round hours?

I have function that returns array or values that represent working hours. Array can return one or two elements. In case where only one element is returned this is pretty simple but when I have two that is the problem to find the way how to replace the existing values in the string. Here is example of the original string: 0600-2200 MAY 15-SEP 30; 0600-2100 OCT 1-MAY 14. I have function that finds the time stamp in the string and returns the hours. Example of the returning array is here: [16,15]. That array has two values and I need to replace 0600-2200 with first element in the array 16 and append the word hours to that. So final output should look like this: 16 hours MAY 15-SEP 30; 15 hours OCT 1-MAY 14. Here is example of the function that converts time stamp to string:
var timeSt = "0600-2200 MAY 15-SEP 30; 0600-2100 OCT 1-MAY 14";
const calcDifference = range => {
const time = range.split`-`.map(e => (+e.substr(0, 2) * 60 + (+e.substr(2))) / 60);
return time[1] - time[0];
};
const diffs = timeSt.match(/\d{4}\-\d{4}/g).map(e => calcDifference(e));
console.log(diffs);
The solution I have tried looks like this:
var hours = "";
for(var i=0; i < diffs.length; i++){
hours += timeSt.replace(regex,diffs[i] + " hours ");
}
Here is the output that above example produced:
16 hours MAY 15-SEP 30; 16 hours OCT 1-MAY 1415 hours MAY 15-SEP 30; 15 hours OCT 1-MAY 14
Seems that entire string was appended twice. I understand why that is happening but still can't get a good way how to fix this problem. The other thing that I noticed is that some time stamp values look like this: 0000 - 2359
In that case function that converts hours will return this: [23.983333333333334]. I would like to round up that value to 24 and that is the only case where the value should be rounded up to 24 the higer int his case. I time stamp looks like this: 0500-2330 function returns [18.5] and that value should not round. It should stay as it is. If anyone knows good way on how to fix these two problems please let me know.
For the problem of replacing you can provide a callback to .replace function in string.
const roundMinutes = 15;
const timeSt = "0600-0000 MAY 15-SEP 30; 0600-2145 OCT 1-MAY 14";
const calcDifference = range => {
const time = range.split`-`.map(e => +e.substr(0, 2) * 60 + (+e.substr(2)));
let [start, end] = time;
if (end < start) {
end += 24 * 60;
}
return end - start;
};
const formatted = timeSt.replace(/\d{4}\-\d{4}/g, (range) => {
const diff = calcDifference(range);
const full = Math.round(diff / roundMinutes) * roundMinutes;
const hours = Math.floor(full / 60);
const minutes = full - hours * 60;
const time = minutes === 0 ? `${hours}` : `${hours}.${minutes}`
return `${time} hours`;
})
console.log(formatted)
To change precision you can tweak roundMinutes constant.

Javascript: finding the time difference between two 'time' strings without involving date

I have two <input type="time">. By default, each input collects a time value as a string. For example, "08:30".
How can I convert this string into an object which would then enable computation? Is it possible to avoid involving the use of date in this approach?
In the end, I would like to compute the difference between two time strings and then return the result in minutes. For example, the expected return value of08:00 and 09:00 would be 60 minutes.
Just do it as if you only had pen and paper:
12:45 => 12 × 60 + 45 = 765 minutes
08:30 => 8 × 60 + 30 = 510 minutes
765 - 510 = 255
Integer division: 255 / 60 = 4 hours
Remainer: 255 - 60 × 4 = 15 minutes
Result: 04:15
You can parse from string using regular expressions:
var parts = "08:45".match(/^(\d+):(\d+)$/);
console.log(+parts[1], +parts[2], +parts[1] * 60 + +parts[2]);
... and formatting back to string should not be very difficult either.
Assuming you want to use a 24h clock:
function minutesBetween (a, b) {
return Math.abs(toMinutes(b) - toMinutes(a))
}
function toMinutes (time) {
time = /^(\d{1,2}):(\d{2})$/.exec(time)
return time[1]*60 + +time[2]
}
console.log(minutesBetween('8:30', '9:30')) //=> 60
Generally speaking I whould suggest using Date insted of using custom functions, but just for your case this is the example function:
const timeStart = "8:00:00";
const timeEnd = "8:10:00";
//Handles only time with format in hh:mm or hh:mm:ss
//For more complicated cases use Date
function diff(start, end) {
const startMinutes = getMinutes(start);
const endMinutes = getMinutes(end);
return endMinutes - startMinutes
}
function getMinutes(strTime) {
const time = strTime.split(':');
return (time[0] * 60 + time[1]*1);
}
alert(diff(timeStart, timeEnd));
Note that this function is not responsible for validation of the time difference only the computation. You should validate you input

JavaScript calculate time and seconds

I was having some problem when trying to perform some calculation logic using JavaScript. Basically along a route there is 80 steps and it took around 9 minutes to finish up the entire route.
So I was trying to do an auto route which will tell you the minutes left to destination. My logic is as below:
9 * 60 / 80 = 6.75
So basically for each step is 6.75 seconds but I wanted to show a round number like 9 instead of 8.4 minutes. Here is the code:
getAllBusLoc(function(busList) {
var totalBusLoc = busList.length;
var busLeftPct = Math.round(parseFloat(busList.length) * 40 / 100)
document.getElementById("busStopLeft").innerHTML = totalBusLoc;
pointArr.forEach(function(coord,index){
setTimeout(function(){
var travelTime = document.getElementById(travelDistMin").value;
moveNext(coord.x, coord.y);
}, 1000* index);
});
});
I got the travel time as variable travelTime which in this case is 9 minutes. For each point, I wanted to minus 6.75 seconds from the 9 minutes and display a round number instead of 8.2.
Any ideas?
Thanks in advance.
Use Math.round() for subtracting 6.75 from travelTime.
This is will round to the nearest whole number.
An idea that I could suggest is to write a generic function that transforms a decimal time interval (for example, 8.25 minutes) into its equivalent 'mm:ss' value instead of rounding so that you display the precise time representation:
Number.prototype.toMMSS = function () {
d = this;
var sign = d < 0 ? "-" : "";
var min = Math.floor(Math.abs(d))
var sec = Math.floor((Math.abs(d) * 60) % 60);
return sign + (min < 10 ? "0" : "") + min + ":" + (sec < 10 ? "0" : "") + sec;
};
Example:
8.25.toMMSS() // "08:15"
JSFiddle
Or, you could try the moment plugin duration function like:
moment.duration(8.25, 'minutes').minutes(); // 8
Or, the humanize method to round off:
console.log(moment.duration(8.51, "minutes").humanize()); // "9 minutes"
console.log(moment.duration(8.15, "minutes").humanize()); // "8 minutes"

Categories