Changeset 849 for trunk/pgdb.py


Ignore:
Timestamp:
Feb 9, 2016, 8:14:26 AM (3 years ago)
Author:
cito
Message:

Make timetz and timestamptz work properly with Python 2

Python 2 has no concrete timezone class, therefore we had so far returned only
naive datetimes in this case. This patch adds a simple concrete timezone class,
so we can return timetz and timestamptz with timezones in Python 2 as well.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/pgdb.py

    r847 r849  
    6464"""
    6565
    66 from __future__ import print_function
     66from __future__ import print_function, division
    6767
    6868from _pg import *
     
    7070__version__ = version
    7171
    72 from datetime import date, time, datetime, timedelta
     72from datetime import date, time, datetime, timedelta, tzinfo
    7373from time import localtime
    7474from decimal import Decimal
     
    129129
    130130try:
    131     if datetime.strptime('+0100', '%z') is None:
    132         raise ValueError
    133 except ValueError:  # Python < 3.2
    134     timezones = None
     131    from datetime import timezone
     132except ImportError:  # Python < 3.2
     133
     134    class timezone(tzinfo):
     135        """Simple timezone implementation."""
     136
     137        def __init__(self, offset, name=None):
     138            self.offset = offset
     139            if not name:
     140                minutes = self.offset.days * 1440 + self.offset.seconds // 60
     141                if minutes < 0:
     142                    hours, minutes = divmod(-minutes, 60)
     143                    hours = -hours
     144                else:
     145                    hours, minutes = divmod(minutes, 60)
     146                name = 'UTC%+03d:%02d' % (hours, minutes)
     147            self.name = name
     148
     149        def utcoffset(self, dt):
     150            return self.offset
     151
     152        def tzname(self, dt):
     153            return self.name
     154
     155        def dst(self, dt):
     156            return None
     157
     158    timezone.utc = timezone(timedelta(0), 'UTC')
     159
     160    _has_timezone = False
    135161else:
    136     # time zones used in Postgres timestamptz output
    137     timezones = dict(CET='+0100', EET='+0200', EST='-0500',
    138         GMT='+0000', HST='-1000', MET='+0100', MST='-0700',
    139         UCT='+0000', UTC='+0000', WET='+0000')
     162    _has_timezone = True
     163
     164# time zones used in Postgres timestamptz output
     165_timezones = dict(CET='+0100', EET='+0200', EST='-0500',
     166    GMT='+0000', HST='-1000', MET='+0100', MST='-0700',
     167    UCT='+0000', UTC='+0000', WET='+0000')
     168
     169
     170def _timezone_as_offset(tz):
     171    if tz.startswith(('+', '-')):
     172        if len(tz) < 5:
     173            return tz + '00'
     174        return tz.replace(':', '')
     175    return _timezones.get(tz, '+0000')
     176
     177
     178def _get_timezone(tz):
     179    tz = _timezone_as_offset(tz)
     180    minutes = 60 * int(tz[1:3]) + int(tz[3:5])
     181    if tz[0] == '-':
     182        minutes = -minutes
     183    return timezone(timedelta(minutes=minutes), tz)
    140184
    141185
     
    208252        tz = '+0000'
    209253    fmt = '%H:%M:%S.%f' if len(value) > 8 else '%H:%M:%S'
    210     if timezones:
    211         if tz.startswith(('+', '-')):
    212             if len(tz) < 5:
    213                 tz += '00'
    214             else:
    215                 tz = tz.replace(':', '')
    216         elif tz in timezones:
    217             tz = timezones[tz]
    218         else:
    219             tz = '+0000'
    220         value += tz
     254    if _has_timezone:
     255        value += _timezone_as_offset(tz)
    221256        fmt += '%z'
    222     return datetime.strptime(value, fmt).timetz()
     257        return datetime.strptime(value, fmt).timetz()
     258    return datetime.strptime(value, fmt).timetz().replace(
     259        tzinfo=_get_timezone(tz))
    223260
    224261
     
    275312            return datetime.max
    276313        fmt = [fmt, '%H:%M:%S.%f' if len(value[1]) > 8 else '%H:%M:%S']
    277     if timezones:
    278         if tz.startswith(('+', '-')):
    279             if len(tz) < 5:
    280                 tz += '00'
    281             else:
    282                 tz = tz.replace(':', '')
    283         elif tz in timezones:
    284             tz = timezones[tz]
    285         else:
    286             tz = '+0000'
    287         value.append(tz)
     314    if _has_timezone:
     315        value.append(_timezone_as_offset(tz))
    288316        fmt.append('%z')
    289     return datetime.strptime(' '.join(value), ' '.join(fmt))
     317        return datetime.strptime(' '.join(value), ' '.join(fmt))
     318    return datetime.strptime(' '.join(value), ' '.join(fmt)).replace(
     319        tzinfo=_get_timezone(tz))
     320
    290321
    291322_re_interval_sql_standard = regex(
Note: See TracChangeset for help on using the changeset viewer.