3636 time64_noday_io
3737 long-long based time I/O with noday-intervals.
3838"""
39+ import warnings
3940import codecs
4041from ..encodings import aliases as pg_enc_aliases
42+ from .. import exceptions as pg_exc
4143
4244from operator import itemgetter , add , sub , mul , methodcaller
4345get0 = itemgetter (0 )
5153from decimal import Decimal , DecimalTuple
5254import datetime
5355
56+ from ..exceptions import TypeConversionWarning
5457from ..python .datetime import UTC , FixedOffset
5558
5659from ..python .functools import Composition as compose
7174# High level type I/O routines.
7275##
7376toordinal = methodcaller ("toordinal" )
77+ convert_to_utc = methodcaller ('astimezone' , UTC )
78+ remove_tzinfo = methodcaller ('replace' , tzinfo = None )
79+ set_as_utc = methodcaller ('replace' , tzinfo = UTC )
7480
7581date_pack = compose ((
7682 toordinal ,
8389 datetime .date .fromordinal
8490))
8591
92+ seconds_in_day = 24 * 60 * 60
93+ seconds_in_hour = 60 * 60
94+
8695def timestamp_pack (x ):
8796 """
8897 Create a (seconds, microseconds) pair from a `datetime.datetime` instance.
8998 """
9099 d = (x - pg_epoch_datetime )
91- return (d .days * 24 * 60 * 60 + d .seconds , d .microseconds )
100+ return (( d .days * seconds_in_day ) + d .seconds , d .microseconds )
92101
93102def timestamp_unpack (seconds ):
94103 """
@@ -103,7 +112,7 @@ def time_pack(x):
103112 Create a (seconds, microseconds) pair from a `datetime.time` instance.
104113 """
105114 return (
106- (x .hour * 60 * 60 ) + (x .minute * 60 ) + x .second ,
115+ (x .hour * seconds_in_hour ) + (x .minute * 60 ) + x .second ,
107116 x .microsecond
108117 )
109118
@@ -132,6 +141,16 @@ def interval_unpack(mds):
132141 `datetime.timedelta` instance.
133142 """
134143 months , days , seconds_ms = mds
144+ if months != 0 :
145+ w = pg_exc .TypeConversionWarning (
146+ "datetime.timedelta cannot represent relative intervals" ,
147+ details = {
148+ ''
149+ 'hint' : 'An interval was unpacked with a non-zero "month" field.'
150+ },
151+ source = 'DRIVER'
152+ )
153+ warnings .warn (w )
135154 sec , ms = seconds_ms
136155 return datetime .timedelta (
137156 days = days + (months * 30 ),
@@ -143,7 +162,9 @@ def timetz_pack(x):
143162 Create a ((seconds, microseconds), timezone) tuple from a `datetime.time`
144163 instance.
145164 """
146- return (time_pack (x ), x .utcoffset ())
165+ td = x .tzinfo .utcoffset (x )
166+ seconds = (td .days * seconds_in_day + td .seconds )
167+ return (time_pack (x ), seconds )
147168
148169def timetz_unpack (tstz ):
149170 """
@@ -167,8 +188,8 @@ def timetz_unpack(tstz):
167188 compose ((ts .time_unpack , timestamp_unpack )),
168189 ),
169190 pg_types .TIMESTAMPTZOID : (
170- compose ((timestamp_pack , ts .time_pack )),
171- compose ((ts .time_unpack , timestamp_unpack )),
191+ compose ((convert_to_utc , remove_tzinfo , timestamp_pack , ts .time_pack )),
192+ compose ((ts .time_unpack , timestamp_unpack , set_as_utc )),
172193 ),
173194 pg_types .INTERVALOID : (
174195 compose ((interval_pack , ts .interval_pack )),
@@ -195,8 +216,8 @@ def timetz_unpack(tstz):
195216 compose ((ts .time64_unpack , timestamp_unpack )),
196217 ),
197218 pg_types .TIMESTAMPTZOID : (
198- compose ((timestamp_pack , ts .time64_pack )),
199- compose ((ts .time64_unpack , timestamp_unpack )),
219+ compose ((convert_to_utc , remove_tzinfo , timestamp_pack , ts .time64_pack )),
220+ compose ((ts .time64_unpack , timestamp_unpack , set_as_utc )),
200221 ),
201222 pg_types .INTERVALOID : (
202223 compose ((interval_pack , ts .interval64_pack )),
@@ -564,7 +585,6 @@ def select_time_io(self,
564585 self ._time_io = time_io_noday
565586 else :
566587 self ._time_io = time_io
567- self ._ts_pack , self ._ts_unpack = self ._time_io [pg_types .TIMESTAMPOID ]
568588
569589 def encode (self , string_data ):
570590 return self ._encode (string_data )[0 ]
@@ -636,10 +656,6 @@ def __init__(self):
636656 pg_types .CIDROID : (None , None ),
637657 pg_types .INETOID : (None , None ),
638658
639- pg_types .TIMESTAMPTZOID : (
640- self ._pack_timestamptz ,
641- self ._unpack_timestamptz ,
642- ),
643659 pg_types .XMLOID : (
644660 self .xml_pack , self .xml_unpack
645661 ),
@@ -672,20 +688,6 @@ def set_encoding(self, value):
672688 self ._encode = ci [0 ]
673689 self ._decode = ci [1 ]
674690
675- def _pack_timestamptz (self , dt ):
676- if dt .tzinfo :
677- return self ._ts_pack (
678- (dt - dt .tzinfo .utcoffset (dt )).replace (tzinfo = None )
679- )
680- else :
681- # If no timezone is specified, assume UTC.
682- return self ._ts_pack (dt )
683-
684- def _unpack_timestamptz (self , data ):
685- dt = self ._ts_unpack (data )
686- dt = dt .replace (tzinfo = UTC )
687- return dt
688-
689691 def resolve_descriptor (self , desc , index ):
690692 'create a sequence of I/O routines from a pq descriptor'
691693 return [
0 commit comments