0

I have a JS code that displays a live digital clock, correcting the minutes/seconds from the server, so if one of the clients has some minutes more or less, it corrects them to match the server time.

<script>
    
    var serverTime = <?php echo (int) round(microtime(true) * 1000) ?>;
    var localTime = +Date.now();
    var timeDiff = serverTime - localTime;

    $(document).ready(function() {
        clockUpdate();
        setInterval(clockUpdate, 1000);
    });

    function clockUpdate() {

        var t = +Date.now() + timeDiff
        var date = new Date(t);

        $('.digital-clock').css({'color': '#fff', 'text-shadow': '0 0 0px #ff0'});
        function addZero(x) {
            if (x < 10) {
                return x = '0' + x;
            } else {
                return x;
            }
        }

        function twelveHour(x) {
            if (x > 12) {
                return x = x - 12;
            } else if (x == 0) {
                return x = 12;
            } else {
                return x;
            }
        }

        var h = addZero(twelveHour(date.getHours()));
        var m = addZero(date.getMinutes());
        var s = addZero(date.getSeconds());

        $('.digital-clock').text(h + ':' + m + ':' + s)
    }

</script>

Now the script works as expected but I realized that when one of the clients is set to a different TimeZone, the clock will match the hour on the client,

If now on the server is 14:52 and on the client is 15:52, it will display 15:52 and I want the opposite, I want all the clocks displayed on all the clients match the exact time on the server (14:52).

Please help me just modify things in this code, no need for other online examples.

/*****************/

Thanks for all who took it seriously and tried to help (not like those who are ready waiting just to vote for closing the question the same second I asked it)

I want to explain it more:

The server is located in France and is using GMT+1 with DST

The clients are in Tunisia, the same timezone GMT+1 but DST is not applicable. BUT for some reason many clients in Tunisia use DST being unaware maybe.

So that's why the time on the page must be the exact same time as in the server and everywhere else.

So with PHP I'm using date_default_timezone_set('Africa/Tunis'); to set the server time to Tunisia timezone.

Thanks!

medk
  • 9,233
  • 18
  • 57
  • 79
  • 3
    Please share more details. What have you tried to resolve the problem? Where are you stuck? How is this related to PHP? – Nico Haase Jun 01 '21 at 13:57
  • The unary "+" in `+Date.now()` is redundant as [*now*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now) is specified as returning a number. The assignment in `return x = x - 12` is also redundant, it should be just `return x - 12`, but the whole *twelveHour* function body can be `return x%12 || 12`. – RobG Jun 02 '21 at 04:01

2 Answers2

1

Ok thanks everybody who tried to help, I solved it by using some help from Reinhard Schnetzinger's answer:

getUTCHours();
getUTCMinutes();
getUTCSeconds();

So the code I used is:

var h = addZero(twelveHour(date.getUTCHours() + 1));
var m = addZero(date.getUTCMinutes());
var s = addZero(date.getUTCSeconds());

Using getUTCHours() + 1 as the time needed is GMT+1

medk
  • 9,233
  • 18
  • 57
  • 79
0

It outputs the time incorrectly because you are using methods that return the time according to the client's local timezone (getHours(), getMinutes(), getSeconds()). You should use the following methods instead:

getUTCHours();
getUTCMinutes();
getUTCSeconds();

Edit

Because it's not clear why I think this might solve the problem, here's a little explanation.

The server time is set in PHP with the microtime() function and the client time with Data.now(). Both return the UNIX timestamp and they are by definition timezone independent, as described here.

Therefore, the time in JavaScript must be output in UTC, otherwise the time displayed on the client may differ from the actual server time.


But let's say the server time would include the timezone offset (e.g. one extra hour in the timestamp). It would still be required to output the time in UTC because the time in JavaScript is set with new Date(epochTimestamp). And this constructor interprets the UNIX timestamp correctly as UTC and does not care about the timezone at all (even if there is an timezone offset; like in the following example with fakeOffset).

const timeInUtc = document.getElementById('time-in-utc');
const timeInLt = document.getElementById('time-in-lt');
const fakeOffset = 3600000; // emulate one extra hour on the server; UTC + 1h
const serverTime = Date.now() + fakeOffset; // for demonstration purposes microtime() is replaced with Date.now()
const clientTime = Date.now();
const timeDiff = serverTime - clientTime;

setInterval(() => {
  const currentTimestamp = Date.now() + timeDiff;
  const currentTime = new Date(currentTimestamp);
  timeInUtc.innerHTML = `${currentTime.getUTCHours()}:${currentTime.getUTCMinutes()}:${currentTime.getUTCSeconds()}`;
  timeInLt.innerHTML = `${currentTime.getHours()}:${currentTime.getMinutes()}:${currentTime.getSeconds()}`;
}, 500)
Actual Server Time (output in UTC): <span id="time-in-utc">Unset</span><br>
Server Time (output in Local Time): <span id="time-in-lt">Unset</span>

<p>Keep in mind that the times may match if your time zone is the same as UTC time.</p>

Edit #2

As @medk explained, the server's timezone is in indeed different from the client's. My recommendation would be to deliver the server timestamp already with the offset included, so that the JavaScript code will always display the correct server time without having to manually change the output (to avoid for example getUTCHours() + 1).

In PHP the perceise offset can be obtained with the function date_offset_get(new DateTime). This will return the offset in seconds. Now we have the offset (e.g. 1h), the UNIX timestamp (UTC) and if we add these two together we get the correct server timestamp (UTC+1).

var serverTime = <?php echo (int) round((microtime(true) + date_offset_get(new DateTime)) * 1000); ?>;

So no matter what timezone you set on the server or if DST is active or not, the time on the client should always match the server time.

  • 2
    Why do you figure this would solve the issue? Server is not necessarily in UTC. – El_Vanja Jun 01 '21 at 14:42
  • 1
    Because both the `microtime` in PHP and `Date.now()` in JS give us just the time past since 1970 without any timezone conversation. So the dates he sets in JS are UTC. However, when he uses `getHours()` the time gets altered because the methods will auto convert to the client time. – Reinhard Schnetzinger Jun 01 '21 at 17:15
  • 1
    Even if the server time would include the timezone offset, it wouldn't matter because he correctly calculates the time difference between server and client. And then he sets the newly created time in UTC (`new Date(t)`). So the timezone of the server would be present in JS, but it is just "stored" as UTC. – Reinhard Schnetzinger Jun 01 '21 at 17:23
  • 1
    I edited my question if you would take a look. – medk Jun 02 '21 at 11:07
  • Yes thank you, I edited my answer regarding your new details :) – Reinhard Schnetzinger Jun 02 '21 at 12:20