Repository: ToucanToco/fastexcel (language: python)

Issue:
Some duration columns contain only null values after load
For durations, we're we using calamine's `as_time` API to convert durations to milliseconds, as the `as_duration` API was not available yet. However, this does not work anymore, as `as_time` will return `None` for `Duration` values.

_Originally posted by @lukapeschke in https://github.com/ToucanToco/fastexcel/issues/158#issuecomment-1914324743_
            


Discussion / hints:

Fix patch:
diff --git a/Makefile b/Makefile
index a59b9e8..2cab815 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
 ruff	= ruff python/ *.py
 format	= ruff format python/ *.py
 mypy	= mypy python/ *.py
-pytest	= pytest
+pytest	= pytest -v
 ## Rust
 clippy	= cargo clippy
 fmt	= cargo fmt
diff --git a/src/types/excelsheet.rs b/src/types/excelsheet.rs
index 59f2d03..36cf6ce 100644
--- a/src/types/excelsheet.rs
+++ b/src/types/excelsheet.rs
@@ -11,7 +11,7 @@ use arrow::{
     record_batch::RecordBatch,
 };
 use calamine::{DataType as CalDataType, Range};
-use chrono::{NaiveDate, Timelike};
+use chrono::NaiveDate;
 
 use pyo3::prelude::{pyclass, pymethods, PyObject, Python};
 
@@ -186,9 +186,7 @@ fn create_string_array(
 }
 
 fn duration_type_to_i64(caldt: &CalDataType) -> Option<i64> {
-    caldt
-        .as_time()
-        .map(|t| 1000 * i64::from(t.num_seconds_from_midnight()))
+    caldt.as_duration().map(|d| d.num_milliseconds())
 }
 
 fn create_date_array(


Test patch:
diff --git a/python/tests/fixtures/single-sheet-skip-rows-durations.xlsx b/python/tests/fixtures/single-sheet-skip-rows-durations.xlsx
new file mode 100644
index 0000000..201dd56
Binary files /dev/null and b/python/tests/fixtures/single-sheet-skip-rows-durations.xlsx differ
diff --git a/python/tests/test_durations.py b/python/tests/test_durations.py
index 1b18c0f..270ddb1 100644
--- a/python/tests/test_durations.py
+++ b/python/tests/test_durations.py
@@ -60,3 +60,23 @@ def test_sheet_with_different_time_types() -> None:
     )
     pd_assert_frame_equal(pd_df, expected_pd)
     pl_assert_frame_equal(pl_df, expected_pl)
+
+
+def test_sheet_with_offset_header_row_and_durations() -> None:
+    excel_reader = fastexcel.read_excel(path_for_fixture("single-sheet-skip-rows-durations.xlsx"))
+    sheet = excel_reader.load_sheet(0, header_row=9)
+
+    pd_df = sheet.to_pandas()
+    pl_df = sheet.to_polars()
+
+    assert pd_df["Tot. Time Away From System"].dtype == np.dtype("timedelta64[ms]")
+    assert pd_df["Tot. Time Away From System"].tolist() == [
+        pd.Timedelta("01:18:43"),
+        pd.Timedelta("07:16:51"),
+    ]
+
+    assert pl_df["Tot. Time Away From System"].dtype == pl.Duration(time_unit="ms")
+    assert pl_df["Tot. Time Away From System"].to_list() == [
+        timedelta(hours=1, minutes=18, seconds=43),
+        timedelta(hours=7, minutes=16, seconds=51),
+    ]