I worked with this:
(function() {
var timeElement, eventTime, currentTime, duration, interval, intervalId;
interval = 1000; // 1 second
// get time element
timeElement = document.querySelector("#countdown");
// calculate difference between two times
eventTime = moment.tz("2022-05-29T08:00:00", "Europe/Berlin");
// based on time set in user's computer time / OS
currentTime = moment.tz();
// get duration between two times
duration = moment.duration(eventTime.diff(currentTime));
// loop to countdown every 1 second
setInterval(function() {
// get updated duration
duration = moment.duration(duration - interval, 'milliseconds');
// if duration is >= 0
if (duration.asSeconds() <= 0) {
clearInterval(intervalId);
// hide the countdown element
timeElement.classList.add("hidden");
} else {
// otherwise, show the updated countdown
timeElement.innerText = duration.days() + ":" + duration.hours() + ":" + duration.minutes() + ":" + duration.seconds();
}
}, interval);
}());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment-with-locales.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.17/moment-timezone-with-data-2012-2022.min.js"></script>
<div id="countdown"></div>
Unfortunately, the time doesn't get calculated correctly. If you change for example 2022-05-29 to 2022-08-29, nothing changes. Additionally, every value should have two digits.
Has someone an idea to fix that? Would be very thankful!
Your question about momentjs is answered here; use asDays() not days()
You can pad a string with 0's using the function padStart(length, withWhat) Mozilla Developer Network Documentation
//...snip...
} else {
// otherwise, show the updated countdown
timeElement.innerText =
duration.asDays().toFixed().padStart(2, 0) + ":" +
duration.hours().toString().padStart(2, 0) + ":" +
duration.minutes().toString().padStart(2, 0) + ":" +
duration.seconds().toString().padStart(2, 0);
}
//...snip...
Related
I am trying two create to separate timers. One timer counts down to a date and displays a countdown and the other counts down on an interval and resets (ie: 5 hours and resets).
The one I am having trouble with is the second option. I am trying to create a countdown that is relative to real-time and then resets once it reaches zero. So for example setting it to 2 days and 5 hours. Once this completes the clock resets to 2 days 5 hours. I am having trouble getting the clock to reset at the specified time and loop without having negative numbers. I tried this two separate ways but feel like I am over-complicating things.
The reason I use real-time is so that the clock will be the same if you open it in another tab. If I create a regular timer it will reset upon refreshing the page.
codpen
In this example I tried to reset the counter every 40 seconds but couldn't get it to work. Ultimately I want to be able to specify the date with ie: 00:12:00 (12 hours countdown) and then have it reset automatically. I just can't figure out how to maintain the counting without going to negative numbers or freezing it.
function timer() {
var currentTime = new Date()
var date = currentTime.getDate()
var hours = currentTime.getHours()
var minutes = currentTime.getMinutes()
var seconds = currentTime.getSeconds()
var daysLeft = 0;
var hoursLeft = 24 - hours;
var minsLeft = 60 - minutes;
var secsLeft = 60 - seconds;
// counter freezes at 40 seconds and hangs for 20seconds
if(secsLeft => 40) {
secsLeft = 40 - seconds
if(secsLeft < 0) {
secsLeft = 40
}
}
document.getElementById('timerUpFront').innerHTML= "<br><br><strong>Duration Countdown with Infinite Reset #2</strong><br>" + daysLeft + " days " + hoursLeft + " hours " + minsLeft + " minutes " + secsLeft + " seconds";
}
var countdownTimer = setInterval('timer()', 1000);
codpen
you can separate the timer to functions to simplify it and apply the following logic
function startTimer () {
val targetRemainedSeconds = // calculate the value
val remainedSeconds = targetRemainedSeconds
setInterval(timer(), 1000)
}
function timer () {
remainedSeconds--
if (remainedSeconds < 0) reaminedSeconds = targetReaminedSeconds // reset the timer
timerUpdate()
}
function timerUpdate() {
// use 'remainedSeconds' to update timer
}
Here's the scenario, I have a time that counts the time_taken by a user. What I want is to get the exact time_taken based from the timer. For example, a user take an exam, then after he/she take the exam, the time_taken will be submitted (e.g. 1hr 25mins 23secs). Please see my code below.
$(document).ready(function(){
var d;
setInterval(function(){
d = new Date();
dates = d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
$('#timeTaken').val(dates);
}, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="timeTaken" value="">
Here is Fiddle for the solution
https://jsfiddle.net/djzsddz6/1/
Ans Solution is below:
$(document).ready(function(){
var seconds = 0, minutes = 0 , hours = 0;
setInterval(function(){
seconds++;
if(seconds == 60){
minutes++
seconds = 0;
}
if(minutes == 60){
hours++
minutes = 0;
}
console.log(hours, minutes, seconds);
$('#timeTaken').val(`${hours}:${minutes}:${seconds}`);
}, 1000);
});
I don't really see the point to use an input there, you can just display in a span and when the form gets submitted take the time elapsed and send it with other data. Anyways, this should work for you:
$(document).ready(function () {
var time_start = new Date();
setInterval(function () {
var time_end = new Date();
var time_diff = (time_end - time_start);
// hours
var hours = Math.floor(time_diff / 1000 / 60 / 60);
// minutes
time_diff = time_diff - hours * 1000 * 60 * 60;
var minutes = Math.floor(time_diff / 1000 / 60);
// seconds
time_diff = time_diff - minutes * 1000 * 60;
var seconds = Math.floor(time_diff / 1000);
renderTime(hours, minutes, seconds);
}, 1000);
});
function renderTime (hrs, min, sec) {
var str = convertTime(hrs) + ":" + convertTime(min) + ":" + convertTime(sec);
$("#timeTaken").val(str);
}
function convertTime (val) {
return val < 10 ? "0" + val : val;
}
What's going on here is we have the time_start which does not change and we have setInterval function that is triggered every second. There we create new Date object, and the subtract the static one from it, which returns the time difference in milliseconds. We do the weird Math.flooring and subtracting, so we can have hours, minutes and seconds as an integers (not floats). Then we use render function to display the time inside an desired element.
Why I think it's a better solution then the others are, is that if you want to handle the user's page refresh you just need to save one variable to cookie or something else and it will work regardless of the page refresh.
Handling the page refresh would look like (with cookie saved for 2 hrs):
function updateTimeCookie () {
var time_now = new Date()
var value = JSON.stringify(time_now);
var expires = time_now.setTime(time_now.getTime() + 7200);
$.cookie("timeStart", value, { expires: expires });
};
// to get Date object from cookie: new Date(JSON.parse($.cookie("timeStart")))
To use $.cookie() you must first include jQuery Cookie Plugin.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
Working fiddle without cookie: https://jsfiddle.net/qc3axmf4/1/
Working fiddle with cookie: https://jsfiddle.net/ta8bnzs0/2/
Rather than getting date at every second you can keep the counter in set interval which will updated at every second. At the time of submission you can perform division and modulus operation to get exact time taken
Example
$(document).ready(function(){
var timer =0;
setInterval(function(){
Timer +=1;
// Code for display in hr mm and ss
$('#timeTaken').val(dates);
}, 1000'
});
You can also convert second in time valueby using moment.js
Hope this helps you.
Happy coding
Trying to build a very simple Javascript countdown. However, whenever the tab is inactive, the countdown begins to lag and holds an incorrect count.
See jsfiddle here for example: https://jsfiddle.net/gbx4ftcn/
function initTimer(t) {
var self = this,
timerEl = document.querySelector('.timer'),
minutesGroupEl = timerEl.querySelector('.minutes-group'),
secondsGroupEl = timerEl.querySelector('.seconds-group'),
minutesGroup = {
firstNum: minutesGroupEl.querySelector('.first'),
secondNum: minutesGroupEl.querySelector('.second')
},
secondsGroup = {
firstNum: secondsGroupEl.querySelector('.first'),
secondNum: secondsGroupEl.querySelector('.second')
};
var time = {
min: t.split(':')[0],
sec: t.split(':')[1]
};
var timeNumbers;
function updateTimer() {
var timestr;
var date = new Date();
date.setHours(0);
date.setMinutes(time.min);
date.setSeconds(time.sec);
var newDate = new Date(date.valueOf() - 1000);
var temp = newDate.toTimeString().split(" ");
var tempsplit = temp[0].split(':');
time.min = tempsplit[1];
time.sec = tempsplit[2];
timestr = time.min + time.sec;
timeNumbers = timestr.split('');
updateTimerDisplay(timeNumbers);
if (timestr === '0000')
countdownFinished();
if (timestr != '0000')
setTimeout(updateTimer, 1000);
}
function animateNum(group, arrayValue) {
TweenMax.killTweensOf(group.querySelector('.number-grp-wrp'));
TweenMax.to(group.querySelector('.number-grp-wrp'), 1, {
y: -group.querySelector('.num-' + arrayValue).offsetTop
});
}
setTimeout(updateTimer, 1000);
}
I'm unsure whether the problem lies with the animation, or with the JS code itself.
For clarification: I want the countdown to continue when the tab is inactive, or to 'catch up with itself' when the tab comes back in to focus.
I know that setTimeout and setInterval can cause issues with inactive tabs, but I'm not entirely sure how to fix this.
Any help would be much appreciated!
For this you can use the HTML5 Visibility API for detecting if the browser tab is active or not. And use regular binding of event handlers for focus and blur for the browser window.
Basically you pause() the timeline when you blur out of the tab, and then play() when you give the tab refocus. Example of this in action:
http://codepen.io/jonathan/pen/sxgJl
// Set the name of the hidden property and the change event for visibility
var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.mozHidden !== "undefined") {
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
// If the page is hidden, pause the video;
// if the page is shown, play the video
function handleVisibilityChange() {
if (document[hidden]) {
tl.pause();
} else {
tl.play();
}
}
// Warn if the browser doesn't support addEventListener or the Page Visibility API
if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
// do nothing or throw error via alert()
alert("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
} else {
// Handle page visibility change
// Pause timeline
tl.pause();
}
HTML5 Visibility Docs:
https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
Regarding GreenSock Forum Topic:
http://forums.greensock.com/topic/9059-cross-browser-to-detect-tab-or-window-is-active-so-animations-stay-in-sync-using-html5-visibility-api/
Also in GSAP the equivalent for setTimeout() is delayedCall()
Provides a simple way to call a function after a set amount of time (or frames). You can optionally pass any number of parameters to the function too.
GSAP delayedCall(): http://greensock.com/docs/#/HTML5/GSAP/TweenMax/delayedCall/
//calls myFunction after 1 second and passes 2 parameters:
TweenMax.delayedCall(1, myFunction, ["param1", "param2"]);
function myFunction(param1, param2) {
//do stuff
}
I hope this helps!
before all, i have to mention that, those countdown animation is truly outstanding and elegant dear sir! well done...
Now to the answers:
as mentioned in many articles, and here is one of them:
setInterval(func, delay) does not guarantee a given delay between
executions. There are cases when the real delay is more or less than
given. In fact, it doesn’t guarantee that there be any delay at all.
Source: http://javascript.info/tutorial/settimeout-setinterval
and..
Most browsers apply performance improvements by reducing the priority
of several tasks on inactive tabs or even some portions of the page
that aren't on screen. Sometimes these improvements affects the
executions of Javascript intervals as well.
Source: How can I make setInterval also work when a tab is inactive in Chrome?
as you can see, they mentioned that setInterval does not guarantee a given delay between executions even when the tab is active, and lets just assume that setTimeout (the one that you used) is also the same because they are relatively is "the same"
so what is the solution to this problem?
well, what you actually can do is check how many times has actually elapsed between the event, something like this Codepen
EDIT: as you have requested, here is a fiddle of your countdown with the fix, and i have //commented on the changes i made to the fiddle, so it would hopefully make it easier for you to understand. So now, when you paired the countdown to other timer (ex. your phone's timer) you should get the same result even when the tab is inactive or the frame rate slowdown.
if you have enjoyed my answer please consider mark it as "the answer" or at least up vote it ;)
The simplest way to ensure the timer stays correct when a user moves off the tab and then returns is to use session storage - to store the original starting time:
on the first load - get the local current datetime and store into session storage (note that will only accept a string - so you will have to stringify the value and then parse it out again upon retrieval).
when the tab loses focus that set start time will still be stored as startTime in ss. When the tab regains focus - have a function that gets the new current datetime, gets the stored datedtime from session storage and calculates the difference. Then the timer can be updated to the new reduced time.
Eg if its 10:00 am on page load - set the startTime into ss. Then the user spends 1 minute on the site and goes offsite for 5 minutes. Upon returning - the above described process will determine the current time is 10:06 and determine that its 6 minutes later than the start time so can update the timer as such.
This avoids the need for intervals and timers etc. You can take the specificity down to ms if needed. And also - I like your fiddle too.
You can use this code. Each time the tab changes, it calculates the end time again and updates the counter.
let interval;
let duration=timeDifference(endTime(),nowDate())
updateTime();
$(window).focus(function () {
clearInterval(interval)
updateTime();
});
function updateTime() {
interval = setInterval(function () {
var timer = duration.split(':');
//by parsing integer, I avoid all extra string processing
var hours = parseInt(timer[0], 10);
var minutes = parseInt(timer[1], 10);
var seconds = parseInt(timer[2], 10);
--seconds;
minutes = (seconds < 0) ? --minutes : minutes;
if (minutes < 0) clearInterval(interval);
seconds = (seconds < 0) ? 59 : seconds;
seconds = (seconds < 10) ? '0' + seconds : seconds;
hours = (hours < 10) ? '0' + hours : hours;
//minutes = (minutes < 10) ? minutes : minutes;
$('.countdown').html(hours + ':' + minutes + ':' + seconds);
duration = hours + ':' + minutes + ':' + seconds;
}, 1000);
}
function nowDate() {
let date = new Date()
let time1 = new Date();
date = date.toISOString().slice(0, 10);
date = date.split('-');
return new Date(date[2] + '/' + date[1] + '/' + date[0] + " " + time1.getHours() + ":" + time1.getMinutes() + ":" + time1.getSeconds());
}
function endTime() {
let endTime = $('input[name=end_date]').val();
endTime = endTime.split(' ');
let date = endTime[0].split('-');
let time = endTime[1];
return new Date(date[2] + '/' + date[1] + '/' + date[0] + " " + time);
}
function timeDifference(date1,date2) {
var difference = date1.getTime() - date2.getTime();
var daysDifference = Math.floor(difference/1000/60/60/24);
difference -= daysDifference*1000*60*60*24
var hoursDifference = Math.floor(difference/1000/60/60);
difference -= hoursDifference*1000*60*60
var minutesDifference = Math.floor(difference/1000/60);
difference -= minutesDifference*1000*60
var secondsDifference = Math.floor(difference/1000);
return hoursDifference +":"+minutesDifference+":"+secondsDifference
}
I have made a memory game with a timer that start at 10 minutes and counts down every second to 0. This function is only called once and has the following setInterval function:
game.countdown = setInterval(function() {
if(game.timeLeft <= 0){
gameEnded = true;
}
if(!gameEnded){
// lower one second
game.timeLeft--;
var timespan = document.querySelector('.timeleft');
var minutes = pad(Math.floor((game.timeLeft / 60)),2 );
var newSeconds = pad(Math.floor(game.timeLeft - (minutes * 60)),2 );
function pad(num, size) {
var s = num+"";
while (s.length < size) s = "0" + s;
return s;
}
var niceTime = minutes + ":" + newSeconds;
timespan.innerHTML = niceTime;
// Then alter time bar on .innertimer
// Calculate percentage starting at 0%
var percentageDone = (Math.floor((10*60 - game.timeLeft) / (10*60) * 10000) / 100);
$(".timer").css({"background": "-webkit-linear-gradient(left, white " + percentageDone + "%, green " + percentageDone + "%)"});
}
}, 1000);
I store the setInterval in object game under variable name countdown. When the game is ended I call another function that has the clearInterval:
clearInterval(game.countdown);
Then when it goes to the next level it calls the setInterval function again and stores it again in game.countdown. But now for every second it takes 2 seconds. The next level 3 seconds. You can see there are multiple setInterval's at work because it's not done at the same time.
Hope someone can really help me out debugging this problem.
What I've done to work around the issue is the following. The interval is only being called if the following is true:
if (undefined == game.countdown){
This way if there is a countdown defined it's calling it again. And since I'm storing the game.timeLeft not in the function itself I can just refill game.timeLeft.
I am using timer in my project , I am having two problems in it. When start button is press time should start & when end button is press time should end.
But 1)when end button is clicked
time is not stopping .
2)when time decrease & reach 1 minute..time is stopped ..it should reduse in seconds also
var tim;
var min = 10;
var sec = 10;
var f = new Date();
function f1() {
f2();
document.getElementById("starttime").innerHTML = "Your started your Exam at " + f.getHours() + ":" + f.getMinutes();
}
function f2() {
if (parseInt(sec) > 0) {
sec = parseInt(sec) - 1;
document.getElementById("showtime").innerHTML = "Your Left Time is :" + min + " Minutes ," + sec + " Seconds";
tim = setTimeout("f2()", 1000);
} else {
if (parseInt(sec) == 0) {
min = parseInt(min) - 1;
if (parseInt(min) == 0) {
clearTimeout(tim);
location.href = ".././Home/Login";
} else {
sec = 60;
document.getElementById("showtime").innerHTML = "Your Left Time is :" + min + " Minutes ," + sec + " Seconds";
tim = setTimeout("f2()", 1000);
}
}
}
}
My suggestion would be this:
Fiddle
var tim;
var sec;
var f = new Date();
function f1() {
sec = 10 * 60;
f2();
document.getElementById("starttime").innerHTML = "Your started your Exam at " + f.getHours() + ":" + f.getMinutes();
}
function f2() {
if (sec > 0) {
sec--;
tim = setTimeout(f2, 1000);
} else {
document.getElementById("starttime").innerHTML = "times up!!!!";
}
var min = Math.floor(sec / 60);
var secDisplay = sec % 60;
document.getElementById("showtime").innerHTML = "Your Left Time is : " + min + " Minutes," + secDisplay + " Seconds";
}
function end() {
clearTimeout(tim);
sec = 0;
f2();
}
Changes are:
Removed the min variable and only use the total seconds instead of two variables. We can easily calculate the minutes based on the total seconds, for the display purposes. Using the seconds variable makes it much easier to check the time remaining. As you can see the code is simplified a lot.
Changed the setTimeout to take the function as an argument, not a string.
Added end() function, to be called when the end button is clicked.
Moved the seconds count to inside f1() so that it can be started and ended repeatedly without reloading the page.
Removed unnecessary parseInt() calls. The sec variable is already of numerical type so no need to convert it.
The timer will stop when the seconds reduce to 0. If you want it to stop when the time remaining reaches one minute, just change the condition in f2() to if (sec > 60) {
For your first question about the end button i cannot see any end button functionality. but you could have a stop function that clears the timeout.
function f3() {
clearTimeout(tim);
//update any text you wish here or move to the next page..
}
For your second question why it ends at 1 minute. You are decreasing the minute value before you check if it is zero. So when you come to f2, sec is 0 and min is 1 you then decrease min to 0.. And then check if it is zero and end the execution.
To solve that move your "min = parseInt(min) - 1;" to after the else and it should count the last minute too.
PS. you don't need parseint since you are using numbers allready