From c25fe54b6f1cb15e88faec3af33c892758dd0a22 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Mon, 9 Mar 2020 14:17:48 +0100 Subject: [PATCH] Refs #373 - Import dates from xls files as Python datetime objects --- HISTORY.md | 1 + src/tablib/formats/_xls.py | 10 +++++++++- tests/files/dates.xls | Bin 0 -> 5632 bytes tests/test_tablib.py | 6 ++++++ 4 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/files/dates.xls 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 0000000000000000000000000000000000000000..b74a045028af5bbf1d7e12831fa88dc44ce8bc2a GIT binary patch literal 5632 zcmeHLU2IfU5T3I?alh*1QC+ja{p3&pY~n)tJT z_@YfDJQxiLA*l~UgEg8MqtWe~4;qc8@#m@NlRpoOK@AD*`h9cn+UvRtThm}Lo$Z`6 zcg~zMbLPyMxwl_@UO#o_?d9jC0PYgM%;Z8+;o%$5R{l9G;sZ_IOfHwpvq3Jvb>x9* z*H)fk0EZX^^2`?j$qTvtb+n}gQ|I7;?J|sCN^IFI2hoqnQ#kSRVF@C}tFD}x-h5Gx z{MBR@^v`=l!n)RspMlHNaY69S|iz>VXZw#lS{j6L1M| zDewm1GT?F`b>8Uqq;CRkyU#6dKf8+s>RNdqWZ@Jmg7QJlr%d^p`_CgH#sd=?7vF=o zTMjWcx?{-!`&z*!wIOC0n;8V@22e&$fmf*RsO~D_;g<}`BHqYT1@``%O8VJZEnwn zyq`NAKV%E}9VPgY68zOA_@SbFK`5v_%*6^B`=k#KY00q+07RIkc$q~Wu=O0DdO^(Pbkc26u7I~-5Fgv;E4--NM%B0ENn{45VMrDwOR&WbEk zH}5>-gfZvEbyAgO%KsQaYsnFV5@BU<<;03g^92?K6bTE(!a@dsJl`aV;Uy*4@_E^cT71n2tTKa&1^`ox)dL zt2}f&=r!LQ#orHI9iS_AjR$v)f8BLPT2Mj>zsje0+x^7CEZGQf~XVn9N*6JrnO`{MOx%p_>U4z^3w^Q{33nySoU6U z;H@mZql;nVb>h$7isw2BWZRV=$~qeH-~pdh>O4A&9}IW<8ssA_A5o9gMzwD$pq zf$631M$jqEo)Fd6X-F@7Wc015hz>uB^IVrpi4}()0+FkuD1Lf|Y rIp|Gy$)NN=!+_cl*Z)Aw&7SrDV*fWocgod2AKhI2@BRM%ul4^44jUt6 literal 0 HcmV?d00001 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'