First off, sorry for any bad English as it's not my primary language.
I'm having some troubles with Javascript. A certain file keeps crashing my browser (doesn't matter if it's Chrome, Firefox or IE) after a few minutes.
$().ready(function() {
timeAgo();
});
function timeAgo() {
$('time.time-ago').each(function() {
//Get datetime from the attribute
var ago = $(this).attr('datetime');
//Split it so we can convert it to a Date object as Firefox doesn't allow raw input
var spl = ago.split(' ');
var date = spl[0].split('-');
var time = spl[1].split(':');
//Convert to object
ago = new Date(date[0],date[1]-1,date[2],time[0],time[1],time[2]);
//Get current date
var now = new Date();
//Calculate difference in days
var days = dayYear(now) - dayYear(ago);
if(days < 0) days += 365;
var out = '';
//Get the propper string
if(days > 0) {
if(days == 1) {
out = 'Gisteren';
}else if(days < 7) {
out = days +' dagen geleden';
}else if(days < 14) {
out = 'Een week geleden';
}else{
out = ago.toLocaleDateString('nl-nl',{day: "numeric",month: "short",year: "numeric"});
}
}else{
var dif = Math.round((now - ago)/1000);
if(dif < 10) {
out = 'Zojuist';
}else if(dif < 60) {
out = 'Enkele seconden geleden';
}else if(dif < 120) {
out = 'Een minuut geleden';
}else if(dif < 60 * 60) {
out = Math.floor(dif/60)+' minuten geleden';
}else if(dif < 60 * 60 * 2) {
out = 'Een uur geleden';
}else{
out = Math.floor(dif/60/60)+' uur geleden';
}
}
$(this).html(out);
});
setInterval(function(){timeAgo()},10000);
}
function dayYear(now) {
var first = new Date(now.getFullYear(),0,1);
var day = Math.round(((now - first) / 1000 / 60 / 60 /24) + 0.5);
return day;
}
I call it with for example the following code.
<time datetime="2013-05-12 19:12:15"></time>
Thanks in advance.
The reason is that you keep calling setInterval inside every loop.
You should use setTimeout instead (or only call setInterval once)
The difference is that setInterval executes the given every x milliseconds.
setTimeoutexecutes the given code after exactly x milliseconds (once).
Since you call setInterval inside the timeAgo method, after a while you will have a lot of timers running, all spawning new timers and the amount of timers will grow exponentially, eventually resulting in a crash.
Related
I'm trying to add 7 days when the timer reaches 0.
Can you help?
It currently reaches negative values, but I want it to restart every Tuesdays for example.
Also, I found some solutions, but the timer was countdown was reset also on page refresh, and I don't want that.
// Countdown timer
function makeTimer() {
var endTime = new Date("October 18, 2020 08:00:00 EST");
var endTime = (Date.parse(endTime)) / 1000;
var now = new Date();
var now = (Date.parse(now) / 1000);
var timeLeft = endTime - now;
var days = Math.floor(timeLeft / 86400);
var hours = Math.floor((timeLeft - (days * 86400)) / 3600);
var minutes = Math.floor((timeLeft - (days * 86400) - (hours * 3600 )) / 60);
var seconds = Math.floor((timeLeft - (days * 86400) - (hours * 3600) - (minutes * 60)));
if (hours < "10") { hours = "0" + hours; }
if (minutes < "10") { minutes = "0" + minutes; }
if (seconds < "10") { seconds = "0" + seconds; }
$("#days").html(days + '<span class="camp">Days</span>');
$("#hours").html(hours + '<span class="camp">Hours</span>');
$("#minutes").html(minutes + '<span class="camp">Minutes</span>');
$("#seconds").html(seconds + '<span class="camp">Seconds</span>');
}
setInterval(function() { makeTimer();
}, 1000);
You have to give the browser a way to know what your end time is or it will go back to the original hardcoded value every time. Either store the data you need to start and end the calculations for a user on the server or use localStorage to do it in the browser only.
https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
So I've added a function called add7Days and I've got a check to see if the time left is less than 0.
This will add extra days to your variable each time it runs out.
I've also created an object as a global variable because if you are running this presumably for weeks you will start to run into memory leak issue if you are re-declaring the variables every second.
var countDownObject = {
'endDate': new Date('2020-10-19 23:45')
,'now': undefined
,'days': 0
,'hours': 0
,'minutes': 0
,'seconds': 0
,'timeLeft': 0
};
function countDown(){
countDownObject.now = new Date();
countDownObject.timeLeft = countDownObject.endDate - countDownObject.now;
if(timeLeft < 0) add7Days(); /* Function to change time left */
countDownObject.days = Math.floor(timeLeft / 86400);
countDownObject.hours = Math.floor((timeLeft - (days * 86400)) / 3600);
countDownObject.minutes = Math.floor((timeLeft - (days * 86400) - (hours * 3600 )) / 60);
countDownObject.seconds = Math.floor((timeLeft - (days * 86400) - (hours * 3600) - (minutes * 60)));
if(hours < 10) countDownObject.hours = "0" + hours;
if(minutes < 10) countDownObject.minutes = "0" + minutes;
if(seconds < 10) countDownObject.seconds = "0" + seconds;
$("#days").html(countDownObject.days + '<span class="camp">Days</span>');
$("#hours").html(countDownObject.hours + '<span class="camp">Hours</span>');
$("#minutes").html(countDownObject.minutes + '<span class="camp">Minutes</span>');
$("#seconds").html(countDownObject.seconds + '<span class="camp">Seconds</span>');
};
function add7Days(){
countDownObject.endDate.setDate(countDownObject.endDate.getDate() + 7);
countDownObject.timeLeft = countDownObject.endDate - countDownObject.now;
};
setInterval(function(){makeTimer();}, 1000);
[Edit]
If you are refreshing the browser you may want to store the object countDownObject as either local storage
//Set Object
localStorage.setItem("countDownObject", JSON.stringify(countDownObject));
//Get Object
var countDownObject = JSON.parse(localStorage.getItem("countDownObject"));
or as its own json file on the server.
An alternate approach for counting down to a specific day of the week and time, based on a specific time zone (Tuesday at 8AM, east coast time in your case) would be to use a third-party time API that you could access using an XMLHttpRequest (or fetch if you don’t need to support Internet Explorer).
The third-party time API would give you a JSON object with GMT time with the current offset for eastern time (I used New York for my JSFiddle example) for standard time or daylight savings time, and it would also note if daylight savings was in effect or not. This could be better than depending on the visitor’s computer time, which could be set to a different time zone (e.g. Phoenix, Arizona uses Mountain Standard Time year round).
Having access to a third party time API would let you resync your timer every so often, so the countdown timer wouldn’t drift too far from the actual end time. setInterval can be slow by around 0.3%, which over a 6 day period would be around 30 minutes.
XMLHttpRequest has an onerror event handler that could be used to connect to an alternative time API if the primary one is offline for some reason. IE10 and 11 support the onerror event handler.
// padStart polyfill for IE
if (!String.prototype.padStart) {
String.prototype.padStart = function padStart(targetLength, padString) {
//floor if number or convert non-number to 0;
targetLength = targetLength >> 0;
padString = String(typeof padString !== 'undefined' ? padString : ' ');
if (this.length > targetLength) {
return String(this);
} else {
targetLength = targetLength - this.length;
if (targetLength > padString.length) {
//append to original to ensure we are longer than needed
padString += padString.repeat(targetLength / padString.length);
}
return padString.slice(0, targetLength) + String(this);
}
};
}
function countdownTime (endDay, endTimeStr, reachedZero) {
var oReq;
var endingTimeObj;
var currentDateObj;
var countdownDisplay = document.getElementById("countdown");
var timeDisplay = document.getElementById("time");
var intervalID = null;
var endTime = {};
var numbers = endTimeStr.split(",").map(Number);
var cycleCount = 0;
endTime.hr = numbers[0];
endTime.min = numbers[1];
endTime.sec = numbers[2];
endTime.ms = numbers[3];
function countdown () {
var remainingDays;
var remainingHours;
var remainingMin;
var remainingSec;
var delta = endingTimeObj - currentDateObj;
if (delta <= 0) {
reachedZero(); // call the passed in function
endingTimeObj.setUTCDate(endingTimeObj.getUTCDate() + 7);
delta = endingTimeObj - currentDateObj;
}
remainingDays = Math.floor(delta / 86400000);
delta = delta - remainingDays * 86400000;
remainingHours = Math.floor(delta / 3600000);
delta = delta - remainingHours * 3600000;
remainingMin = Math.floor(delta / 60000);
delta = delta - remainingMin * 60000;
remainingSec = Math.floor(delta / 1000);
timeDisplay.innerHTML = remainingDays + ":" +
remainingHours.toString().padStart(2, "0") + ":" +
remainingMin.toString().padStart(2, "0") + "." +
remainingSec.toString().padStart(2, "0");
currentDateObj.setSeconds(currentDateObj.getSeconds() + 1);
// Sync the countdown after an hour to prevent too much drift
cycleCount += 1;
if (cycleCount >= 3600) {
load();
}
}
function reqListener () {
if(this.readyState === 4 && this.status === 200) {
// Stop the existing timer - will create a new timer in a moment
if (intervalID !== null) {
window.clearInterval(intervalID);
intervalID = null;
}
var obj = JSON.parse(this.responseText);
currentDateObj = new Date(obj.datetime);
endingTimeObj = new Date(obj.datetime);
console.log("GMT: " + currentDateObj.toUTCString());
currentDateObj.setHours(currentDateObj.getHours()
+ parseInt(obj.utc_offset,10));
console.log("ET: " + currentDateObj.toUTCString());
// Time to the next countdown finish
endingTimeObj.setUTCDate(currentDateObj.getUTCDate()
+ (7 + endDay - currentDateObj.getUTCDay()) % 7);
endingTimeObj.setUTCHours(endTime.hr, endTime.min, endTime.sec, endTime.ms);
if (currentDateObj > endingTimeObj) {
endingTimeObj.setUTCDate(endingTimeObj.getUTCDate() + 7);
}
console.log("End: " + endingTimeObj.toUTCString());
// display is initially hidden when first loaded
countdownDisplay.style.display = "block";
countdown();
intervalID = window.setInterval(countdown, 1000);
}
}
function load() {
cycleCount = 0;
oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
if (oReq.onerror !== undefined) {
// A function to connect to a different time API could go
// here (IE9 doesn't support onerror)
}
oReq.open("GET", "https://worldtimeapi.org/api/timezone/America/New_York");
oReq.send();
}
window.onload = load;
if ("visibilityState" in document) {
document.addEventListener("visibilitychange", function() {
if (document.visibilityState === "visible") {
load();
}
});
}
}
function reachedZeroAlert () {
document.body.style.backgroundColor = "red";
alert("Done");
document.body.style.backgroundColor = "white";
}
// Pass in the day (Sunday = 0),
// a string for the time of day the countdown should finish,
// an the function to execute when the countdown reaches zero
countdownTime(2, "08,0,0,0", reachedZeroAlert);
body {
background-color: white;
}
span {
margin: 0;
padding: 0;
}
#countdown {
font-family: monospace;
display: none;
}
.values {
font-size: 2rem;
margin-left: 0.625rem;
}
.labels {
font-size: 0.8rem;
}
.days {
margin-left: 0.1875rem;
}
.hours {
margin-left: 1.0625rem;
}
.minutes {
margin-left: 1.875rem;
}
.seconds {
margin-left: 1.5625rem;
}
<div id="countdown">
<div class="values">
<span id="time">5:22:43.04</span>
</div>
<div class="labels">
<span class="days">Days</span>
<span class="hours">Hr</span>
<span class="minutes">Min</span>
<span class="seconds">Sec</span>
</div>
</div>
In a JavaScript step in Pentaho Data Integration, I want calculate the time in hours which passes between one date and another.
After following along with this this blog post, I realize that I need to adjust the startDate and endDate values in the function below which fall outside business hours so that they're within business hours so the function doesn't return zero. The dates are in the format 09/27/2018 18:54:55.
Here's my attempt so far:
var Approve_Gap;
var created_at_copy;
var approved_at_copy1;
// Function that accepts two parameters and calculates
// the number of hours worked within that range
function workingHoursBetweenDates(startDate, endDate) {
// Store minutes worked
var minutesWorked = 0;
// Validate input
if (endDate < startDate) { return 0; }
// Loop from your Start to End dates (by hour)
var current = startDate;
// Define work range
var workHoursStart = 8;
var workHoursEnd = 17;
var includeWeekends = true;
// bring dates into business hours
if(current.getHours() > workHoursEnd) {
current = current - (current.getHours() - workHoursEnd);
}
else if(current.getHours() < workHoursStart) {
current = current + (workHoursStart - current.getHours())
}
if(endDate.getHours() > workHoursEnd) {
endDate = endDate - (endDate.getHours() - workHoursEnd);
}
else if(endDate.getHours() < workHoursStart) {
endDate = endDate + (workHoursStart - endDate.getHours())
}
// Loop while currentDate is less than end Date (by minutes)
while(current <= endDate){
// Is the current time within a work day (and if it
// occurs on a weekend or not)
if(current.getHours() >= workHoursStart && current.getHours() < workHoursEnd && (includeWeekends ? current.getDay() !== 0 && current.getDay() !== 6 : true)){
minutesWorked++;
}
// Increment current time
current.setTime(current.getTime() + 1000 * 60);
}
// Return the number of hours
return minutesWorked / 60;
}
Approve_Gap = workingHoursBetweenDates(created_at_copy, approved_at_copy1);
I got the dates into business hours by adjusting copies of the dates as shown below:
if(created_at_copy.getHours() >= workHoursEnd) {
created_at_copy.setDate(created_at_copy.getDate() + 1);
created_at_copy.setHours(8);
created_at_copy.setMinutes(0);
created_at_copy.setSeconds(0);
} else if(created_at_copy.getHours() < workHoursStart) {
created_at_copy.setHours(8);
created_at_copy.setMinutes(0);
created_at_copy.setSeconds(0);
}
if(approved_at_copy1.getHours() >= (workHoursEnd)) {
approved_at_copy1.setDate(approved_at_copy1.getDate() + 1);
approved_at_copy1.setHours(8);
approved_at_copy1.setMinutes(0);
created_at_copy.setSeconds(0);
} else if(approved_at_copy1.getHours() < workHoursStart) {
approved_at_copy1.setHours(8);
approved_at_copy1.setMinutes(0);
created_at_copy.setSeconds(0);
}
I am working on a stopwatch and for now it works, but I want that I can calculate the average of time people get. E.g. let's say I have 5 times in an array which looks like the following: scores = ["00:32:192", "00:30:126", "00:31:542", "00:25:236", "00:36:320"];. You may think now: What the hell is it? Well the times are in: minutes:seconds:milliseconds. The array is printed to the screen by using a for loop.
jQuery
var int,
ms=0,
s=0,
m=0;
$('#swatch').text("00:00:00");
function swatch(){
var startTime = new Date().getTime();
int = setInterval(function(){
var time = new Date().getTime();
var dif = time-startTime;
ms= dif%1000;
s = Math.floor(dif/1000)%60;
m = Math.floor(dif/1000/60)%60;
if(ms < 10) {
ms = '0'+ms;
}
if(s < 10) {
s = '0'+s;
}
if(m < 10) {
m = '0'+m;
}
$('#swatch').text(m+':'+s+':'+ ms);
},1);
}
var scores= [];
$(document).on('keydown', function(e){
var result = $('#swatch').text();
var i = parseInt(scores.length);
if(e.keyCode == 32 && !int){
swatch();
} else if (e.keyCode == 32){
clearInterval(int);
int=0;
scores.push(result);
$('#score ol').append('<li>' + scores[i] + '</li>');
if(scores.length >= 5) {
$('#ao5').html("ao5: 00:27:43");
$('#ao5').slideDown(500);
}
if (scores.length >= 12) {
$('#ao12').html("ao12: 00:27:43");
$('#ao12').slideDown(500);
}
}
});
In my code above this, you see this:
if(scores.length >= 5) {
$('#ao5').html("ao5: 00:27:43");
$('#ao5').slideDown(500);
}
if (scores.length >= 12) {
$('#ao12').html("ao12: 00:27:43");
$('#ao12').slideDown(500);
}
I want if the array has 5 different time values (as in the example above where I showed you the array format) it outputs the average on the screen. As you see I just filled it in for myself to picture it, but I want a function that calculates it. I am building this in jQuery because the timer worked better in here than in JS.
If some of you guys could give me an example and re-write my code with the function in it, that'd be great. I am really struggling with this for days to figure out how I can calculate an average of 5 and/or 12.
Thank you.
Note that the code I provide below doesn't rely on JQuery or any library directly. You feed it an array of 'time-strings', and it gives you back an average. You can use whatever library you choose to get that array of strings.
First, you need a utility function which breaks a time-string into it's component pieces:
var str_to_time = function(time_str) {
var pieces =time_str.split(':');
return {
minutes: parseInt(pieces[0], 10),
seconds: parseInt(pieces[1], 10),
milliseconds: parseInt(pieces[2], 10)
};
};
Now a function to convert an array of time-strings to an array of times:
var str_array_to_time_array = function(str_array) {
return str_array.map(str_to_time);
};
Lastly, a way to average all these values together:
var average_time = function(time_array) {
var minutes = 0;
var seconds = 0;
var milliseconds = 0;
for (var i = 0; i < time_array.length; i++) {
minutes += time_array[i].minutes;
seconds += time_array[i].seconds;
milliseconds += time_array[i].milliseconds;
}
minutes /= time_array.length;
seconds /= time_array.length;
milliseconds /= time_array.length;
// Minutes and seconds may be fractional. Carry the fractions down.
seconds += (minutes - Math.floor(minutes)) * 60;
minutes = Math.floor(minutes);
milliseconds += (seconds - Math.floor(seconds)) * 1000;
seconds = Math.floor(seconds);
milliseconds = Math.round(milliseconds);
// if milliseconds is >= 1000, add a second.
seconds += Math.floor(milliseconds / 1000);
milliseconds %= 1000;
// If seconds >= 60, add a minute.
minutes += Math.floor(seconds / 60);
seconds %= 60;
return {
minutes: minutes,
seconds: seconds,
milliseconds: milliseconds
};
};
Now you can call something like the following to get an average:
average_time(str_array_to_time_array(['33:23:354', '34:00:32']))
// Object {minutes: 33, seconds: 41, milliseconds: 693}
I am trying to display the time remaining for the next 5 minutes (snapped to the full 5 minutes of the current time e.g., 15:05, 15:10..)
I was able to achieve the same for the time remaining for next Hour (Not minutes):
<span class="timer"></span>
<script>
function secondPassed() {
var cur_date = new Date();
var hour = cur_date.getHours();
var minutes = cur_date.getMinutes();
var seconds = cur_date.getSeconds();
var minutes_remain = parseInt(59 - parseInt(minutes));
var seconds_remain = parseInt(60 - parseInt(seconds));
var timers = document.getElementsByClassName('timer');
for (var i = 0; i < timers.length; i++) {
timers[i].innerHTML = minutes_remain+":"+seconds_remain;
}
}
var countdownTimer = setInterval(secondPassed, 1000);
</script>
JSfiddle : http://jsfiddle.net/ov0oo5f7/
Something like this?
function secondPassed() {
var cur_date = new Date();
var minutes = cur_date.getMinutes();
var seconds = cur_date.getSeconds();
var timers = document.getElementsByClassName('timer');
for (var i = 0; i < timers.length; i++) {
timers[i].innerHTML = (4 - minutes % 5) + ":" + (seconds >= 50 ? "0" : "") + (59 - seconds);
}
}
var countdownTimer = setInterval(secondPassed, 1000);
<span class="timer"></span>
You can reduce the code a bit and to make it more accurate, use setTimeout and call the function as close as reasonable to the next full second. setInterval will slowly drift.
// Return the time to next 5 minutes as m:ss
function toNext5Min() {
// Get the current time
var secs = (new Date() / 1000 | 0) % 300;
// Function to add leading zero to single digit numbers
function z(n){return (n < 10? '0' : '') + n;}
// Return m:ss
return (5 - secs/60 | 0) + ':' + z(60 - (secs%60 || 60));
}
// Call the function just after the next full second
function runTimer() {
console.log(toNext5Min());
var now = new Date();
setTimeout(runTimer, 1020 - now % 1000);
}
The above ticks over on the full minute so that at say 10:00:00 it shows 5:00. If you'd rather is showed 0:00, then the last line of toNext5Min should be:
return (5 - (secs? secs/60 : 5) | 0) + ':' + z(60 - (secs%60 || 60));
This is what you need to change to get it to work the way you want:
var minutes = cur_date.getMinutes();
var seconds = cur_date.getSeconds();
try change it to this:
var minutes_remain = 5 - minutes%5 - 1;
var seconds_remain = 59 - seconds;
Try it out here: jsFiddle
Change your minutes remain to following line. It calculates current minute mod by 5 subtracted from 5, which is what you need.
function secondPassed() {
var cur_date = new Date();
var hour = cur_date.getHours();
var minutes = cur_date.getMinutes();
var seconds = cur_date.getSeconds();
var minutes_remain = parseInt(5 - parseInt(minutes%5));
var seconds_remain = parseInt(60 - parseInt(seconds));
var timers = document.getElementsByClassName('timer');
for (var i = 0; i < timers.length; i++) {
timers[i].innerHTML = minutes_remain+":"+seconds_remain;
}
}
var countdownTimer = setInterval(secondPassed, 1000);
Updated fiddle http://jsfiddle.net/ov0oo5f7/2/
You can work out what the next 5 minutes interval will be if you divide by 5, round it up, and multiply by 5 again.
You need to handle if you are on an exact minute otherwise minutes_remain will show as 1 minute less.
In terms of being accurate, you don't need to parseInt everywhere as they are all numbers already. I've tried to make it as efficient as possible. In any case, you are only checking it once a second, so you can't guarantee accuracy.
http://jsfiddle.net/ov0oo5f7/6/
function secondPassed() {
var cur_date = new Date();
var hour = cur_date.getHours();
// handle 0 seconds - would be 60 otherwise
var seconds_remain = 60 - (cur_date.getSeconds() || 60);
// handle ceil on 0 seconds - otherwise out by a minute
var minutes = cur_date.getMinutes() + (seconds_remain == 0 ? 0 : 1);
var minutes_remain = Math.ceil(minutes/5) * 5 - minutes;
var timers = document.getElementsByClassName('timer');
for (var i = 0; i < timers.length; i++) {
timers[i].innerHTML = minutes_remain+":"+seconds_remain;
}
}
var countdownTimer = setInterval(secondPassed, 1000);
If you are looking for the mechine time and counting it down for 5 minutes , then this might help -
var startTime = new Date();
function secondPassed() {
var cur_date = new Date();
if(parseInt((cur_date - startTime)/1000) >300 ){
window.clearInterval(countdownTimer);
}
var hour = cur_date.getHours();
var minutes = cur_date.getMinutes();
var seconds = cur_date.getSeconds();
var minutes_remain = parseInt(59 - parseInt(minutes));
var seconds_remain = parseInt(60 - parseInt(seconds));
var timers = document.getElementsByClassName('timer');
for (var i = 0; i < timers.length; i++) {
timers[i].innerHTML = minutes_remain+":"+seconds_remain;
}
}
var countdownTimer = setInterval(secondPassed, 1000);
A simple approach is nothing that 5 minutes are 5*60*1000 milliseconds, thus
var k = 5*60*1000;
var next5 = new Date(Math.ceil((new Date).getTime()/k)*k);
I have a countdown like this one:
var countdown = {
startInterval: function() {
var count = 600
var countorig = 600;
var currentId = setInterval(function() {
var min = (count - (count % 60)) / 60;
var sec = count % 60;
if (sec < 10) {
$('#timer').html(min + ':0' + sec);
} else {
$('#timer').html(min + ':' + sec);
}
$('#time').val(countorig - count);
if (count == 0) {
$('#form').submit();
}--count;
}, 1000);
countdown.intervalId = currentId;
}
};
It works. But if I load the page, the countdown starts but it stutter it is not "round" like a clock is.
JSFiddle.
setInterval isn’t exact. You should use Dates instead, to get an accurate time, and then choose an interval of less than one second to get a smoother clock. Here’s a demo!
var countdown = {
startInterval: function() {
var count = 600;
var start = new Date(); // The current date!
var currentId = setInterval(function() {
var difference = Math.max(0, count - (new Date() - start) / 1000 | 0);
var min = difference / 60 | 0;
var sec = difference % 60;
$('#timer').text(min + ':' + (sec < 10 ? '0' : '') + sec);
$('#time').val(difference);
if(count === 0) {
$('#form').submit();
}
}, 200);
countdown.intervalId = currentId;
}
};
It's never a good idea to assume your timers are exact. Instead, use delta timing.
var startTime = new Date().getTime();
setInterval(function() {
var elapsed = new Date().getTime()-startTime;
console.log("Been running for "+Math.floor(elapsed/1000)+" seconds");
},25);
That is because setInterval is not meant to be a high resolution timer. It will NOT hit every 1000 milliseconds on the dot. You might have swings as much as 20 to 30 milliseconds in either direction, resulting in a clock that is off.
Using Date.now(), this is a quick example of a countdown function ( x is milliseconds )
function countdown(x){
var o = {future: Date.now()+x, last:-1, i:null}; // object so we can pass by-ref if req.
o.i = setInterval( function() { // use o.i so we can clear interval
var remain = o.future - Date.now(),
secs = Math.floor( remain / 1000 ),
mins = 0;
if( remain < 0 ){ // finished, do whatever
return clearInterval(o.i); // then clear & exit
}
if( secs === o.last ) return; // skip this iteration if it's not been a second
o.last = secs; // else update last time
// do whatever you want for this new second
if( secs > 59 ) mins = Math.floor( secs / 60 ), secs = secs % 60;
console.log(
(mins < 10 ? '0'+mins : mins) + ':' +
(secs < 10 ? '0'+secs : secs) + ' remain.'
);
}, 100);
}
If you know it wont be used in IE, consider adding o as an argument to the callback function in the interval and also as the last argument to setInterval (so it is passed to the callback as first arg), which means closure is independent => callback can be defined anywhere.