Reputation: 61
I'm a PHP programmer who seldom uses Javascript, so I need help figuring out how to accomplish this with JS or JQuery (I currently have jquery-1.7.min.js). I've created three clocks showing the time in different timezones with PHP, and I'd like to use JS to increment the times every minute.
The HTML for a clock is like this:
<div class="clock">
<div class="pm"></div>
<div class="time">11:59</div>
</div>
After adding one minute it should be like this:
<div class="clock">
<div class="am"></div>
<div class="time">00:00</div>
</div>
This is what I've got so far:
var myVar = setInterval(function(){setClocks()},60000);
function setClocks()
{
$(".clock").each(function() {
var ampm = $("div:first-child");
var time = $(".time");
// add one minute to time and toggle am/pm if needed
time.innerHTML = newTime;
}
}
Any help would be greatly appreciated.
UPDATE:
I've got it, thanks to Dead133 and kei. This is my updated code:
var myVar = setInterval(function(){setClocks()}, 60000);
function setClocks()
{
$(".clock").each(function() {
var ampm = $("div:first-child", $(this));
var time = $(".time", $(this));
var parts = time.text().split(':');
var hours = parseInt(parts[0], 10);
var minutes = parseInt(parts[1], 10);
++minutes;
if (minutes == 60)
{
minutes = 0;
++hours;
if (hours == 12)
{
ampm.toggleClass('am');
ampm.toggleClass('pm');
}
}
if (hours > 12) hours -= 12;
if (hours.toString().length < 2) hours = "0" + hours;
if (minutes.toString().length < 2) minutes = "0" + minutes;
time.text(hours + ':' + minutes);
})
}
Thanks for the help, everybody! I'd done this kind of thing in PHP, so I knew the logic. It was just the JS/JQ that was hanging me up.
Upvotes: 0
Views: 1732
Reputation: 477
I use moment()
library to do it, here an example :
console.log(moment('12:30', 'HH:mm').add(60, 'm').format("HH:mm"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
Upvotes: 1
Reputation: 2776
thanks to kei for improving my answer and adding this DEMO
var myVar = setInterval(function(){setClocks()},60000);
function setClocks() {
$(".clock").each(function() {
var ampm = $("div:first-child", $(this)); // $(this) is important since you're dealing with 3 clocks
var time = $(".time", $(this));
var clockTime = time.text().split(':'),
hours = clockTime[0],
minutes = clockTime[1];
++minutes;
if (minutes == 60) {
minutes = 0;
++hours;
if (hours == 12) {
hours = 0;
ampm.toggleClass('am')
.toggleClass('pm');
}
}
if (hours.toString().length < 2) hours = "0"+hours; // Added padding to the digits
if (minutes.toString().length < 2) minutes = "0"+minutes;
time.text(hours + ':' + minutes);
}); // ); is important
}
Upvotes: 2
Reputation: 27282
There are really two parts to your question: how to format numbers the way you want them (with leading zeros, etc.), and how best to update time displays.
The first part (formatting) is easier to answer, so I'll hit that one first. JavaScript, unfortunately, has no built-in way for adding leading zeros when converting a number to a string. So you have two options. One is to use a library to get more robust number-to-string formatting in JavaScript. I really like javascript-sprintf, but then I'm an old C guy. If you just want to get this done, and you just need some zero padding, you can extend the string class to do that:
String.prototype.padLeft = function( prefix, maxLength ) {
var s = this; while( s.length < maxLength ) s = prefix + s; return s;
}
Now if you have minutes and seconds you need to format, it's easy:
var min = 3;
var sec = 3;
var s = String(min).padLeft( '0', 2 ) + ':' + String(sec).padLeft( '0', 2 );
Because this is a bit unwieldy, let's roll it all up into a function:
function formatTime( date ) {
return String(date.getHours()).padLeft( '0', 2 ) + ':' +
String(date.getMinutes()).padLeft( '0', 2 );
}
Now on to the trickier problem: how to manage the actual updating. First of all, working with time zones in JavaScript can be a right PITA, because JavaScript (ES5) doesn't have any real way to construct a Date
object with a time zone other than the browser's time zone. Boo for that. (This will likely be addressed in ES6, at least as far as I can tell from the talk on es-discuss.) Also, you're playing with fire by creating a timeout that will do something every 60 seconds like that, and expecting that to stay in sync with the clock. If the user's only going to have the page open for 15 minutes or something, maybe that would be okay (maybe), but it's just going to drift farther and farther apart from the actual time. Telling JavaScript "do something in 60" seconds can't be relied on perfectly. JavaScript's juggling a lot of balls, and it will do its best to get to it in 60 seconds, but it could be 60.001 seconds, or 59.993 seconds. It may not seem like much, but it adds up. Also, if there's a catastrophic event, like stack overflows or other errors that will bork the JavaScript container, it could be off by a lot more than milliseconds.
The other problem with that approach is that the clocks you seen on screen won't be rolling over at the correct times. If the page loads half a minute in, the time won't update until half a minute into the NEXT minute. So really, what you're seen on screen could be off by up to 30 seconds. Maybe that's not a big deal to your application, but it sounds awful to me.
So, what's a better way to do it? Well, ideally, every time you wanted to refresh the screen (and we'll talk about that frequency in a minute), you'd get a Date
object from the browser, convert it into the appropriate time zone, and then update the times from those objects. The problem is, there's no real way to do this in JavaScript (display something in a different time zone).
You have three broad options here:
Load the page with timestamps provided by PHP (this was the basis for my previous answer, which I have abandoned). The problem with this approach is that it is complicated, and can fail around time transitions (daylight savings time transitions). I have come up with better options.
Use PHP for the timezone calculations, and use AJAX to update your time strings. This is a pretty solid solution, but why do that work on the server when the work can be done on the client?
Use a library that brings timezone-capable dates to JavaScript. This to me is the ideal solution. It's shameful that timezone-capable date objects aren't already available in JavaScript, and this solution "fixes" JavaScript.
Fortunately, there is a library available so we can go with option #3:
https://github.com/mde/timezone-js
Once you have that script installed, you can get whatever timezones you want (I'm putting this in a function that will also update the displays):
function updateDateDisplays() {
var now = new Date();
var paris = new timezoneJS.Date( now, 'Europe/Paris');
var miami = new timezoneJS.Date( now, 'America/Miami');
// other TZs go here....
// update HTML here....
}
The only drawback to this approach is that it relies on the user's computer date to be correct. If that's a concern, you will have to use AJAX, or pass the current date on page load and go off of offsets. However, let's assume that we can trust the user's clock.
Now that we have a way of getting dates in specific timezones, all that concerns us is updating the clock. As I mentioned before, updating every 60 seconds has a problem: the minute could be off by up to 30 seconds. Perhaps this isn't an issue in your implementation, but it's an easy enough thing to fix, so why not do it correctly?
Most UX research indicates that things that happen within 100 milliseconds appear "instantaneous" to humans. I usually half that to 50 milliseconds, which is hardly a burden on any computer made in the last 20 years. So all you have to do is call updateTimeDisplays()
every 50 milliseconds, and you will have an accurate time display for your users.
Upvotes: 0