From 5853e1a7f8ffb89d26f183322c4a3ae69644fa99 Mon Sep 17 00:00:00 2001 From: John McNamara Date: Wed, 31 Dec 2014 02:57:26 +0000 Subject: [PATCH] BUG: Fix for Timestamp handling in xlwt and xlsxwriter engines. Fix for writing Timestamp objects using the xlwt and xlsxwriter engines. Both modules write Excel dates and times using datetime.timedelta which differs from pandas.Timedelta. This fix coerces Timestamp objects to datetime objects. Issue #9139. --- doc/source/whatsnew/v0.16.0.txt | 2 ++ pandas/io/excel.py | 9 +++++++++ pandas/io/tests/test_excel.py | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/doc/source/whatsnew/v0.16.0.txt b/doc/source/whatsnew/v0.16.0.txt index 21b1ddea0e9da..2dbb1f284560d 100644 --- a/doc/source/whatsnew/v0.16.0.txt +++ b/doc/source/whatsnew/v0.16.0.txt @@ -96,6 +96,8 @@ Bug Fixes - Bug in ``pivot`` and `unstack`` where ``nan`` values would break index alignment (:issue:`7466`) +- Fixed bug where minutes and seconds components were zeroed when writing + Timestamp objects to Excel using xlwt and xlsxwriter (:issue:`9138`). diff --git a/pandas/io/excel.py b/pandas/io/excel.py index 2ece91b5dea11..792b9d554be68 100644 --- a/pandas/io/excel.py +++ b/pandas/io/excel.py @@ -16,6 +16,7 @@ from pandas.compat import map, zip, reduce, range, lrange, u, add_metaclass from pandas.core import config from pandas.core.common import pprint_thing +from pandas import Timestamp import pandas.compat as compat import pandas.compat.openpyxl_compat as openpyxl_compat import pandas.core.common as com @@ -1118,6 +1119,10 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0): val = _conv_value(cell.val) num_format_str = None + + if isinstance(val, Timestamp): + val = val.to_pydatetime() + if isinstance(cell.val, datetime.datetime): num_format_str = self.datetime_format elif isinstance(cell.val, datetime.date): @@ -1239,6 +1244,10 @@ def write_cells(self, cells, sheet_name=None, startrow=0, startcol=0): for cell in cells: num_format_str = None + + if isinstance(cell.val, Timestamp): + cell.val = cell.val.to_pydatetime() + if isinstance(cell.val, datetime.datetime): num_format_str = self.datetime_format elif isinstance(cell.val, datetime.date): diff --git a/pandas/io/tests/test_excel.py b/pandas/io/tests/test_excel.py index 4f97cef3d46d3..95b4c0ace642f 100644 --- a/pandas/io/tests/test_excel.py +++ b/pandas/io/tests/test_excel.py @@ -1151,6 +1151,28 @@ def test_swapped_columns(self): tm.assert_series_equal(write_frame['A'], read_frame['A']) tm.assert_series_equal(write_frame['B'], read_frame['B']) + def test_datetimes(self): + # Test writing and reading datetimes. For issue #9139. + _skip_if_no_xlrd() + + datetimes = [datetime(2013, 1, 13, 1, 2, 3), + datetime(2013, 1, 13, 2, 45, 56), + datetime(2013, 1, 13, 4, 29, 49), + datetime(2013, 1, 13, 6, 13, 42), + datetime(2013, 1, 13, 7, 57, 35), + datetime(2013, 1, 13, 9, 41, 28), + datetime(2013, 1, 13, 11, 25, 21), + datetime(2013, 1, 13, 13, 9, 14), + datetime(2013, 1, 13, 14, 53, 7), + datetime(2013, 1, 13, 16, 37, 0), + datetime(2013, 1, 13, 18, 20, 52)] + + with ensure_clean(self.ext) as path: + write_frame = DataFrame.from_items([('A', datetimes)]) + write_frame.to_excel(path, 'Sheet1') + read_frame = read_excel(path, 'Sheet1', header=0) + + tm.assert_series_equal(write_frame['A'], read_frame['A']) def raise_wrapper(major_ver): def versioned_raise_wrapper(orig_method):