2
2
3
3
import datetime
4
4
from decimal import Decimal
5
+ import re
5
6
import time
6
7
7
8
from .constants import FIELD_TYPE , FLAG
@@ -145,6 +146,16 @@ def escape_date(obj, mapping=None):
145
146
def escape_struct_time (obj , mapping = None ):
146
147
return escape_datetime (datetime .datetime (* obj [:6 ]))
147
148
149
+ def _convert_second_fraction (s ):
150
+ if not s :
151
+ return 0
152
+ # Pad zeros to ensure the fraction length in microseconds
153
+ s = s .ljust (6 , '0' )
154
+ return int (s [:6 ])
155
+
156
+ DATETIME_RE = re .compile (r"(\d{1,4})-(\d{1,2})-(\d{1,2})[T ](\d{1,2}):(\d{1,2}):(\d{1,2})(?:.(\d{1,6}))?" )
157
+
158
+
148
159
def convert_datetime (obj ):
149
160
"""Returns a DATETIME or TIMESTAMP column value as a datetime object:
150
161
@@ -163,23 +174,20 @@ def convert_datetime(obj):
163
174
"""
164
175
if not PY2 and isinstance (obj , (bytes , bytearray )):
165
176
obj = obj .decode ('ascii' )
166
- if ' ' in obj :
167
- sep = ' '
168
- elif 'T' in obj :
169
- sep = 'T'
170
- else :
177
+
178
+ m = DATETIME_RE .match (obj )
179
+ if not m :
171
180
return convert_date (obj )
172
181
173
182
try :
174
- ymd , hms = obj .split (sep , 1 )
175
- usecs = '0'
176
- if '.' in hms :
177
- hms , usecs = hms .split ('.' )
178
- usecs = float ('0.' + usecs ) * 1e6
179
- return datetime .datetime (* [ int (x ) for x in ymd .split ('-' )+ hms .split (':' )+ [usecs ] ])
183
+ groups = list (m .groups ())
184
+ groups [- 1 ] = _convert_second_fraction (groups [- 1 ])
185
+ return datetime .datetime (* [ int (x ) for x in groups ])
180
186
except ValueError :
181
187
return convert_date (obj )
182
188
189
+ TIMEDELTA_RE = re .compile (r"(-)?(\d{1,3}):(\d{1,2}):(\d{1,2})(?:.(\d{1,6}))?" )
190
+
183
191
184
192
def convert_timedelta (obj ):
185
193
"""Returns a TIME column as a timedelta object:
@@ -200,16 +208,17 @@ def convert_timedelta(obj):
200
208
"""
201
209
if not PY2 and isinstance (obj , (bytes , bytearray )):
202
210
obj = obj .decode ('ascii' )
211
+
212
+ m = TIMEDELTA_RE .match (obj )
213
+ if not m :
214
+ return None
215
+
203
216
try :
204
- microseconds = 0
205
- if "." in obj :
206
- (obj , tail ) = obj .split ('.' )
207
- microseconds = float ('0.' + tail ) * 1e6
208
- hours , minutes , seconds = obj .split (':' )
209
- negate = 1
210
- if hours .startswith ("-" ):
211
- hours = hours [1 :]
212
- negate = - 1
217
+ groups = list (m .groups ())
218
+ groups [- 1 ] = _convert_second_fraction (groups [- 1 ])
219
+ negate = - 1 if groups [0 ] else 1
220
+ hours , minutes , seconds , microseconds = groups [1 :]
221
+
213
222
tdelta = datetime .timedelta (
214
223
hours = int (hours ),
215
224
minutes = int (minutes ),
@@ -220,6 +229,9 @@ def convert_timedelta(obj):
220
229
except ValueError :
221
230
return None
222
231
232
+ TIME_RE<
B41A
/span> = re .compile (r"(\d{1,2}):(\d{1,2}):(\d{1,2})(?:.(\d{1,6}))?" )
233
+
234
+
223
235
def convert_time (obj ):
224
236
"""Returns a TIME column as a time object:
225
237
@@ -244,17 +256,21 @@ def convert_time(obj):
244
256
"""
245
257
if not PY2 and isinstance (obj , (bytes , bytearray )):
246
258
obj = obj .decode ('ascii' )
259
+
260
+ m = TIME_RE .match (obj )
261
+ if not m :
262
+ return None
263
+
247
264
try :
248
- microseconds = 0
249
- if "." in obj :
250
- (obj , tail ) = obj .split ('.' )
251
- microseconds = float ('0.' + tail ) * 1e6
252
- hours , minutes , seconds = obj .split (':' )
265
+ groups = list (m .groups ())
266
+ groups [- 1 ] = _convert_second_fraction (groups [- 1 ])
267
+ hours , minutes , seconds , microseconds = groups
253
268
return datetime .time (hour = int (hours ), minute = int (minutes ),
254
269
second = int (seconds ), microsecond = int (microseconds ))
255
270
except ValueError :
256
271
return None
257
272
273
+
258
274
def convert_date (obj ):
259
275
"""Returns a DATE column as a date object:
260
276
@@ -324,7 +340,7 @@ def through(x):
324
340
#def convert_bit(b):
325
341
# b = "\x00" * (8 - len(b)) + b # pad w/ zeroes
326
342
# return struct.unpack(">Q", b)[0]
327
- #
343
+ #
328
344
# the snippet above is right, but MySQLdb doesn't process bits,
329
345
# so we shouldn't either
330
346
convert_bit = through
0 commit comments