When displaying the latest data on the front end, we should show how long ago it was relative to the current time. So I wrote Date.now() - timestamp
and then formatted it.
However, a colleague reported that the displayed time was negative, showing something like “- xx seconds ago,” which was confusing. I checked the data on my PC, Mac, and mobile phone, and everything seemed well. When I asked other colleagues, it seemed like everything was fine, as if it were an intermittent and strange bug.
Initially, I suspected that the time returned by Date.now() might not be accurate, with a possible deviation of 1 or a few seconds. I couldn't think of a better solution at the moment.
Recently, the issue has become more noticeable. Even on my own Mac device, the problem is now visible. So, I decided to observe the issue more closely. I added an error report to the display logic and corrected the minimum value to 0. By observing the error data, I found even more absurd cases. The negative values varied in size, with some as small as -200ms and others as large as over ten thousand seconds. Of course, I could tell that the ones with excessively long times were from bots.
Is it due to device system updates, issues with browsers like Chrome, or has our website's code become more complex?
- It's plausible to suspect the complexity of the website code, as it has been observed (albeit not conclusively) that larger projects are more prone to this issue than smaller ones.
The main range of negative values falls between -1 to -10 seconds, with a fairly even distribution.
Solution
The proposal is to use a server timestamp to replace the local time.
- How to Choose a Suitable Public API
After a thorough search, I couldn't find a suitable API
.
Side Note: During the search for timestamp services, I was misled to an
RFC 3161
list. After some research, I realized that this is for timestamping proof, which is not what we need.
- Should We Launch Our Own Timestamp API?
I've carefully considered this option. If we were to launch such an interface, it would face the pressure of frequent, high-volume requests. Given our previous experience with interface crashes, a simple front-end implementation might not be sufficient to handle this task.
For example, if we request it every 3 seconds, based on our user volume, the interface might not perform well, and the real-time nature of the problem could make it even more complex. If we were to request it every 1 second, the situation would become even more complicated, and it would also incur additional service costs.
Escalating this to a full-fledged project involving backend, operations, front-end, and other teams seems a bit excessive.
- Requesting Our Own Website to Obtain the Header
AI suggested that we could make a HEAD
request to our own URL and extract the Date
data from the request headers. This could serve as an API alternative. The precision of the Date
data is 1 second.
After multiple debugging sessions, I found that there is about a half-second delay in the returned time difference. This seems feasible, but the issue of repeatedly pinging the interface still exists.
So, is there a better solution?
Yes, there is.
Current Solution
Instead of making new requests, we can leverage the existing requests on our website. Since our site has many ongoing requests, and each request has a basic Axios setup, we can extract the latest Date
header from the response interceptors in Axios.
Remember to also retrieve the
Date
header fromerror.response
.
By using Math.max
to compare each server date, and then comparing the server date with Date.now()
, we can obtain the maximum value.
This approach avoids the need for additional requests, as the site already has continuous requests, thus eliminating extra service pressure. It also ensures that the rendered timestamp is always the latest and non-negative.
Performance
Since our website does not have second-level requests, there will still be a multi-second time difference. To optimize further, we can set the latest performance.now
based on the most recent server date. When using the latest server timestamp, we can add the current difference and perform additional operations to achieve better optimization.
Conclusion
The current solution addresses the issue of negative values. However, it is still not a 100% fix, as server dates have second-level inaccuracies and the uncertain latency of request responses. It seems this is the best we can achieve with the current approach.
- Conjecture 1: Assign a precision value to each server date (based on request time) and use the most accurate server date plus the
performance
difference.- Combining this with the latest
now
from above should yield even better results.
- Combining this with the latest
- Is there a better alternative to
Date.now()
? It would be great if there were.