Roundup Tracker

Symbolic Timezone Enhancement

Support for whole hour timezone offsets have been around since early roundup versions. However it didn't follow daylight savings time and provided no support for partial hour offsets.

If your python has the pytz package installed, you can use symbolic (e.g. US/Eastern, America/New_York or America/Panama) names. However the current editing interface is a simple text entry box. So how do you figure out what symbolic name to use?

This change checks to see if pytz is installed and if so changes the entry text box into a select pulldown.

It has a change to user.item.html and three supporting functions.

The user page looks like:

userpage.png

after the change.

Changes to user.item.html template

Change the lines:

 <td><input name="timezone" metal:use-macro="normal_input">
  <tal:block tal:condition="edit_ok" i18n:translate="">(this is a numeric hour offset, the default is
   <span tal:replace="db/config/DEFAULT_TIMEZONE" i18n:name="zone"
   />)</tal:block>

to:

 <td>
    <tal:block tal:condition="python:(context.is_edit_ok() or
                              context.timezone) and
                              not utils.UsingPytz()">
      <input name="timezone" metal:use-macro="normal_input">
    </tal:block>
    <tal:subif condition="python:utils.UsingPytz()">
      <tal:span tal:condition="python: not context.is_edit_ok()"
                tal:content="context/timezone"></tal:span>
      <select tal:condition="python:context.is_edit_ok()"
              name="timezone">
        <option value="0">- no selection -</option>
        <tal:block tal:repeat="tz python:utils.GetCommonTz()">
          <option tal:attributes="value tz; selected python:tz == context.timez\
one"
                  tal:content="tz"></option>
        </tal:block>
      </select>
    </tal:subif>
   <tal:block tal:condition="python:context.is_edit_ok() and not utils.UsingPytz()" i18n:translate="">(this is a numeric hour offset, the default is
     <span tal:replace="db/config/DEFAULT_TIMEZONE" i18n:name="zone"
    />)</tal:block> Local Time is: <tal:span tal:replace="python:utils.CurrentLocalTime(context.timezone.plain())"></tal:span>

Note that the call to CurrentLocalTime is passed the current timezone of the user. This lets the user change and save the timezone and verify that it matches their current time. Also it allows support personnel to look up the user and quickly see the user's current time.

Supporting extension functions

The template uses three functions:

utils.UsingPytz
returns True if the import of pytz is successful, otherwise it returns False.
utils.GetCommonTz
returns the list of common timezones from the pytz module.
utils.CurrentLocalTime
takes the timezone for the user and returns the current time in that timezone.

Put the following in the extensions subdirectory of your tracker. I call the file time.py.

import roundup.date
import gettext

_ = gettext.gettext

def current_local_time(user_tz):
    try:
        localtime = roundup.date.Date().local(user_tz)
    except KeyError:
        localtime = _("%s (unrecognized timezone or offset UTC used)"%
                     (roundup.date.Date().local(0)))

    return localtime

def using_pytz():
    try:
        import pytz
        return True
    except:
        return False

def get_common_tz():
    if using_pytz():
        import pytz
        return pytz.common_timezones

def init(instance):
    instance.registerUtil('CurrentLocalTime', current_local_time)
    instance.registerUtil('UsingPytz', using_pytz)
    instance.registerUtil('GetCommonTz', get_common_tz)