2
\$\begingroup\$

I use the following PHP Code to output the user's local time and the servers time (office time). $local_time and $remote_time are the corresponding UNIX timestamps:

<span class='icon-time' data-time='<?php echo $local_time; ?>' id='local-time'>
Local : <?php echo date('D, M j, h:ia', $local_time); ?></span><br />
<span class='icon-time text-<?php

echo (6 > date('N') && 9 <= date('G') && date('G') <= 17) // change class if open/closed
    ? 'success'
    : 'error';

?>' data-time='<?php echo $remote_time; ?>' id='remote-time'>
Office : <?php echo date('D, M j, h:ia', $remote_time); ?></span>

I then have the following JavaScript to update the clocks in real-time:

// update local/office clocks
window.setInterval(function () {

    lclock = $('#local-time');
    rclock = $('#remote-time');

    // convert to UNIX timestamp, add 60 secs since setInterval() will no start onload but after 60 secs
    ltime = new Date((lclock.data('time') * 1000) + 60000); 
    rtime = new Date((rclock.data('time') * 1000) + 60000);

    lhours = ltime.getHours();
    rhours = rtime.getHours();

    // make 12hr time format and left-pad with zero
    lshours = ((0 === lhours) ? 12 : (lhours - ((12 < lhours) ? 12 : 0)));
    rshours = ((0 === rhours) ? 12 : (rhours - ((12 < rhours) ? 12 : 0)));

    lmins = ltime.getMinutes();
    rmins = rtime.getMinutes();

    rday = rtime.getDay();

    // determine if office is closed and change class
    ostatus = 'icon-time ' + ((6 > rday && 0 < rday && 9 <= rhours && 17 >= rhours)
        ? 'text-success'
        : 'text-error');

    // update clock, increment timestamp by 60 secs
    lclock.text('Local : ' + days[ltime.getDay()] + ', ' 
    + months[ltime.getMonth()] + ' ' + ltime.getDate() + ', ' 
    + ((10 > lshours) ? '0' + lshours : lshours) + ':' 
    + ((10 > lmins) ? '0' + lmins : lmins) 
    + ((12 <= lhours) ? 'pm' : 'am')).data().time += 60;

    // update clock, change CSS class, increment timestamp by 60 secs
    rclock.text('Office : ' + days[rtime.getDay()] + ', ' 
    + months[rtime.getMonth()] + ' ' + rtime.getDate() + ', ' 
    + ((10 > rshours) ? '0' + rshours : rshours) + ':' 
    + ((10 > rmins) ? '0' + rmins : rmins) 
    + ((12 <= rhours) ? 'pm' : 'am')).attr('class', ostatus).data().time += 60;

}, 60000);

It works great. However, after a few hours the time can end up being off by up to -7 minutes. I tried caching as many objects as I could and optimizing it the best I could to reduce the amount of variable value assignments, and used chaining as well, but can't see how else to speed it up to make it not lose time.

  • How can I optimize this further, in either my method, code being used, or is there something I am doing wrong?
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

The thing to understand with setInterval() and other timer-based functions in general is that they do not guarantee precise timing. You request an interval of 60000ms, and your mistake is assuming that what you get is in fact an interval of exactly 60000ms.

The main trick is to measure the actual amount of elapsed time between intervals, rather than assuming that each interval occurs exactly 60000ms after the previous one. Do that and you should see better results.

Note that there may also be secondary effects caused by the execution time of your code itself. To get around that, instead of adding deltas on each invocation you could track the initial starting timestamp at which your script starts running, and then just always compute the total amount of time that has elapsed between that starting timestamp and now, and add that amount to the starting timestamp when displaying the time. That should give you very accurate output, and it solves the problem of the imprecise timer as well.

Here's a similar JavaScript timer that I coded awhile back that you can use as a reference.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Excellent suggestions! I'll re-work it and see how it works out and will be back. Thank you. \$\endgroup\$
    – kittycat
    Feb 1, 2013 at 6:22
  • \$\begingroup\$ Re-did code per your suggestions and working great. \$\endgroup\$
    – kittycat
    Feb 1, 2013 at 10:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.