Skip to content

Commit a55e7e4

Browse files
committed
ENH: handle np.datetime64,np.timedelta64,date,timedelta types
1 parent c9a9e3e commit a55e7e4

File tree

2 files changed

+60
-21
lines changed

2 files changed

+60
-21
lines changed

pandas/io/packers.py

+44-21
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@
4040
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4141
"""
4242

43-
from datetime import datetime
43+
from datetime import datetime, date, timedelta
4444
import time
4545
import re
4646
import copy
4747
import itertools
4848
import warnings
49+
from dateutil.parser import parse
4950

5051
import numpy as np
5152
from pandas import (
@@ -128,8 +129,12 @@ def read_msgpack(path, iterator=False, **kwargs):
128129
return l[0]
129130
return l
130131

131-
dtype_dict = { 'datetime64[ns]' : np.dtype('M8[ns]'),
132-
'timedelta64[ns]' : np.dtype('m8[ns]') }
132+
dtype_dict = { 21 : np.dtype('M8[ns]'),
133+
u'datetime64[ns]' : np.dtype('M8[ns]'),
134+
u'datetime64[us]' : np.dtype('M8[us]'),
135+
22 : np.dtype('m8[ns]'),
136+
u'timedelta64[ns]' : np.dtype('m8[ns]'),
137+
u'timedelta64[us]' : np.dtype('m8[us]') }
133138

134139
def dtype_for(t):
135140
if t in dtype_dict:
@@ -169,33 +174,33 @@ def encode(obj):
169174
return {'typ' : 'period_index',
170175
'klass' : obj.__class__.__name__,
171176
'name' : getattr(obj,'name',None),
172-
'dtype': obj.dtype.name,
177+
'dtype': obj.dtype.num,
173178
'data': obj.tolist() }
174179
elif isinstance(obj, DatetimeIndex):
175180
return {'typ' : 'datetime_index',
176181
'klass' : obj.__class__.__name__,
177182
'name' : getattr(obj,'name',None),
178-
'dtype': obj.dtype.name,
183+
'dtype': obj.dtype.num,
179184
'data': obj.values.view('i8').tolist(),
180185
'freq' : obj.freqstr,
181186
'tz' : obj.tz}
182187
elif isinstance(obj, MultiIndex):
183188
return {'typ' : 'multi_index',
184189
'klass' : obj.__class__.__name__,
185190
'names' : getattr(obj,'names',None),
186-
'dtype': obj.dtype.name,
191+
'dtype': obj.dtype.num,
187192
'data': obj.tolist() }
188193
else:
189194
return {'typ' : 'index',
190195
'klass' : obj.__class__.__name__,
191196
'name' : getattr(obj,'name',None),
192-
'dtype': obj.dtype.name,
197+
'dtype': obj.dtype.num,
193198
'data': obj.tolist() }
194199
elif isinstance(obj, Series):
195200
if isinstance(obj, SparseSeries):
196201
d = {'typ' : 'sparse_series',
197202
'klass' : obj.__class__.__name__,
198-
'dtype': obj.dtype.name,
203+
'dtype': obj.dtype.num,
199204
'index' : obj.index,
200205
'sp_index' : obj.sp_index,
201206
'sp_values' : convert(obj.sp_values)}
@@ -207,7 +212,7 @@ def encode(obj):
207212
'klass' : obj.__class__.__name__,
208213
'name' : getattr(obj,'name',None),
209214
'index' : obj.index,
210-
'dtype': obj.dtype.name,
215+
'dtype': obj.dtype.num,
211216
'data': convert(obj.values) }
212217
elif issubclass(tobj, NDFrame):
213218
if isinstance(obj, SparseDataFrame):
@@ -239,11 +244,11 @@ def encode(obj):
239244
'blocks' : [ { 'items' : b.items,
240245
'values' : convert(b.values),
241246
'shape' : b.values.shape,
242-
'dtype' : b.dtype.name,
247+
'dtype' : b.dtype.num,
243248
'klass' : b.__class__.__name__
244249
} for b in data.blocks ] }
245250

246-
elif isinstance(obj, datetime):
251+
elif isinstance(obj, (datetime,date,timedelta)):
247252
if isinstance(obj, Timestamp):
248253
tz = obj.tzinfo
249254
if tz is not None:
@@ -255,8 +260,16 @@ def encode(obj):
255260
'value': obj.value,
256261
'offset' : offset,
257262
'tz' : tz}
258-
return { 'typ' : 'datetime',
259-
'data' : obj.isoformat() }
263+
elif isinstance(obj, timedelta):
264+
return { 'typ' : 'timedelta',
265+
'data' : (obj.days,obj.seconds,obj.microseconds) }
266+
elif isinstance(obj, datetime):
267+
return { 'typ' : 'datetime',
268+
'data' : obj.isoformat() }
269+
elif isinstance(obj, date):
270+
return { 'typ' : 'date',
271+
'data' : obj.isoformat() }
272+
raise Exception("cannot encode this datetimelike object: %s" % obj)
260273
elif isinstance(obj, Period):
261274
return {'typ' : 'period',
262275
'ordinal' : obj.ordinal,
@@ -276,8 +289,11 @@ def encode(obj):
276289
return {'typ' : 'ndarray',
277290
'shape': obj.shape,
278291
'ndim': obj.ndim,
279-
'dtype': obj.dtype.name,
292+
'dtype': obj.dtype.num,
280293
'data': convert(obj)}
294+
elif isinstance(obj, np.timedelta64):
295+
return { 'typ' : 'np_timedelta64',
296+
'data' : obj.view('i8') }
281297
elif isinstance(obj, np.number):
282298
if np.iscomplexobj(obj):
283299
return {'typ' : 'np_scalar',
@@ -293,9 +309,8 @@ def encode(obj):
293309
return {'typ' : 'np_complex',
294310
'real': obj.real.__repr__(),
295311
'imag': obj.imag.__repr__()}
296-
else:
297-
import pdb; pdb.set_trace()
298-
return obj
312+
313+
return obj
299314

300315
def decode(obj):
301316
"""
@@ -333,8 +348,11 @@ def create_block(b):
333348
blocks = [ create_block(b) for b in obj['blocks'] ]
334349
return globals()[obj['klass']](BlockManager(blocks, axes))
335350
elif typ == 'datetime':
336-
import pdb; pdb.set_trace()
337-
return datetime.fromtimestamp(obj['data'])
351+
return parse(obj['data'])
352+
elif typ == 'date':
353+
return parse(obj['data']).date()
354+
elif typ == 'timedelta':
355+
return timedelta(*obj['data'])
338356
elif typ == 'sparse_series':
339357
dtype = dtype_for(obj['dtype'])
340358
return globals()[obj['klass']](np.array(obj['sp_values'],dtype=dtype),sparse_index=obj['sp_index'],
@@ -353,17 +371,22 @@ def create_block(b):
353371
return np.array(obj['data'],
354372
dtype=np.typeDict[obj['dtype']],
355373
ndmin=obj['ndim']).reshape(obj['shape'])
374+
elif typ == 'np_timedelta64':
375+
return np.timedelta64(obj['data'])
356376
elif typ == 'np_scalar':
357377
if obj.get('sub_typ') == 'np_complex':
358378
return c2f(obj['real'], obj['imag'], obj['dtype'])
359379
else:
360-
return np.typeDict[obj['dtype']](obj['data'])
380+
dtype = dtype_for(obj['dtype'])
381+
try:
382+
return dtype(obj['data'])
383+
except:
384+
return dtype.type(obj['data'])
361385
elif typ == 'np_complex':
362386
return complex(obj['real']+'+'+obj['imag']+'j')
363387
elif isinstance(obj, (dict,list,set)):
364388
return obj
365389
else:
366-
import pdb; pdb.set_trace()
367390
return obj
368391

369392
def pack(o, default=encode,

pandas/io/tests/test_packers.py

+16
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,22 @@ def test_timestamp(self):
155155
i_rec = self.encode_decode(i)
156156
self.assert_(i == i_rec)
157157

158+
def test_datetimes(self):
159+
160+
for i in [ datetime.datetime(2013,1,1), datetime.datetime(2013,1,1,5,1),
161+
datetime.date(2013,1,1), np.datetime64('2013-01-05 2:15') ]:
162+
i_rec = self.encode_decode(i)
163+
self.assert_(i == i_rec)
164+
165+
def test_timedeltas(self):
166+
167+
for i in [ datetime.timedelta(days=1),
168+
datetime.timedelta(days=1,seconds=10),
169+
np.timedelta64(1000000) ]:
170+
i_rec = self.encode_decode(i)
171+
self.assert_(i == i_rec)
172+
173+
158174
class TestIndex(Test):
159175

160176
def setUp(self):

0 commit comments

Comments
 (0)