Workspace:GetServerTimeNow() documentation incorrect and DateTime.now() needs more information

Workspace:GetServerTimeNow() documentation is incorrect

Documentation says

Essentially, it is the client’s best guess of what os.clock would return on the server.

It is not at all an estimate based on what os.clock() would return on the server, os.clock() has no Unix epoch baseline. The single function it could be said to estimate the server value of would be tick(), but tick() is not monotonically increasing and Workspace:GetServerTimeNow() is.

This distinction is important, any code relying on that documentation will almost certainly be incorrect.

DateTime.now() documentation does not specify if it’s monotonically increasing

Documentation says nothing about whether DateTime.now() is monotonically increasing. tick() isn’t, os.time() is, Workspace:GetServerTimeNow() is, so it’s unclear.

6 Likes

We’ve filed a ticket to our internal database for this issue. We will come back as soon as we have updates!

Thanks for the report!

5 Likes

Workspace:GetServerTimeNow() can be called from the server to compare results

this seems like easy to find, but you normally try the idea of using os.time() etc. first and may never know

What is your use case? Hard to tell what kind of clock you want without knowing more.

Still trying to confirm with others, but from my reading of the code…

Docs are definitely incorrect, it probably meant to say os.time(), which does report system time. I believe DateTime.now() also reads system time as well. I don’t believe these would be monotonic on clients or servers given leap seconds, and other clock updates. On clients there’s no guarantee of any kind of accuracy or sanity.

I believe tick() is actually monotonic. It captures a timestamp offset on startup, but it uses a monotonic clock and should be monotonic from there. Leaves some possibility of it drifting over the runtime of the session (leap seconds, etc.), but in practice not by much.

GetServerTimeNow is like tick() (based off the same internal monotonic clock), but with constant synchronization and smoothing on top of . Like the docs say, it will slightly slow or speed up time to maintain synchronization instead of skipping backwards/forwards.

GetServerTimeNow does some additional NTP-like approximate latency compensation, attempting to sync it up with wall clock time on the server. Some monotonic smoothing on top of something like…

lastReceivedServerTime + (ping / 2)

However…

… for many game use cases this type of wall clock latency compensation is not actually something you want! We don’t do any kind of time extrapolation like this on the rest of a client’s view of the world! The only thing you know for sure is that by the time the server receives an event from a client, it is a user’s reaction to a view of the world that was full round tip latency in the past. Or locally from the perspective of the client its character is running full round trip latency in the future relative to the rest of the world! Outside of their own character simulation (or other owned simulation), the client’s view of the world only includes reactions to their actions RTT in the past.

In many cases it’s better to not do any latency compensation (i.e. extrapolation) and just accept the client’s view of the world being behind the server. If you pushed your client next to a monitor on the server it would be behind, but you’ll never be able to do that anyway! Extrapolation comes with it’s own problems that are often worse than the mixed timeline view inconsistency.

You usually usually never actually want a latency compensated wall clock for coordinating things in a networked simulation.

I’m a little disappointed we added this approximate latency compensation on GetServerTimeNow; use cases for it exist, but are extraordinarily niche.

Suggestion: client initiated actions either happen on the server at the moment they are received (with no compensation) or skipped ahead by that client’s full RTT (to line up with their predicted view by the time they receive it). If you’re doing anything coordinated with any other systems these are the only two options that make any sense.

Don’t know your actual use case, not sure if this applies. I just get worried when people start asking detailed questions about GetServerTimeNow.

Unless a lawyer is demanding that all clients see something happen in game when the clock strikes 12, and he will be verifying this with an atomic clock and a high speed camera and won’t be paying you otherwise (run away!), you probably don’t want GetServerTimeNow.

5 Likes

We have:

  • GetServerTimeNow()
  • Tick()
  • os.time()

Yet not a single one of them will tell you the time.

What does it profit me if the server says it’s 4pm. 4 PM WHERE?! In China??

There is ofcourse no function that tells you the timezone of the server either.
They are all utterly useless and it’s embarrasing that after 20 years you still need to use HTTPService to get the time.

4 Likes