diff --git a/doc/source/whatsnew/v0.17.1.txt b/doc/source/whatsnew/v0.17.1.txt index fa08a9790f789..88c46f3bcb863 100755 --- a/doc/source/whatsnew/v0.17.1.txt +++ b/doc/source/whatsnew/v0.17.1.txt @@ -96,3 +96,4 @@ Bug Fixes - Bugs in ``to_excel`` with duplicate columns (:issue:`11007`, :issue:`10982`, :issue:`10970`) - Fixed a bug that prevented the construction of an empty series of dtype ``datetime64[ns, tz]`` (:issue:`11245`). +- Bug in ``DataFrame.to_dict()`` produces an datetime object instead of Timestamp when only datetime is present in data (:issue:`11327`) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index e92de770ac4bd..827373c9a330b 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -802,11 +802,12 @@ def to_dict(self, orient='dict'): elif orient.lower().startswith('sp'): return {'index': self.index.tolist(), 'columns': self.columns.tolist(), - 'data': self.values.tolist()} + 'data': lib.map_infer(self.values.ravel(), _maybe_box_datetimelike) + .reshape(self.values.shape).tolist()} elif orient.lower().startswith('s'): - return dict((k, v) for k, v in compat.iteritems(self)) + return dict((k, _maybe_box_datetimelike(v)) for k, v in compat.iteritems(self)) elif orient.lower().startswith('r'): - return [dict((k, v) for k, v in zip(self.columns, row)) + return [dict((k, _maybe_box_datetimelike(v)) for k, v in zip(self.columns, row)) for row in self.values] elif orient.lower().startswith('i'): return dict((k, v.to_dict()) for k, v in self.iterrows()) diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 6667d389bd6c5..c3abbae137418 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -4728,6 +4728,55 @@ def test_to_dict(self): for k2, v2 in compat.iteritems(v): self.assertEqual(v2, recons_data[k2][k]) + def test_to_dict_timestamp(self): + # GH11247 + tsmp = Timestamp('20130101') + test_data = DataFrame({'A': [tsmp, tsmp], 'B': [tsmp, tsmp]}) + test_data_mixed = DataFrame({'A': [tsmp, tsmp], 'B': [1, 2]}) + + expected_records = [{'A': tsmp, 'B': tsmp}, + {'A': tsmp, 'B': tsmp}] + expected_records_mixed = [{'A': tsmp, 'B': 1}, + {'A': tsmp, 'B': 2}] + + tm.assert_almost_equal(test_data.to_dict( + orient='records'), expected_records) + tm.assert_almost_equal(test_data_mixed.to_dict( + orient='records'), expected_records_mixed) + + expected_series = { + 'A': Series([tsmp, tsmp]), + 'B': Series([tsmp, tsmp]), + } + expected_series_mixed = { + 'A': Series([tsmp, tsmp]), + 'B': Series([1, 2]), + } + + tm.assert_almost_equal(test_data.to_dict( + orient='series'), expected_series) + tm.assert_almost_equal(test_data_mixed.to_dict( + orient='series'), expected_series_mixed) + + expected_split = { + 'index': [0, 1], + 'data': [[tsmp, tsmp], + [tsmp, tsmp]], + 'columns': ['A', 'B'] + } + expected_split_mixed = { + 'index': [0, 1], + 'data': [[tsmp, 1], + [tsmp, 2]], + 'columns': ['A', 'B'] + } + + tm.assert_almost_equal(test_data.to_dict( + orient='split'), expected_split) + tm.assert_almost_equal(test_data_mixed.to_dict( + orient='split'), expected_split_mixed) + + def test_to_dict_invalid_orient(self): df = DataFrame({'A':[0, 1]}) self.assertRaises(ValueError, df.to_dict, orient='xinvalid')