diff --git a/HISTORY.md b/HISTORY.md index 4e449e4..c02639d 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -11,6 +11,7 @@ ### Bugfixes - Fixed minimal openpyxl dependency version to 2.6.0 (#457). +- Dates from xls files are now read as Python datetime objects (#373). ## 1.1.0 (2020-02-13) diff --git a/src/tablib/formats/_xls.py b/src/tablib/formats/_xls.py index 7a8ec63..b4e7eb2 100644 --- a/src/tablib/formats/_xls.py +++ b/src/tablib/formats/_xls.py @@ -6,6 +6,7 @@ from io import BytesIO import tablib import xlrd import xlwt +from xlrd.xldate import xldate_as_datetime # special styles wrap = xlwt.easyxf("alignment: wrap on") @@ -74,12 +75,19 @@ class XLSFormat: dset.title = sheet.name + def cell_value(value, type_): + if type_ == xlrd.XL_CELL_ERROR: + return xlrd.error_text_from_code[value] + elif type_ == xlrd.XL_CELL_DATE: + return xldate_as_datetime(value, xls_book.datemode) + return value + for i in range(sheet.nrows): if i == 0 and headers: dset.headers = sheet.row_values(0) else: dset.append([ - val if typ != xlrd.XL_CELL_ERROR else xlrd.error_text_from_code[val] + cell_value(val, typ) for val, typ in zip(sheet.row_values(i), sheet.row_types(i)) ]) diff --git a/tests/files/dates.xls b/tests/files/dates.xls new file mode 100644 index 0000000..b74a045 Binary files /dev/null and b/tests/files/dates.xls differ diff --git a/tests/test_tablib.py b/tests/test_tablib.py index 3d71da5..6a2fbc2 100755 --- a/tests/test_tablib.py +++ b/tests/test_tablib.py @@ -975,6 +975,12 @@ class XLSTests(BaseTestCase): in_stream = self.founders.xls self.assertEqual(detect_format(in_stream), 'xls') + def test_xls_date_import(self): + xls_source = Path(__file__).parent / 'files' / 'dates.xls' + with open(str(xls_source), mode='rb') as fh: + dset = tablib.Dataset().load(fh, 'xls') + self.assertEqual(dset.dict[0]['birth_date'], datetime.datetime(2015, 4, 12, 0, 0)) + def test_xls_import_with_errors(self): """Errors from imported files are kept as errors.""" xls_source = Path(__file__).parent / 'files' / 'errors.xls'