Contact: fumanchu@aminus.org

Log in as guest/geniusql to create tickets

Changeset 153

Show
Ignore:
Timestamp:
08/28/07 20:28:30
Author:
fumanchu
Message:

Separate adapters for timezone-aware or -naive datetimes for Postgres.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/geniusql/providers/postgres.py

    r152 r153  
    3333 
    3434 
    35 class PgTIMESTAMPTZ_Adapter(adapters.Adapter): 
     35class datetime_to_PgTIMESTAMPTZ_Adapter(adapters.Adapter): 
     36    """Adapter for timezone-naive datetime objects. 
     37     
     38    Postgres stores all timestamps as UTC internally, adjusting inbound 
     39    values based on their timezone component, and offsetting outbound 
     40    values relative to the Postgres 'timezone' config entry. 
     41     
     42    This adapter assumes you always want to push and pull datetime objects 
     43    that have no timezone. Therefore, it doesn't supply a timezone atom 
     44    when sending datetime data to Postgres. When retrieving values, any 
     45    offset is silently ignored. That is, in both case, we assume you 
     46    correctly set the connection's timezone attribute. 
     47    """ 
    3648     
    3749    def push(self, value, dbtype): 
     
    4153                (value.year, value.month, value.day, 
    4254                 value.hour, value.minute, value.second)) 
     55     
     56    def pull(self, value, dbtype): 
     57        if value is None: 
     58            return None 
     59        if isinstance(value, datetime.datetime): 
     60            return value 
     61        chunks = (value[0:4], value[5:7], value[8:10], 
     62                  value[11:13], value[14:16], value[17:19]) 
     63        args = map(int, chunks) 
     64         
     65        ms, tz = None, None 
     66        mstz = value[19:] 
     67        if mstz: 
     68            signpos = mstz.find("+") 
     69            if signpos == -1: 
     70                signpos = mstz.find("-") 
     71             
     72            if signpos != -1: 
     73                # We have a timezone. Split it off. 
     74                ms = mstz[:signpos] 
     75            else: 
     76                ms = mstz 
     77             
     78            if ms: 
     79                ms = int(ms.strip(".")) 
     80         
     81        args.append(ms or 0) 
     82         
     83        return datetime.datetime(*args) 
     84 
     85 
     86class datetime_tz_to_PgTIMESTAMPTZ_Adapter(adapters.Adapter): 
     87    """Adapter for timezone-aware datetime objects. 
     88     
     89    Postgres stores all timestamps as UTC internally, adjusting inbound 
     90    values based on their timezone component, and offsetting outbound 
     91    values relative to the Postgres 'timezone' config entry. 
     92     
     93    This adapter assumes you always want to push and pull datetime objects 
     94    that have a valid tzinfo. Therefore, it always tries to supply a 
     95    timezone atom when sending datetime data to Postgres. If you push 
     96    a datetime with a tzinfo of None, "+00" is used for the timezone. 
     97    When retrieving values, any offset in the database value is used to 
     98    form a valid tzinfo object for the value (see dbtypes.FixedTimeZone). 
     99    In both directions, we assume you correctly set the connection's 
     100    timezone attribute. 
     101    """ 
     102     
     103    def push(self, value, dbtype): 
     104        if value is None: 
     105            return 'NULL' 
     106         
     107        if value.tzinfo is None: 
     108            h, m = 0, 0 
     109        else: 
     110            h, m = divmod(value.tzinfo.utcoffset(value), 60) 
     111         
     112        if h < 0: 
     113            h = abs(h) 
     114            sign = "-" 
     115        else: 
     116            sign = "+" 
     117         
     118        return ("TIMESTAMP WITH TIME ZONE " 
     119                "'%04d-%02d-%02d %02d:%02d:%02d%s%02d:%02d'" % 
     120                (value.year, value.month, value.day, 
     121                 value.hour, value.minute, value.second, 
     122                 sign, h, m)) 
    43123     
    44124    def pull(self, value, dbtype): 
     
    401481class TIMESTAMPTZ(dbtypes.SQL92TIMESTAMP): 
    402482    """A date and time.""" 
    403     default_adapters = {datetime.datetime: PgTIMESTAMPTZ_Adapter()} 
     483    default_adapters = {datetime.datetime: datetime_to_PgTIMESTAMPTZ_Adapter()} 
    404484 
    405485class DATE(dbtypes.SQL92DATE):