:date: 2018-03-16 ====================== Friday, March 16, 2018 ====================== Time zones ========== Yesterday I opened :ticket:`2345` and started working on it. Here comes the result. Until today we had just had a field :attr:`User.timezone` (a ``Charfield(max_length=15)`` when :setting:`USE_TZ` was `True`. In order to get an *aware* datetime of the start and end times of a session, we used the user's time zone. Which was okay unless the user travels and works in changing time zones. Jane is the only production site with :setting:`USE_TZ` Now I added a timezone field per :class:`working.Session` as well. But before doing this I reviewed and optimized the whole system a bit. I added a choicelist `about.Timezones` which defines a subset of all timezones known to `pytz `_. This has one theoretical disadvantage (it requires local system admins to define their own list of timezones allowed on their site) but some advantages: it reduces server load because it uses only 2 instead of 15 bytes per Session record and (more important) avoids a lookup into the pytz database (a dict containing 439 keys) for every incoming web request. Also it will probably be more ergonimic. >>> import pytz >>> len(pytz.common_timezones) 439 The :func:`django.utils.timezone.activate` function (called for every incoming request) is smart enough and would avoid the lookup if we would provide the ``tzinfo`` object ourselves:: def activate(timezone): if isinstance(timezone, tzinfo): _active.value = timezone elif isinstance(timezone, six.string_types): _active.value = pytz.timezone(timezone) else: raise ValueError("Invalid timezone: %r" % timezone) We currently store the timezone (either per user or system-wide) as a string. That is, for the moment we are using the inefficient variant. Where to put our TimeZones choicelists? To :mod:`lino.modlib.about`? Or into a separate plugin :mod:`lino.modlib.timezones`? I noted that we have two plugins :mod:`lino.modlib.about` and :mod:`lino.modlib.system` which should maybe get merged. One difference is that :mod:`about` is always there while :mod:`system` only when needed. Though it is needed by :mod:`lino.modlib.users` and therefore they are almost always both present. Changes: - New choicelist :class:`lino.modlib.about.TimeZones` with at least one :attr:`default `. - Replaced the CharField `timezone` by a ChoiceListField `time_zone` (the correct English spelling is with two words). - In :mod:`lino.core.auth.middleware` we now use the tzinfo objects on every choice of :class:`TimeZones `. Another change of more general impact: - When :meth:`lino.core.choicelists.ChoiceListField.to_python` receives a string, then this should be the ``value`` of a choice. Now it supports also specifying a ``name``. New page :ref:`dg.plugins.about`. Here is the line to modify in the :xfile:`restore.py` file when upgrading a production site:: kw.update(time_zone=settings.SITE.models.about.TimeZones.find(text=timezone)) After installing it on Jane I started to get the feeling that maintaining a local list of "allowed" time zones will be cumbersome. To be observed. About inspired working ======================= I have been asking myself "Why the hell did I open and fix that :ticket:`2345`? Why *now*? Aren't there more urgent things to do?" It is what I would call inspired working. Every well-educated project manager will give me -1 for this technique. It happened after updating our `jobs page `_ and reviewing the :ref:`book` (in case somebody looks at it).