[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