Skip to content
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Fix regression in reading date columns (#616)
- Fix error in `read_dataframe` when `use_arrow=True` and `columns` is used to filter
out columns of some specific types (#611)
- Fix Time type columns being skipped when reading with `arrow=False` (#617)

## 0.12.0 (2025-11-26)

Expand Down
8 changes: 5 additions & 3 deletions pyogrio/_io.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ FIELD_TYPES = [
None, # OFTWideStringList, deprecated, not supported
"object", # OFTBinary, Raw Binary data
"datetime64[D]", # OFTDate, Date
None, # OFTTime, Time, NOTE: not directly supported in numpy
"object", # OFTTime, Time, NOTE: not directly supported in numpy
"datetime64[ms]", # OFTDateTime, Date and Time
"int64", # OFTInteger64, Single 64bit integer
"list(int64)" # OFTInteger64List, List of 64bit integers, not supported
Expand Down Expand Up @@ -976,8 +976,7 @@ cdef process_fields(
bin_value = OGR_F_GetFieldAsBinary(ogr_feature, field_index, &ret_length)
data[i] = bin_value[:ret_length]

elif field_type == OFTDateTime or field_type == OFTDate:

elif field_type in (OFTDateTime, OFTDate, OFTTime):
if field_type == OFTDateTime and datetime_as_string:
# defer datetime parsing to user/ pandas layer
IF CTE_GDAL_VERSION >= (3, 7, 0):
Expand Down Expand Up @@ -1019,6 +1018,9 @@ cdef process_fields(
year, month, day, hour, minute, second, microsecond
).isoformat()

elif field_type == OFTTime:
data[i] = datetime.time(hour, minute, second, microsecond)

elif field_type == OFTIntegerList:
# According to GDAL doc, this can return NULL for an empty list, which is a
# valid result. So don't use check_pointer as it would throw an exception.
Expand Down
26 changes: 12 additions & 14 deletions pyogrio/tests/test_geopandas_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
import re
import warnings
from datetime import datetime
from datetime import datetime, time
from io import BytesIO
from zipfile import ZipFile

Expand Down Expand Up @@ -566,7 +566,7 @@ def test_roundtrip_many_data_types_geojson_file(
):
"""Test roundtripping a GeoJSON file containing many data types."""

def validate_result(df: pd.DataFrame, use_arrow: bool, ignore_mixed_list_col=False):
def validate_result(df: pd.DataFrame, use_arrow: bool, after_write=False):
"""Function to validate the data of many_data_types_geojson_file.

Depending on arrow being used or not there are small differences.
Expand Down Expand Up @@ -597,11 +597,12 @@ def validate_result(df: pd.DataFrame, use_arrow: bool, ignore_mixed_list_col=Fal
assert is_datetime64_dtype(df["date_col"].dtype)
assert df["date_col"].to_list() == [pd.Timestamp("2020-01-01")]

# Ignore time columns till this is solved:
# Reported in https://github.com/geopandas/pyogrio/issues/615
# assert "time_col" in df.columns
# assert is_object_dtype(df["time_col"].dtype)
# assert df["time_col"].to_list() == [time(12, 0, 0)]
if not (after_write and use_arrow and not GDAL_GE_311):
# Before GDAL 3.11, if time columns were written with arrow they were
# not actually written.
assert "time_col" in df.columns
assert is_object_dtype(df["time_col"].dtype)
assert df["time_col"].to_list() == [time(12, 0, 0)]

assert "datetime_col" in df.columns
assert is_datetime64_dtype(df["datetime_col"].dtype)
Expand All @@ -615,22 +616,21 @@ def validate_result(df: pd.DataFrame, use_arrow: bool, ignore_mixed_list_col=Fal
assert is_object_dtype(df["list_str_col"].dtype)
assert df["list_str_col"][0].tolist() == ["a", "b", "c"]

if not ignore_mixed_list_col:
if not (after_write and use_arrow):
# Writing a column with mixed types in a list is not supported with Arrow.
assert "list_mixed_col" in df.columns
assert is_object_dtype(df["list_mixed_col"].dtype)
assert df["list_mixed_col"][0] == [1, "a", None, True]

# Read and validate result of reading
read_gdf = read_dataframe(many_data_types_geojson_file, use_arrow=use_arrow)
validate_result(read_gdf, use_arrow)
validate_result(read_gdf, use_arrow, after_write=False)

# Write the data read, read it back, and validate again
if use_arrow:
# Writing a column with mixed types in a list is not supported with Arrow.
ignore_mixed_list_col = True
read_gdf = read_gdf.drop(columns=["list_mixed_col"])
else:
ignore_mixed_list_col = False
request.node.add_marker(
pytest.mark.xfail(
reason="roundtripping list types fails with use_arrow=False"
Expand All @@ -642,9 +642,7 @@ def validate_result(df: pd.DataFrame, use_arrow: bool, ignore_mixed_list_col=Fal

# Validate data written
read_back_gdf = read_dataframe(tmp_file, use_arrow=use_arrow)
validate_result(
read_back_gdf, use_arrow, ignore_mixed_list_col=ignore_mixed_list_col
)
validate_result(read_back_gdf, use_arrow, after_write=True)


@pytest.mark.filterwarnings(
Expand Down