I am attempting to implement a countdown timer to a specific point in time in the future. This point in time is always the same day of the week and hour, and is based on UTC time.
I am attempting to write a general function that given a day of the week and an hour, it will return a date object that represents that criteria in the future.
Examples:
getNextOccuranceOfUTCDayAndHour(1, 7);
Get the next occurrence of 7 am on Monday. If today is Monday, 5/25/2015 # midnight UTC, then this function should return a Date object representing Monday 6/1/2015 7 am UTC.
getNextOccuranceOfUTCDayAndHour(3, 13);
Get the next occurrence of 1 pm on Wednesday. If today is Tuesday, 5/26/2015 # midnight UTC, then this function should return a Date object representing Wednesday 5/27/2015 1 pm UTC.
I have attempted to write a function to do this and I have included the snippet below, but it only seems to work for some dates and not others. It's incredibly unreliable. I would prefer not to use Moment.js.
function getNextOccuranceOfUTCDayAndHour(day, hour) {
d = new Date();
d.setDate(d.getUTCDate() + (7 + day - d.getUTCDay()) % 7)
d.setUTCHours(hour, 0, 0, 0);
return d;
}
function format_seconds(t) {
var d = Math.floor(t / 86400);
var h = Math.floor(t % 86400 / 3600);
var m = Math.floor(t % 3600 / 60);
var s = Math.floor(t % 3600 % 60);
return ((d > 0 ? d + " d. " : "") +
(h > 0 ? h + " h. " : "") +
(m > 0 ? m + " m. " : "") +
s + " s.");
}
function update() {
var next_occurance = getNextOccuranceOfUTCDayAndHour(1, 7);
$('#next_occurance').text(next_occurance);
var ms = next_occurance - new Date();
$('#countdown').text(format_seconds(Math.floor(ms / 1000)));
}
$(function() {
update();
setInterval(update, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="next_occurance">Next Occurance</p>
<p id="countdown">Countdown</p>
Edit: Some examples of expected vs. returned values. JSFiddle
The problem in the original code was the use of d.setDate(); instead of d.setUTCDate();. Additionally, if the current day was the same day of week as the target day, then the result was incorrect. Simply adding an if statement to check for this case fixes that problem.
Updated JSFiddle: https://jsfiddle.net/2j49q0ak/1
Related
If the user sets a date on the backend (via jQuery DateTimer Picker) the following acf_vars.timer variable would look like this on the frontend:
2021 2 9 13 08 00
I have the following construct as a countdown timer (CODEPEN):
const [y, month, d, h, minute, s] = acf_vars.timer.split(' ');
// monthIndex in Date Object begins with 0, so we subtract 1
const countDownDate = new Date(y, month - 1, d, h, minute, s).getTime();
const updateCountdown = () => {
const now = new Date().getTime(); // Get today's date and time
const distance = countDownDate - now; // Find distance between now and the countdown date
const expiredTimer = distance <= 0;
let days = Math.floor(distance / (1000 * 60 * 60 * 24));
let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
let seconds = Math.floor((distance % (1000 * 60)) / 1000);
if (expiredTimer) {
days = hours = minutes = seconds = 0;
clearInterval(timerInterval);
}
document.querySelectorAll('.ticker').forEach((container) => {
container.children[0].classList.contains('days') &&
(container.children[0].textContent = days);
container.children[2].classList.contains('hours') &&
(container.children[2].textContent = hours);
container.children[4].classList.contains('minutes') &&
(container.children[4].textContent = minutes);
container.children[6].classList.contains('seconds') &&
(container.children[6].textContent = seconds);
});
};
const timerInterval = setInterval(updateCountdown, 1000);
updateCountdown();
If the user doesn't specify a future date on the backend, I'd like to use a fallback which automatically sets the countdown timer to the upcoming Sunday at 9am. To solve this I tried setting a standardized countDownDate variable but I'm having trouble coming up with a way to set the day and time to automatically be the upcoming Sunday at 9am.
It seems you just want a way to set a date to next Sunday at 09:00. In plain JS it might be:
/* Get a date for next occurence of Sunday at 09:00
*
* #param {Date} d - start date, default is current date and time
* #returns {Date} for next Sunday at 09:00 after d
*/
function getNextSunday(d = new Date()) {
// Create date for next Sun at 9
let sun = new Date(d.getFullYear(), d.getMonth(), d.getDate() + (7 - (d.getDay() || 7)), 9, 0, 0, 0);
// If date is same day but later, move to next Sun
sun <= d? sun.setDate(sun.getDate() + 7) : null;
return sun;
}
// Examples
// Next Sunday at 9:00
console.log(getNextSunday().toString());
// Next Sunday after Sun 7 Feb at 8:59:59
console.log(getNextSunday(new Date(2021, 1, 7, 8, 59, 59)).toString());
// Next Sunday after Sun 7 Feb at 9:00
console.log(getNextSunday(new Date(2021, 1, 7, 9)).toString());
Notes:
d.getDay() || 7 is used so that if getDay returns 0 (Sunday), it's replaced with the number 7. That means the expression sets sun to the current day if it's Sunday or the next Sunday if it isn't. Otherwise on Sundays it would create a Date for the previous Sunday.
sun <= d? sun.setDate(sun.getDate() + 7) : null is used so that if the current date is Sunday but the time is after the specified time (in this case 9:00) the date is moved to the following Sunday at 9:00. Using the compound ? : operator this way is just a another way of writing if (sun <= d) sun.setDate(sun.getDate() + 7) on one line. I prefer if statements to be followed by a block and would rather use ? : for simple expressions on single lines.
Moment.js might be what you are looking for.
moment().endOf('week').add(1, 'second').add(9, 'hours').toString()
End of week uses the locale aware week start day, so you might have to configure it if you have users globally.
Edit
Alternatively, if you do not want to use external libraries you can check the current weekday and hour with the JavaScript Date object.
const day = countDownDate.getDay() // weekday sun = 0, sat = 6
const hour = countDownDate.getHours() // 0 - 23
Within your logic, you would want to get the distance between day and 0 (also accounting for countDownDate starting on a Sunday) and hour and 9. However, another way to implement this is to check the current date upon each update which could reduce the error in case the interval gets interrupted.
I am currently working on Jvascript datetime part in that getting NaN error while converting hours and minutes to seconds like strtotime in PHP so I want to know how to convert minutes and seconds like the way we do in strtotime in PHP.
var d = new Date();
var total = d.getHours() + ":" + d.getMinutes();
var ts = Date.parse(total);
document.write(ts);
In output getting error NaN
This is a sort of inane question, but here's the number of seconds in the hours and minutes of that number:
var d = new Date();
var total = (d.getHours() * 60 * 60) + (d.getMinutes() * 60);
document.write(total);
First of all, Date.parse() takes a string of a specific format (such as Jul 18, 2018). Second, it will not convert the date to seconds, but will return the number of milliseconds since January 1, 1970 00:00:00 GMT.
If you need to convert hh:mm to seconds, the correct approach is to multiply the value of getHours() by 3600 and multiply the value of getMinutes() by 60, then sum up the two values.
var d = new Date();
var timeinsecs = d.getHours() * 3600 + d.getMinutes() * 60;
document.write(timeinsecs);
While if you need to get the time in seconds from January 1, 1970 00:00:00 GMT till the current time, you will need to parse the current date then divide by 1000:
var d = new Date();
document.write(Date.parse(d) / 1000);
Just get hours and minutes, then sum them multiplying hours * 3600 and minutes * 60, like this
var d = new Date();
var total = d.getHours() * 3600 + d.getMinutes() * 60;
document.write(total)
If you want to follow your original approach of not doing the math by hand, you need to include a date before the time (any date should do, could be today if you wish) and convert ms to seconds (both of these for the reasons Wais Kamal pointed out) as follows.
var d = new Date();
var total = d.getHours() + ":" + d.getMinutes();
var someDate ='July 4, 1776';//works, but maybe safer to choose since 1990
total=someDate+', '+total;
var ts = Date.parse(total);
document.write((ts- Date.parse(someDate))/1000);
I see that I various times like
01:45
//and
15:00
I assume that date is HH:MM in military ?
While have I seen some advanced functions then parse sentences and even some using the seconds like HH:MM:SS , I am wanting a simple and accurate way of getting the HH:MM
So I assume 15:00 is 3:00 ?
This function below is not going to work because I already have ":"
so below assumed HHMM right? when I believe I need HH:MM to be parsed ?
var getTravelTimeFormatted = function (str) {
var hours = Math.trunc(str / 60),
minutes = str % 60;
return hours + ':' + minutes;
};
Update
Ok, I assume that 15:00 is 3:00 , right?
So i stripped out the incoming ":" and then add it back
problem is the result is 25.0 so what does that mean?
var getTravelTimeFormatted = function (str) {
str = str.replace(/:/g,'');
var hours = Math.trunc(str / 60),
minutes = str % 60;
return hours + ':' + minutes;
};
console.log(getTravelTimeFormatted('15:00'));
Given a string HH:MM you can just split then subtract 12 hours. Here's a naive solution that doesn't check for invalid input.
function TwelveHourFormat(time) {
var dtParts = time.split(":");
var hours = dtParts[0];
var minutes = dtParts[1];
var suffix = "AM";
if (hours > 12) {
hours = hours - 12;
suffix = "PM";
}
else if (hours == "00") {
hours = 12;
suffix = "AM";
}
else if (hours == "12") {
suffix = "PM";
}
return (hours + ":" + minutes + " " + suffix);
}
This is a duplicate of Converting 24 hour time to 12 hour time w/ AM & PM using Javascript. Jasen's answer is fine, and more concise than the duplicate, but the function can be a little more concise:
/* Convert time in 24 hour hh:mm format to 12 hour h:mm ap format
** #param {string} time - in hh:mm format (e.g. 14:30)
** #returns {string} time in 12 hour format (e.g. 2:30 PM)
*/
function to12HourTime(time) {
var b = time.split(/\D/);
return (b[0]%12 || 12) + ':' + b[1] +
(b[0]<11? ' AM' : ' PM');
}
// Some tests
['23:15','2:15','03:15','00:30'].forEach(function(v) {
console.log(v + ' => ' + to12HourTime(v));
});
This question already has answers here:
Javascript, Time and Date: Getting the current minute, hour, day, week, month, year of a given millisecond time
(4 answers)
Closed 6 years ago.
I'm working on a project where I need to get the hours and minutes alone without the semicolon (:) separating them, and represent them in a variable, myTime, as a 4-digit number. Here is my code:
var now = new Date();
var time = now.toString().substr(16,5)
Use the .getHours() and .getMinutes() methods of Date objects to get these numbers. To get a 4-digit number representation (as a zero-padded string), concatenate and zero-pad as necessary with ('0000' + (hours * 100 + minutes)).slice(-4)as demonstrated below:
var now = new Date();
var hours = now.getHours();
var minutes = now.getMinutes();
var myTime = ('0000' + (hours * 100 + minutes)).slice(-4);
//note that myTime is a zero-padded string of length 4
console.log(now.toString(), hours, minutes, myTime);
To get Hours or Minutes from a datetime use the associated functions myDate.getHours() or myDate.getMinutes()
Edit: you probably don't want military time so adding 12 hour conversion...
var mt = getHoursMinutesSeconds(new Date());
alert(mt);
function getHoursMinutesSeconds(date) {
var h = date.getHours();
h = ((h + 11) % 12 + 1);
var m = date.getMinutes();
var myTime = addZero(h) + addZero(m);
return myTime;
}
function addZero(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
Having two strings (start and end time) in such form "16:30", "02:13" I want to compare them and check if the gap is greater than 5 mins.
How can this be achieved in Javascript in an easy way?
function parseTime(time) {
var timeArray = time.split(/:/);
// Using Jan 1st, 2010 as a "base date". Any other date should work.
return new Date(2010, 0, 1, +timeArray[0], +timeArray[1], 0);
}
var diff = Math.abs(parseTime("16:30").getTime() - parseTime("02:13").getTime());
if (diff > 5 * 60 * 1000) { // Difference is in milliseconds
alert("More that 5 mins.");
}
Do you need to wrap over midnight? Then this is more difficult. For example, 23:59 and 00:01 will produce a difference of 23 hours 58 minutes and not 2 minutes.
If that's the case you need to define your case more closely.
You can do as following:
if (((Date.parse("16:30") - Date.parse("02:13")) / 1000 / 60) > 5)
{
}
// time is a string having format "hh:mm"
function Time(time) {
var args = time.split(":");
var hours = args[0], minutes = args[1];
this.milliseconds = ((hours * 3600) + (minutes * 60)) * 1000;
}
Time.prototype.valueOf = function() {
return this.milliseconds;
}
// converts the given minutes to milliseconds
Number.prototype.minutes = function() {
return this * (1000 * 60);
}
Subtracting the times forces the object to evaluate it's value by calling the valueOf method that returns the given time in milliseconds. The minutes method is another convenience method to convert the given number of minutes to milliseconds, so we can use that as a base for comparison throughout.
new Time('16:30') - new Time('16:24') > (5).minutes() // true
This includes checking whether midnight is between the two times (as per your example).
var startTime = "16:30", endTime = "02:13";
var parsedStartTime = Date.parse("2010/1/1 " + startTime),
parsedEndTime = Date.parse("2010/1/1 " + endTime);
// if end date is parsed as smaller than start date, parse as the next day,
// to pick up on running over midnight
if ( parsedEndTime < parsedStartTime ) ed = Date.parse("2010/1/2 " + endTime);
var differenceInMinutes = ((parsedEndTime - parsedStartTime) / 60 / 1000);
if ( differenceInMinutes > 5 ) {
alert("More than 5 mins.");
}