Detecting changes to system time in JavaScript - javascript

How can I write a script to detect when a user changes their system time in JS?

There is no (portable) way to track a variable in JavaScript. Also, date information does not lie in the DOM, so you don't get the possibility of a DOM event being triggered.
The best you can do is to use setInterval to check periodically (every second?). Example:
function timeChanged(delta) {
// Whatever
}
setInterval(function timeChecker() {
var oldTime = timeChecker.oldTime || new Date(),
newTime = new Date(),
timeDiff = newTime - oldTime;
timeChecker.oldTime = newTime;
if (Math.abs(timeDiff) >= 5000) { // Five second leniency
timeChanged(timeDiff);
}
}, 500);

Check in an interval function that the time has not changed too much:
function getTime() {
var d = new Date();
return d.getTime();
}
function checkTime() {
if (Math.abs(getTime() - oldtime) > 2000) { // Changed by more than 2 seconds?
alert("You changed the time!");
}
oldtime = getTime();
}
var oldtime = getTime();
setInterval(checkTime, 1000); // Check every second that the time is not off
Tested on Windows with Opera & FF and works flawlessly.

Don't think there is a solution to what you are asking for but you can get the users timezone offset.
new Date().getTimezoneOffset() * -1
This returns the offset in minutes from GMT. Bare in mind though this does not take DST into consideration.

var last_time = new Date().getTime();
setInterval(function() {
var time = new Date().getTime();
var offset = time - last_time;
if(offset < 0 || offset > 1500) {
// Time has been changed
}
last_time = time;
}, 1000);
In theory, this should work. It will check every second to make sure the time hasn't been changed. Note that I use 1100 milliseconds as most JS interpreters don't fire off events at exactly the time specified.
Hope this helps!

use performance.now() to get duration, which will be independent of system clock
see https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
var t0 = performance.now();
doSomething();
var t1 = performance.now();
console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.");
And then you can compare performance.now() elapsed with Date.now() elapsed to see whether they are diff too much.

Do you mean if they are changing their own system time to something that is wrong? You can ask the user for their time zone and get the correct time from the server, and then compare it to the user's system time.

You could check every 30 seconds, etc. If the new Time is off by more than 30 seconds +/- some threshold, you could do a more exhaustive comparison to determine how much it has been changed.

Related

How can I use a while loop to generate a delay between console logging one item and another item?

I have the following code but it doesn't seem to work. I want to log to the console "dark-green", have it wait a couple milliseconds, then log "light-green", all WITHOUT using setInterval or setTimeout. Is this possible with javascript?
function logGreen() {
console.log("dark-green");
wait(200);
console.log("light-green");
}
function wait(ms) {
var time = new Date();
var milliseconds = time.getMilliseconds();
var startTime = milliseconds;
var currentTime = milliseconds;
while(currentTime - startTime < ms) {
currentTime = milliseconds;
}
}
The problem I am running into is that the the loop breaks the browser so to speak, and I'm not sure how to fix this. Is there a way to do this with a for loop?
The issue with your code is that the value of currentTime is not being updated properly in your while loop.
The code inside your while loop will execute indefinitely (infinite loop) causing a stack overflow - I'm assuming that's what you mean by "breaks the browser". This is because your condition is always true:startTime and currentTime are the same value (currentTime - startTime < 200)
Try this instead:
while(currentTime - startTime < ms) {
time = new Date();
currentTime = time.getTime();
}
Creating a new Date object and calling time.getTime() inside the loop will return the latest time and should fix your problem. Use getTime() instead of getMilliseconds() because the latter only returns a number between 0 and 999 (ie. less than a second). This limited upper range will be problematic for your code because getMilliseconds() will only return the number of milliseconds elapsed since the previous second.
You can you generator as lazy evaluating. Please see below example. To run an infinite loop setInterval. You can modify the code according to your use.
This is supported on es6 supported browser and node 8.9.1LTS or above.
function* asyncRandomNumbers() {
let tm = new Date().getTime();
while (true) {
let updatedTm = new Date().getTime()
if(updatedTm - tm >= 1000){
tm = updatedTm;
yield tm;
}
}
}
for (var val of asyncRandomNumbers()) {
console.log(val) // outputs 0 — 9
}

"infinite" setinterval function "timing out"

having a slightly weird issue that I cant figure out. Ive set up a javascript timer, all it does is repeats an interval every second that checks the difference between 2 dates and displays the results. All seems fine, however when leaving the browser open for several minutes (not touching it.. literally walking away for a while), it seems to "time out" and stop functioning. No console error messages or anything, the code just stops executing.. Was wondering if anyone had any idea what could be causing this? Is my code the issue or is this a built in browser function to stop js functions if there is no input from the user on a page for a certain time?
edit sorry should mention this timer is set to run for around 40 days at the moment so it will never realistically meet the clearinterval statement in a user session. The future date variable im adding to the function is a dynamic unix timestamp from PHP for a date which is roughly 40 days in future. Currently set to 1444761301.88
function MModeTimer(futureDate) {
zIntervalActive = true;
var currentTime = new Date().getTime() / 1000;
var timeRemaining = futureDate - currentTime;
var minute = 60;
var hour = 60 * 60;
var day = 60 * 60 * 24;
var zDays = Math.floor(timeRemaining / day);
var zHours = Math.floor((timeRemaining - zDays * day) / hour);
var zMinutes = Math.floor((timeRemaining - zDays * day - zHours * hour) / minute);
var zSeconds = Math.floor((timeRemaining - zDays * day - zHours * hour - zMinutes * minute));
if (zSeconds <= 0 && zMinutes <= 0) {
console.log("timer in negative");
// timer at zero
clearInterval(zTimeInterval);
} else {
if (futureDate > currentTime) {
console.log("timer interval running");
// changes html as part of function
}
}
}
zTimeInterval = setInterval(function() {
MModeTimer(zNewTime)
}, 1000);
This line:
clearInterval(zTimeInterval);
Is clearing the interval when the condition:
if (zSeconds <= 0 && zMinutes <= 0) {
Is met.
And as per the log you've wrote inside, that would be wrong. You are checking that zSeconds and zMinues are less or equal to 0. So when both are 0, the interval will be cleared.
Edit
As per your edits and explanations, may I suggest adding a console log that i'ts not inside any condition?:
function MModeTimer(futureDate) {
console.log('running');
//... rest of your code
That way you can make sure if the interval is running, maybe your conditions are not being TRUE after a while and you won't see any log, but the interval would be still running.

Best Way to detect midnight and reset data

I've been developing a web application Dashboard and I was wondering how to detect that is midnight in order to reset some arrays that contains datas from the previous day using jquery or momentjs.
Use moment().format("h:mm:ss") that returns time in a h:mm:ss format.
var midnight = "0:00:00";
var now = null;
setInterval(function () {
now = moment().format("H:mm:ss");
if (now === midnight) {
alert("Hi");
}
$("#time").text(now);
}, 1000);
JSFIDDLE
A better way would be to compute the seconds until midnight. This is very simple and human readable using MomentJS:
// returns the number of seconds until next midnight
moment("24:00:00", "hh:mm:ss").diff(moment(), 'seconds');
So, just do:
setTimeout(
midnightTask,
moment("24:00:00", "hh:mm:ss").diff(moment(), 'seconds')
);
function midnightTask() {
/* do something */
}
JSFIDDLE
There's only really two ways to accomplish this
poll every x seconds and see whether we're within x seconds of midnight
Calculate the time between now and midnight, and sleep for that amount of time before executing
(1) has been demonstrated in other answers, here's (2).
The first thing to do is calculate the number of milliseconds until midnight then use that as a parameter to javascripts setTimeout.
setTimeout(function(){
// whatever you want to do at midnight
}, msToMidnight);
After you've finished your work in that function, you might want to recaculate the time until next midnight and repeat the process.
So I think you're going about this the wrong way. What you're looking for isn't when it's midnight, you just want to know when the day has changed, which is a much simpler task.
The first thing I'm going to say is avoid using timers at all costs. They're not worth it. The performance hit and extra CPU time you take from running the same function >3600 times a day is ridiculous, especially when it's running on someone else's computer. You don't know how much it can handle, so assume it can't handle much at all. Go easy on your users.
I would suggest listening to a user input event, assuming that this is something you would have on a regular computer, and not something like this, where there is no user input.
If user input events are something you could rely on, I would do this..
var today = new Date(), lastUpdate;
window.addEventListener( "mousemove", function () {
var time = new Date();
// If we haven't checked yet, or if it's been more than 30 seconds since the last check
if ( !lastUpdate || ( time.getTime() - lastUpdate.getTime() ) > 30000 ) {
// Set the last time we checked, and then check if the date has changed.
lastUpdate = time
if ( time.getDate() !== today.getDate() ) {
// If the date has changed, set the date to the new date, and refresh stuff.
today = time
this_is_where_you_would_reset_stuff()
}
}
} )
If you absolutely need to use a timer, then I would do this..
function init() {
var today = new Date();
var midnight = new Date();
midnight.setDate( today.getDate() + 1 )
midnight.setHours( 0 )
midnight.setMinutes( 0 )
setTimeout( function () {
// If the date has changed, set the date to the new date, and refresh stuff.
today = time
this_is_where_you_would_reset_stuff()
init()
}, midnight.getTime() - today.getTime() )
}
init()
Keep in mind that the second way is likely to be far less reliable.
Create a date at midnight this morning, add 86400 seconds, and set a timeout for then:
new Date(Date.parse((new Date()).toString().replace(/\d\d:\d\d:\d\d/,'00:00:00')) + 86400 * 1000)
Here's how you'd use it:
var delay_to_midnight = Date.parse((new Date()).toString().replace(/\d\d:\d\d:\d\d/,'00:00:00')) + 86400 * 1000 - Date.now()
var timeoutid = window.setTimeout(function() { alert("It's midnight!"); }, delay_to_midnight);
I would try:
window.setInterval(resetAtMidnight, 1000*5) // every five seconds
function resetAtMidnight() {
var now = new Date();
if(now.getHours() < 1
&& now.getMinutes() < 1
&& now.getSeconds() < 5 ) {
redrawPage();
}
};

Performing an operation days or months in the future

I'm trying to figure out the best way to perform a task, e.g. send an email to a user, in the future.
My idea is to store (in a database along with users data) when the email needs to be sent, and on a daily basis check what users need emails sent, and use Meteor's Timer functions.
// 7 hours in millisec.
Meteor.setTimeout( function() {
Meteor.call( "sendReminderEmail", ... );
}, 2.52e+7 );
The problem that I see is having too many timers set up, and hindering performance. What is a good solution?
Edit: Basically my use case includes the user creating an event, which they set as a long term event or short term(based on days, weeks, or months), and they receive a follow-up on that event depending on the duration.
I guess I could check every hour, but that seems like a problem with equal cost. Is there a Meteor specific way to do this? Or just a better concept?
Edit2: Ok, I've realized that accurracy isn't that important for my problem, so I'm thinking of setting one timer per timezone, which would send bulk emails. If the user has a long term event and their reminder is this week, than send it now. Basically it depends on duration of event and timezone of user.
So my updated question is, how do I run something on a daily basis, with my problem in mind?
Let's say you want to execute a code at 9am today and now is 8am, you could create a timeout to match the minutes in the targeted time and then create a interval of 1 hour and at each execution check if the time is 9am, if it's, execute.
in this small scale example, I'm executing executeMe() when the clock shows 9 seconds:
Live Test: http://jsbin.com/ikulok/4/edit
<body>
Last run: <span id="time"></span><br>
Next execution: <span id="target"></span>
<script type="text/javascript">
function executeMe(){
alert("9 seconds!");
}
var timeout = null;
var interval = null;
function timer(){
var now = new Date();
document.getElementById('time').innerHTML = now;
document.getElementById('target').innerHTML = new Date(now.getTime()+ 1000);
//console.log("timer()", now);
if(now.getSeconds() == 9)
setTimeout("executeMe();",1); // async
if(interval == null)
interval = setInterval("timer()",1000);
}
var now = new Date();
var target = new Date(now.getFullYear(),now.getMonth(),now.getDate(),now.getHours(),now.getMinutes(),now.getSeconds()+1,0);
//console.log("now", now);
//console.log("target", target);
//console.log("diff", target.getTime() - now.getTime());
document.getElementById('target').innerHTML = target;
timeout = setTimeout("timer()", target.getTime() - now.getTime() );
</script>
If you want to run the timer() every hour instead of every second, just adjust the target and the setInterval() and of course your conditions
Live Test: http://jsbin.com/ikulok/3/edit
<body>
Last run: <span id="time"></span><br>
Next execution: <span id="target"></span>
<script type="text/javascript">
function executeMe(){
alert("1:20am!");
}
var timeout = null;
var interval = null;
function timer(){
var now = new Date();
document.getElementById('time').innerHTML = now;
document.getElementById('target').innerHTML = new Date(now.getTime()+ 1*60*60*1000);
//console.log("timer()", now);
if(now.getHour() == 1)
setTimeout("executeMe();", 20*60*1000); // !!!! this will execute at 1:20am
if(interval == null)
interval = setInterval("timer()",1*60*60*1000); // !!!! repeat every hour
}
var now = new Date();
// !!!! targeting next exact hour
var target = new Date(now.getFullYear(),now.getMonth(),now.getDate(),now.getHours(),now.getMinutes()+1,0,0);
//console.log("now", now);
//console.log("target", target);
//console.log("diff", target.getTime() - now.getTime());
document.getElementById('target').innerHTML = target;
timeout = setTimeout("timer()", target.getTime() - now.getTime() );
</script>
</body>

Change an image every minute using the computer's clock to time the changes

I want to change an image every minute. When the computer's clock moves from 8:50 to 8:51 then to 8:52 all the way back to 8:49 I want my picture to change from 0001.jpg to 0002.jpg to 0003.jpg all the way to 1440.jpg.
Since I am going to be using the computer's clock, I am interested in using JavaScript. I am also just starting out, so full code (which would be awesome!) is probably not what I need. Instead, I am looking for a place to start and maybe a direction to go. Any resources online that you know of would also be helpful
compute how many seconds until the next minute starts, then using setTimeout begin rotating the pictures. Use setInterval to do so every 60000 milliseconds.
var seconds = 60 - new Date().getSeconds();
setTimeout(function(){
console.log('start');
setInterval(function(){
console.log ('iterate over pictures here');
}, 1000 * 60);
}, seconds * 1000);
You can read more about both functions here
You'll want to study up on setInterval().
The code would look something like this:
var counter = 1,
lastUpdate = (new Date()).getTime(),
img = document.getElementById('image'); // Assuming your HTML has an img tag
// with an id of "image"
// This function just pads your number with 0s
function pad(num) {
var padding = '',
i = 4 - num.toString().length;
while (i > 0) {
padding += '0';
i -= 1;
}
return padding + num;
}
// This function is what actually does the updating
function update() {
var now = (new Date()).getTime();
if (lastUpdate + 1000 <= now) {
lastUpdate = now;
img.src = pad(counter) + '.jpg'; // change the image
counter += 1; // increment the counter
if (counter > 1440) { // reset to 1 if we get to our last image
counter = 1;
}
}
}
// Run update every 10th of a second
setInterval(update, 100);
The Mozilla Developer Center site has lots of great JavaScript and DOM references. I would also suggest learning to use JSLint, it will help a lot in avoiding stupid syntax errors that will cause headaches. I would suggest reading Douglas Crockford's book JavaSript: The Good Parts and Stoyan Stefanov's Object-Oriented JavaScript they are both excellent books to learn JavaScript from.
Place the code below in the BODY of a page:
<img />
<script>
var start = new Date().getTime(),
i = 0,
//get the node of the image to change
img = document.getElementsByTagName('IMG')[0];
setInterval(function(){
//what time is now
var now = new Date().getTime();
if(now - start > 60000){
//initialize the counter
start = now;
//overlay with 0's -> substr(-4)
//rotate on 1440 with a modulo -> i++ % 1440
img.src = ('000' + (i++ % 1440 + 1)).substr(-4) + '.jpg';
}
}, 10000); //check every 10 sec
</script>
If you start with Javascript a good reference is MDC
If you want to do this tied to the computer clock. Use the setInterval with a delay less than a second (<1000) and check the actual time with Date(). This way you can make your changes according to the clock.

Categories

Resources