Changeset 849 for trunk/pg.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/pg.py

    r833 r849  
    2828# supporting documentation.
    2929
    30 from __future__ import print_function
     30from __future__ import print_function, division
    3131
    3232from _pg import *
     
    3737import warnings
    3838
    39 from datetime import date, time, datetime, timedelta
     39from datetime import date, time, datetime, timedelta, tzinfo
    4040from decimal import Decimal
    4141from math import isnan, isinf
     
    158158
    159159try:
    160     if datetime.strptime('+0100', '%z') is None:
    161         raise ValueError
    162 except ValueError:  # Python < 3.2
    163     timezones = None
     160    from datetime import timezone
     161except ImportError:  # Python < 3.2
     162
     163    class timezone(tzinfo):
     164        """Simple timezone implementation."""
     165
     166        def __init__(self, offset, name=None):
     167            self.offset = offset
     168            if not name:
     169                minutes = self.offset.days * 1440 + self.offset.seconds // 60
     170                if minutes < 0:
     171                    hours, minutes = divmod(-minutes, 60)
     172                    hours = -hours
     173                else:
     174                    hours, minutes = divmod(minutes, 60)
     175                name = 'UTC%+03d:%02d' % (hours, minutes)
     176            self.name = name
     177
     178        def utcoffset(self, dt):
     179            return self.offset
     180
     181        def tzname(self, dt):
     182            return self.name
     183
     184        def dst(self, dt):
     185            return None
     186
     187    timezone.utc = timezone(timedelta(0), 'UTC')
     188
     189    _has_timezone = False
    164190else:
    165     # time zones used in Postgres timestamptz output
    166     timezones = dict(CET='+0100', EET='+0200', EST='-0500',
    167         GMT='+0000', HST='-1000', MET='+0100', MST='-0700',
    168         UCT='+0000', UTC='+0000', WET='+0000')
     191    _has_timezone = True
     192
     193# time zones used in Postgres timestamptz output
     194_timezones = dict(CET='+0100', EET='+0200', EST='-0500',
     195    GMT='+0000', HST='-1000', MET='+0100', MST='-0700',
     196    UCT='+0000', UTC='+0000', WET='+0000')
     197
     198
     199def _timezone_as_offset(tz):
     200    if tz.startswith(('+', '-')):
     201        if len(tz) < 5:
     202            return tz + '00'
     203        return tz.replace(':', '')
     204    return _timezones.get(tz, '+0000')
     205
     206
     207def _get_timezone(tz):
     208    tz = _timezone_as_offset(tz)
     209    minutes = 60 * int(tz[1:3]) + int(tz[3:5])
     210    if tz[0] == '-':
     211        minutes = -minutes
     212    return timezone(timedelta(minutes=minutes), tz)
    169213
    170214
     
    674718        tz = '+0000'
    675719    fmt = '%H:%M:%S.%f' if len(value) > 8 else '%H:%M:%S'
    676     if timezones:
    677         if tz.startswith(('+', '-')):
    678             if len(tz) < 5:
    679                 tz += '00'
    680             else:
    681                 tz = tz.replace(':', '')
    682         elif tz in timezones:
    683             tz = timezones[tz]
    684         else:
    685             tz = '+0000'
    686         value += tz
     720    if _has_timezone:
     721        value += _timezone_as_offset(tz)
    687722        fmt += '%z'
    688     return datetime.strptime(value, fmt).timetz()
     723        return datetime.strptime(value, fmt).timetz()
     724    return datetime.strptime(value, fmt).timetz().replace(
     725        tzinfo=_get_timezone(tz))
    689726
    690727
     
    741778            return datetime.max
    742779        fmt = [fmt, '%H:%M:%S.%f' if len(value[1]) > 8 else '%H:%M:%S']
    743     if timezones:
    744         if tz.startswith(('+', '-')):
    745             if len(tz) < 5:
    746                 tz += '00'
    747             else:
    748                 tz = tz.replace(':', '')
    749         elif tz in timezones:
    750             tz = timezones[tz]
    751         else:
    752             tz = '+0000'
    753         value.append(tz)
     780    if _has_timezone:
     781        value.append(_timezone_as_offset(tz))
    754782        fmt.append('%z')
    755     return datetime.strptime(' '.join(value), ' '.join(fmt))
     783        return datetime.strptime(' '.join(value), ' '.join(fmt))
     784    return datetime.strptime(' '.join(value), ' '.join(fmt)).replace(
     785        tzinfo=_get_timezone(tz))
     786
    756787
    757788_re_interval_sql_standard = regex(
Note: See TracChangeset for help on using the changeset viewer.