From 1daf300ca310adbbd52687aea62b08ef5a59f37c Mon Sep 17 00:00:00 2001 From: Federico Di Gregorio Date: Mon, 2 Mar 2009 11:07:17 +0100 Subject: [PATCH] Support for seconds in time zone offsets --- ChangeLog | 3 +++ lib/extras.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/ChangeLog b/ChangeLog index ffaab92e..baea1824 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2009-03-02 Federico Di Gregorio + * Applied modified patch from Karsten Hilbert to provide a + type-caster able to parse times with seconds in the time zone. + * Applied patch from Menno Smits to avoid problems with DictCursor when the query is executed by a named cursor. Also added Menno's tests and uniformed other DictCursor tests. diff --git a/lib/extras.py b/lib/extras.py index 78156467..4ab62bbf 100644 --- a/lib/extras.py +++ b/lib/extras.py @@ -360,4 +360,53 @@ def register_inet(oid=None, conn_or_curs=None): return _ext.INET +# safe management of times with a non-standard time zone + +def _convert_tstz_w_secs(s, cursor): + try: + return DATETIME(s, cursor) + + except (DataError,), exc: + if exc.message != "unable to parse time": + raise + + if regex.match('(\+|-)\d\d:\d\d:\d\d', s[-9:]) is None: + raise + + # parsing doesn't succeed even if seconds are ":00" so truncate in + # any case + return DATETIME(s[:-3], cursor) + +def register_tstz_w_secs(oids=None, conn_or_curs=None): + """Register alternate type caster for TIMESTAMP WITH TIME ZONE. + + The Python datetime module cannot handle time zones with + seconds in the UTC offset. There are, however, historical + "time zones" which contain such offsets, eg. "Asia/Calcutta". + In many cases those offsets represent true local time. + + If you encounter "unable to parse time" on a perfectly valid + timestamp you likely want to try this type caster. It truncates + the seconds from the time zone data and retries casting + the timestamp. Note that this will generate timestamps + which are INACCURATE by the number of seconds truncated + (unless the seconds were 00). + + + which OIDs to use this type caster for, + defaults to TIMESTAMP WITH TIME ZONE + + a cursor or connection if you want to attach + this type caster to that only, defaults to + None meaning all connections and cursors + """ + if oids is None: + oids = (1184,) # hardcoded from PostgreSQL headers + + _ext.TSTZ_W_SECS = _ext.new_type(oids, 'TSTZ_W_SECS', _convert_tstz_w_secs) + _ext.register_type(TSTZ_W_SECS, conn_or_curs) + + return _ext.TSTZ_W_SECS + + __all__ = [ k for k in locals().keys() if not k.startswith('_') ]