Run a function at time increments of 3 minutes - JS - javascript

I want to run a function at specific time points in a particular timeframe, say from 5:30 to 14:30. The specific time points would be increments of 3 minutes from 5:30 like so, 5:30, 5:33, 5:36,...,6:00 etc until 14:30. I thought the logic would be as simple as checking if the current time in integer format was a multiple of 3 and checking if the "seconds" in the current time was "00", since I want to run it only at the beginning of these specific time points. But this logic is incorrect. Since a lot of time points such as 10:00, 11:00, 13:00, 14:00 etc are not divisible by 3. Also, the browser freezes because of the while loop. How do I go about this and what is the correct logic here?
myFunc = () => {
//Some Task
};
myFunc();
var dateToday = Date();
while (Number(dateToday.getHours()+(dateToday.getMinutes()<10?'0':'') + dateToday.getMinutes())) >= 530 && Number(dateToday.getHours()+(dateToday.getMinutes()<10?'0':'') + dateToday.getMinutes()) <= 1430){
var dateTodayCheck = new Date(),
hoursCheck = dateTodayCheck.getHours(),
minutesCheck = (dateTodayCheck.getMinutes()<10?'0':'')
+ dateTodayCheck.getMinutes(),
secondsCheck = (dateTodayCheck.getSeconds()<10?'0':'')
+ dateTodayCheck.getSeconds();
var timeNowCheck = Number(hoursCheck+minutesCheck)
var remainder = timeNowCheck % 3
if (remainder === 0 && secondsCheck==="00") {
myFunc();
};
};

Okay, I got it to work for me. I came up with new logic. I hard-coded the minutes, I wanted the function to run at, ex: [0, 3, 6, 9, 12, 15,....,60]. Now say the current time is 6:35:15 the "minutes" part of the current time would be 35, so I checked for the number from my array that was closest to 35, which would be 36 (Found the code for this online). Then I took the difference between the closest value and the "minutes" part of the current time, in this case, 36 - 35 = 1 (1 minute). Later I accounted for the seconds, so 1 min - 15 seconds = 45 seconds. Finally, passed 45 seconds into a Timeout Function which contains an Interval Function that calls myFunc() every 3 minutes. This way if I open the app at 6:35:15, the program would know to wait for 45 seconds and call myFunc() at 6:36, and every 3 minutes from that point.
var dateToday = new Date(),
hours = dateToday.getHours(),
minutes = (dateToday.getMinutes()<10?'0':'') + dateToday.getMinutes(),
seconds = (dateToday.getSeconds()<10?'0':'') + dateToday.getSeconds();
var timeNow = hours+minutes
if(Number(timeNow) >= 530 && Number(timeNow) <= 1430){
const closest = [0, 3, 6, 9, 12, 15, 18, 21, 24,
27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57,
60].reduce((a, b) => {
let aDiff = Math.abs(a - Number(minutes));
let bDiff = Math.abs(b - Number(minutes));
if (aDiff === bDiff) {
return a > b ? a : b;
} else {
return bDiff < aDiff ? b : a;
};
});
var difference = closest - Number(minutes)
var timeoutTime = difference === -1 ? 2 : difference
var timeoutTimeCorrected = (timeoutTime * 1000 * 60) - (Number(seconds) * 1000)
setTimeout(() => {
myFunc();
setInterval(() => {
myFunc();
}, 180000);
},timeoutTimeCorrected);
};
Please let me know, if there is a more elegant way to do this.

Related

Time round up quarter without condition

I need to round up quarter my time even if I'm on the current quarter.
Here is my code :
const currentDate = new Date(2020, 1, 8, 9, 42, 0, 0);
let roundedUpQuarter = Math.ceil(currentDate.getMinutes() / 15) * 15 % 60;
So in my exemple the current time is 09:42 so in my roundedUpQuarter variable I'll get the good result 09:45
But I have a problem when I send 0, 15, 30 or 45 minutes on my current time because I need to round up too.
For an example if my current time is 09:30 I need to get 09:45
I don't want to use if condition to do that. It's possible to do this only with a formula ?
const currentDate = new Date(2020, 1, 8, 9, 42, 0, 0);
let roundedUpQuarter = Math.ceil((currentDate.getMinutes()+0.1) / 15) * 15 % 60;
Check % 15 === 0 and add 1 minute to real minutes. Than continue with your equation.
const currentDate = new Date(2020, 1, 8, 9, 45, 0, 0);
var minutes = currentDate.getMinutes() % 15 === 0 ? (currentDate.getMinutes() + 1) : currentDate.getMinutes();
let roundedUpQuarter = Math.ceil(minutes / 15) * 15 % 60;
console.log(roundedUpQuarter); // for 45 return 0

Count down and reset count with javascript

I want to show a countdown on my website. for all users but I don't want to use any backend language.
Countdown is starting from 20 and after each 1min I am decreasing number by 1. Means after 2mins the value will be 18 and when it reachs at 3 the number should reset to 20. I use the time difference to do that it count down correctly but reseting is not working. I have two functions
function change_html() {
var start_number = 20;
var start = new Date("November 11, 2020 00:00:00"); // This will get the all milisec
var end = new Date(); // This will get the all milisec of current
var final = (get_difference(start,end)); // This will return all the mins passed
var new_start = (final/20); // This will get how many 20 are passed
var new_final = new_start.toString();
new_final = new_final.split(".");
var final_to_show = new_start-parseInt(new_final[0]);
final_to_show = final_to_show*20; // This will get how many numbers are remain to complete 20
final_to_show = Math.round(((20)-final_to_show));
document.getElementById('html_element').innerHTML = final_to_show;
}
And second for converting milisec to mins
function get_difference(start,end) {
var difference =((end.getTime() - start.getTime()) / 1000)/60;
return Math.abs(Math.round(difference));
}
I didn't want to reset the countdown on reload and the loop is endless.
I don't understand what to do with reset because it is not based on any static value it will be done in jQuery and Javascript. Please help me with this or suggest me to do it with another way.
You just need to use a setInterval method
the most complicated was to set your countdown of 17 minutes in offset of 3 points, with a first start at 20.
...and you should have a look about how the modulo works in math
const showElement = document.getElementById('html_element')
, one_Sec = 1000
, one_Min = one_Sec * 60
, countMax = 20
, countMin = 3
, countRange = countMax - countMin +1
, startDateT = (new Date("November 11, 2020 00:00:00")).getTime()
, timeNowDiff = () => Math.floor(Math.abs(((new Date()).getTime() -startDateT) / one_Min ))
;
showElement.textContent = countMax -(timeNowDiff() % countRange)
setInterval(()=>
{
showElement.textContent = countMax -(timeNowDiff() % countRange)
}
, one_Sec *10); // check display change every 10 seconds....
changing every minutes : <span id="html_element" style="color:red"></span> until 3

How to format dates in Javascript date object and work with setting intervals between them?

I am making a scheduling application. The requirement is the user enters two time frames and the application should divide it into intervals of 20 with 10 minutes break in between. For instance, if I enter 15:15-17:15, it should give me slots like: ['15:15', '15:35', '15:45', '16:55'].
Errors I am facing: The approach I am using works fine for setting intervals but unable to give 10 minute break in between. My output gives ["15:15", "15:35", "15:55", "16:15", "16:35", "16:55", "17:15"]. Further if I enter the end time as 17:05, the result still gives the final count as 17:15.
Lastly if the above two issues are resolved I would be grateful if somebody can tell me how would I format the array such that I can the result as: [ '15:15-15:35', '15:45-16:55']. TIA
let date1 = new Date(2020, 8, 20, 15, 15);
let date2 = new Date(2020, 8, 20, 17, 05);
let slots = []
if(date1 < date2){
console.log((date2.getHours()*60 - date1.getHours()*60)/20)
for(var i = 0; date1 < date2; i=20)
{
date1.setMinutes(date1.getMinutes()+i)
slots.push(date1.getHours() + ':' + date1.getMinutes());
}
console.log(slots)
}
else{
console.log('End time should be greater than start time')
}
This should do the trick:
const dateToString = date => date.getHours() + ':' + (date.getMinutes() + '').padStart(2, '0')
const date1 = new Date(2020, 8, 20, 15, 15);
const date2 = new Date(2020, 8, 20, 17, 05);
function getIntervals(date1, date2) {
date1 = new Date(date1.getTime()) // so we don't mutate date1
const intervalLength = 20, breakLength = 10, intervals = []
let interval
while (date1 < date2) {
interval && intervals.push(interval)
interval = [intervalLength, breakLength].map(len => {
const str = dateToString(date1)
date1.setMinutes(date1.getMinutes() + len)
return str
}).join('-') // - separator
}
return intervals
}
console.log(getIntervals(date1, date2))
dateToString converts a Date object into an hh:mm format, padding the minute component with zeroes if necessary. To get the intervals, we step through by alternating time lengths of intervalLength and breakLength and push each generated interval to our array. We then return the interval.
The code in the OP doesn't seem to be dividing the time correctly or allowing for the intervals between periods.
The time between the two dates needs to be broken into n periods with n-1 10 minute breaks in between. Subtracting one date from the other will give the time difference in milliseconds, then it needs to be divided that into the required periods and intervals, e.g.
/**
* #param {Date} start - start date and time
* #param {Date} end - end date and time
* #param {number} periods - number of periods
* #param {number} interval - interval between periods in minutes
* #returns {Array} array of perids with interval gap between
* in format ['HH:mm - HH:mm', ...]
*/
function getSlots(start, end, periods, interval) {
// Function to format period timestamp
function f(d) {
return ('' + d.getHours()).padStart(2, '0') + ':' + ('' + d.getMinutes()).padStart(2, '0');
}
let slots = [];
let diff = end - start;
if (diff < 0) return 'End must be after start';
// Get length of interval in ms
let intLength = interval * 6e4;
// Get total length of intervals in ms
let intTotal = (periods - 1) * intLength;
// Get length of each period in ms
let periodLength = (diff - intTotal) / periods;
// Generate periods
for (let e, s = new Date(start), i = periods; i > 0; i--) {
// Copy start to get end and add length of period
e = new Date(+s + periodLength);
// Write period to slots array
slots.push(f(s) + '-' + f(e));
// Increment s to start of next period
s.setMilliseconds(s.getMilliseconds() + periodLength + intLength);
}
return slots;
}
let date1 = new Date(2020, 8, 20, 15, 15);
let date2 = new Date(2020, 8, 20, 17, 5);
console.log(getSlots(date1, date2, 2, 10));
Note that this entirely fills the time allowed, there is no interval at the ends. Also, times are truncated to whole minutes, so may appear to not have exactly the same number of minutes or be equal.

Get remaining time with an array for opening hours

I'm trying to create a countdown to get the remaining time before my shop will close
// My array for the opening hours :
var openTime = [
{ open : 9, close : 17},
{ open: 9, close : 18 },
{ open: 9, close : 18 },
{ open: 9, close : 18 },
{ open: 9, close : 18 },
{ open: 9, close : 18 },
{ open: 10, close : 16.5 }
]
var current = new Date();
var day = current.getDay();
var currentTime = current.getHours() + (current.getMinutes() / 60);
var remainTime = 0;
if (openTime[day].open >= 0 && openTime[day].open < currentTime && openTime[day].close >
currentTime) {
remainTime = (openTime[day].close - currentTime).toFixed(2)
}
console.log("the shop will close in %s hours", remainTime);
But I have a problem with this line :
var currentTime = current.getHours() + (current.getMinutes()/60);
Because when I execute the code, for exemple, actually it's 17h22, the code give me on my debugger that current time equal to 17.36 ?
There is something wrong with the line, because it's give me the wrong remaining time...
0.36 of an hour (a decimal magnitude) equals 21.6 (≈22) minutes.
It's simple to convert decimal to minutes: 60*decimal. Or (60*decimal).toFixed(0) or (60*decimal).round() if you want a round number.
Also, remember that JS uses the device's time. Today most devices sync their time, but if you don't want to rely on it, you should bring the time from your server (ie. storing it in a JS variable at preprocessing time, like var time=<?=time()?>;).
If you want current time as string you have to:
var currentTime = current.getHours() + ":" + (current.getMinutes() / 60);
but thats not what you want I guess. You get of coures 17.36 because 17:22 converted to decimal base 10 instead of 60 minutes gives this value (22 min /60 =0.363636 rounded two digits 0.36). If you want to have the timer working you convert either back the decimal part by *60 to easy find it. Use:
var decimalPart = remainTime % 1;
var remainTimeHours = remainTime - decimalPart;
var remainTimeMin = decimalPart * 60;
Of course you can simplify it - just to show the logic
-in your closing time you use already 16.5 means 16:30 or should it be 16:50 -> then 16.83
or preferred seperate logic for hours and minutes not converted to decimal using even seconds if needed.

Changing milliseconds from 3 digits to 2 digits

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);

Categories