Drupal happily hides the chaos when it comes to timezones. We have UNIX timestamps, which are timezone-agnostic, and other forms of dates that are always in UTC, which it converts for you on-the-fly before displaying them to the users. This way, you do not need to worry about the pain of converting dates between timezones, a magic database in the background resolves it. Obviously it won’t work for anonymous visitors as the timezone information is missing, also the pages are often cached for them. One solution would be to render the dates for the frontend entirely on the client side, but it means throwing away all that Drupal does for us already - a well tested and designed handling for the dates with formatters, etc. But what about the backend side? Let us introduce the Anonymous Timezone contrib module.
Serving timezone-aware data from the backend means that the traditional page cache is not usable anymore, however with Dynamic Page Cache and BigPipe present, it seems to be an acceptable trade-off to be able to implement this functionality. All we need to do is to invoke the kill switch and page cache is eliminated. Some pages do not contain dates, so it’s possible to maintain a whitelist where the kill switch isn’t triggered, so for example the homepage can load pretty fast, even fully from a nearby CDN endpoint. Then for a specific node view, we can render it properly with timezone information. For our specific use case, performance was acceptable and scalability wasn’t the main concern, but beware, this module definitely deteriorates performance and needs careful fine tuning. Also the pages where dates are present, become timezone-dependent, it means adding
timezone cache context is needed. This isn’t automatic, that’s part of the integration.
On the backend, it’s impossible to get perfectly accurate timezone information, but an approximate solution exists based on the IP address of the client. The free database that’s available turned out to be precise enough, as we do not need city-level accuracy, merely timezone-level, in simple cases, it provided good results for us. The upside of this solution is that we do not need to query an external service, the downside is that the static GeoDB file needs to be updated from time to time to preserve the accuracy.
Altering Core - Easier Than You Imagine
Veteran Drupal developers might tend to think that altering core is a bit hard or complicated; but usually it’s far from the truth. With services architecture, it’s possible to just redefine any service in a custom module and that’s all, for instance the
services: current_user: class: Drupal\anonymous_timezone\AnonymousTimezoneAccountProxy arguments: ['@event_dispatcher', '@page_cache_kill_switch', '@request_stack', '@config.factory']
Devel module similarly does its sophisticated profiling, by overriding many core services. It’s likely wise to check with a profiler what changes in terms of CPU time and DB usage when Anonymous Timezone disables the classical page cache.
If you’d like to test the accuracy of this approach, try it out yourself using GitPod, upload the city-level MMDB database from MaxMind at
/admin/config/anonymous_timezone, then try the accuracy using anonymous user and let us know :)