[Zope3-dev] mini-RFC: times and timezones

Gary Poster gary at zope.com
Wed Feb 23 22:26:42 EST 2005


Problems:
- working with mixed Python timezone-aware and -naive datetimes is a  
big pain (i.e., they don't work together well, and are not intended to  
AFAIK).
- Given a choice, timezone-aware datetimes are more explicit, clear,  
and effective.  The Zope 3 code base does not use timezone-aware  
datetimes. [1]
- The datetimeutils package is disliked by some (Stephan being an  
important voter[2]).  Much of its functionality is replaced by the  
zope.i18n package.  The timezone implementation is an important  
exception: Jim crafted them to be happy pickle participants, and...
- ...the timezones generated by the newly imported pytz package do not  
pickle well (in particular, the utc timezone does not).  However...
- ...the datetimeutils tzinfos don't behave well in  
datetime.now(datetimeutils.tzinfo(0))[3]
- Displaying datetimes in UTC is not user friendly.  Users should see  
datetimes in their timezones.

Other observations:
- Working internally with utc datetimes is considered best practice[4].  
  The Zope 3 code base does store UTC dates, just without a timezone.

Suggested Solution:
- zope.i18n should grow a picklable utc timezone that behaves well with  
datetime.now()[5]
- datetimes generated in the Zope core to be stored should have a utc  
timezone (i.e., datetime.now(zope.i18n.utc)--again, see footnote [5])
- datetimes generated in the Zope core for display should always have  
"localized" timezones.  Specifically:
   * zope.interface.common should grow an ITZInfo interface
   * zope.app.i18n should grow an adapter that adapts a default request  
to an ITZInfo.  It will be intentionally dumb--always returning  
i18n.utc--but will be intended to be a hook point for applications to  
specify other defaults or heuristics for getting the appropriate  
display timezone for a given request.  If anyone wants to improve the  
default, great, but I'm not planning on it.
   * zope.i18n should grow a convenience method to convert dates from  
utc to another timezone [6]
   * Views should generally display dates (stored with a UTC timezone)  
using something like this:
         formatter = request.locale.dates.getFormatter('dateTime',  
length='short')
         tz = zope.interface.common.tzinfo.ITZInfo(request)
         return formatter.format(zope.i18n.switchTimeZones(date, tz)

Objections?  I'd like schoolbell(/tool) folks to buy in on this as  
well, ideally.  This should be pretty easy for me to throw together if  
everyone is ok with it.

Thanks

Gary

[1] Some of these are more important than others.
./i18n/interfaces/locales.py:121:        constraint = lambda date: date  
< datetime.now(),
./app/dublincore/browser/metadataedit.py:41:            message.mapping  
= {'datetime': formatter.format(datetime.utcnow())}
./app/dublincore/timeannotators.py:26:        dc.modified =  
datetime.utcnow()
./app/dublincore/timeannotators.py:31:        now = datetime.utcnow()
./app/file/browser/file.py:168:        status.mapping = {'date_time':  
formatter.format(datetime.utcnow())}
./app/form/browser/editview.py:123:                         
datetime.utcnow())}
./app/securitypolicy/browser/rolepermissionview.py:156:             
status.mapping = {'date_time': formatter.format(datetime.utcnow())}
./app/versioncontrol/repository.py:61:        self._created =  
datetime.datetime.utcnow()

[2] http://mail.zope.org/pipermail/zope3-dev/2005-February/013182.html

[3] This is understandable for the datetimeutils design, but not what  
we would want from a utc timezone implementation:
 >>> datetime.datetime.now(zope.app.datetimeutils.tzinfo(0))
Traceback (most recent call last):
   File "<stdin>", line 1, in ?
ValueError: fromutc: non-None dst() result required

The current workaround is  
datetime.datetime.utcnow().replace(tzinfo=zope.app.datetimeutils.tzinfo( 
0))

[4] http://pytz.sourceforge.net/

[5] So you see the results of what I mean (we are currently doing # 2  
and I want to change to effectively doing # 3, except with a  
zope.i18n.utc timezone):
 >>> datetime.datetime.now()
datetime.datetime(2005, 2, 23, 21, 44, 59, 233963)
 >>> datetime.datetime.utcnow()
datetime.datetime(2005, 2, 24, 2, 45, 7, 802388)
 >>> datetime.datetime.now(pytz.reference.utc)
datetime.datetime(2005, 2, 24, 2, 45, 28, 597637,  
tzinfo=<pytz.reference.UTC object at 0x38a1f0>)

[6] Anybody know any better approach than this?

def switchTimeZones(date, tz):
     newdate = date.replace(tzinfo = tz)
     return newdate + (date-newdate)



More information about the Zope3-dev mailing list