2

I am trying to sync my client app time to my server time (it matters because the app is serverless and has offline-work). On the app startup I calculate the time difference and then override the Date.now() method to add the difference into original now. For example assume this code:

Date.__serverDifference = calculateServerDifference();
Date.__now = Date.now;
Date.now = () => Date.__now() + Date.__serverDifference;

and it works fine. But the problem is about other Date functionalities. For example if I use new Date() it will return original time and it doesn't care the overridden now method.
As the MDN documentation says:

JavaScript Date objects represent a single moment in time in a platform-independent format. Date objects contain a Number that represents milliseconds since 1 January 1970 UTC.

Is there any way to override the js Date Class to return all current times according to this new calculation?

ConductedClever
  • 4,175
  • 2
  • 35
  • 69
  • 3
    Why not a simple wrapper that you call like `makeMeADate()` which creates an object and then makes any adjustment needed, finally returns you the object? Why modify built-ins and potentially break all kinds of stuff? – VLAZ Feb 23 '22 at 07:34
  • 1
    Thanks @VLAZ for your suggestion. Because I use many packages and then I should always be aware of passing my own date or sometimes inject into them. It seems more general and easy to use If I could do this override. – ConductedClever Feb 23 '22 at 07:37
  • 2
    You're assuming the client/server lag is consistent, which it likely isn't. – RobG Feb 23 '22 at 09:08
  • 1
    Yes. A very useful note but the main problem I am trying to solve is not covering the client/server lag, but the time difference from client and server. Thus, till the client does not change the local time this diff would still remain same (and if does the consequences is on him). – ConductedClever Feb 23 '22 at 11:30
  • 1
    With `Date.now` the OP changes just a static method on the `Date` namespace. The implementation of `Date` itself of cause remains untouched. How about writing an own `MyDate` class which extends the built-in `Date` type? ... e.g. `class MyDate extends Date { constructor(...params) { super(...params); /* more instantiation code */ } /* prototype land */ }` – Peter Seliger Feb 24 '22 at 16:12
  • Good Idea @PeterSeliger but then I should inject this new class into any third party package to take this new Date class into account. So it is more appropriate if I could just manipulate the Date class itself to propagate this change into any other package. – ConductedClever Mar 13 '22 at 07:49
  • If 3rd party code is expected to change its behavior, then the entire approach is to be questioned. But of cause one could replace/wrap/reimplement the built-in *Date* class as easily as the OP already did with an own *Date.now*. – Peter Seliger Mar 13 '22 at 09:30

1 Answers1

2

The best approach would be to create helper methods that include the offset for all functions for which the built-in functions don't return the desired value. Your Date.__now is a start, but you could also have:

const offset = calculateServerDifference();
const newDateIncludingOffset = (...args) => {
  const date = new Date(...args);
  date.setMilliseconds(date.getMilliseconds() + offset);
  return date;
};

And then replace all instances of new Date(...args) with newDateIncludingOffset(...args). If you have a lot of references to new Date already - bite the bullet and change them appropriately.

While you could change methods on the prototype, that's not such a good idea - using your own functions and methods while not changing the built-ins is a much better approach.

You could also replace window.Date entirely with something new, with your own methods, allowing you to change the Date constructor to factor in the offset you need - but again, that's not a great idea and can lead to fragile code and incompatibility issues.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320