| 35 | | class PgTIMESTAMPTZ_Adapter(adapters.Adapter): |
|---|
| | 35 | class 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 | """ |
|---|
| | 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 | |
|---|
| | 86 | class 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)) |
|---|