Skip to content

Commit

Permalink
Shapefile driver/ogr2ogr to Shapefile: write DateTime as ISO8601 stri…
Browse files Browse the repository at this point in the history
…ng, both in Arrow and non-Arrow code paths

Fixes #11671
  • Loading branch information
rouault committed Jan 16, 2025
1 parent 4b02b50 commit 213cd47
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 5 deletions.
11 changes: 10 additions & 1 deletion apps/ogr2ogr_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4048,6 +4048,12 @@ static void DoFieldTypeConversion(GDALDataset *poDstDS,
}
oFieldDefn.SetType(OFTReal);
}
else if (oFieldDefn.GetType() == OFTDateTime && poDstDriver &&
EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile"))
{
// Just be silent. The shapefile driver will itself emit a
// warning mentionning it converts DateTime to String.
}
else if (!bQuiet)
{
CPLError(
Expand Down Expand Up @@ -6518,7 +6524,10 @@ bool LayerTranslator::Translate(
}

poDstFeature->Reset();
if (poDstFeature->SetFrom(poFeature.get(), panMap, TRUE) !=

if (poDstFeature->SetFrom(
poFeature.get(), panMap, /* bForgiving = */ TRUE,
/* bUseISO8601ForDateTimeAsString = */ true) !=
OGRERR_NONE)
{
if (psOptions->nGroupTransactions)
Expand Down
42 changes: 42 additions & 0 deletions autotest/utilities/test_ogr2ogr_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -3169,3 +3169,45 @@ def test_ogr2ogr_lib_transfer_filegdb_relationships(tmp_vsimem):
assert relationship.GetLeftTableName() == "table6"
assert relationship.GetRightTableName() == "table7"
assert relationship.GetMappingTableName() == "composite_many_to_many"


###############################################################################


@gdaltest.enable_exceptions()
@pytest.mark.parametrize("OGR2OGR_USE_ARROW_API", ["YES", "NO"])
def test_ogr2ogr_lib_datetime_in_shapefile(tmp_vsimem, OGR2OGR_USE_ARROW_API):

src_filename = str(tmp_vsimem / "src.gpkg")
with ogr.GetDriverByName("GPKG").CreateDataSource(src_filename) as src_ds:
src_lyr = src_ds.CreateLayer("test", geom_type=ogr.wkbNone)

field = ogr.FieldDefn("dt", ogr.OFTDateTime)
src_lyr.CreateField(field)
f = ogr.Feature(src_lyr.GetLayerDefn())
f.SetField("dt", "2022-05-31T12:34:56.789+05:30")
src_lyr.CreateFeature(f)

got_msg = []

def my_handler(errorClass, errno, msg):
got_msg.append(msg)
return

out_filename = str(tmp_vsimem / "out.dbf")
with gdaltest.error_handler(my_handler), gdaltest.config_options(
{"CPL_DEBUG": "ON", "OGR2OGR_USE_ARROW_API": OGR2OGR_USE_ARROW_API}
):
gdal.VectorTranslate(out_filename, src_filename)

if OGR2OGR_USE_ARROW_API == "YES":
assert "OGR2OGR: Using WriteArrowBatch()" in got_msg
else:
assert "OGR2OGR: Using WriteArrowBatch()" not in got_msg

print(got_msg)
assert "Field dt created as String field, though DateTime requested." in got_msg

with ogr.Open(out_filename) as dst_ds:
dst_lyr = dst_ds.GetLayer(0)
assert [f.GetField("dt") for f in dst_lyr] == ["2022-05-31T12:34:56.789+05:30"]
8 changes: 4 additions & 4 deletions ogr/ogrsf_frmts/shape/ogrshapelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2086,11 +2086,11 @@ OGRErr OGRShapeLayer::CreateField(const OGRFieldDefn *poFieldDefn,
case OFTDateTime:
CPLError(
CE_Warning, CPLE_NotSupported,
"Field %s create as date field, though DateTime requested.",
"Field %s created as String field, though DateTime requested.",
szNewFieldName);
chType = 'D';
nWidth = 8;
oModFieldDefn.SetType(OFTDate);
chType = 'C';
nWidth = static_cast<int>(strlen("YYYY-MM-DDTHH:MM:SS.sss+HH:MM"));
oModFieldDefn.SetType(OFTString);
break;

default:
Expand Down

0 comments on commit 213cd47

Please sign in to comment.