Skip to content

Commit 195e02a

Browse files
committed
Shapefile driver/ogr2ogr to Shapefile: write DateTime as ISO8601 string, both in Arrow and non-Arrow code paths
Fixes #11671
1 parent 92ed5d5 commit 195e02a

File tree

3 files changed

+57
-5
lines changed

3 files changed

+57
-5
lines changed

apps/ogr2ogr_lib.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -4048,6 +4048,12 @@ static void DoFieldTypeConversion(GDALDataset *poDstDS,
40484048
}
40494049
oFieldDefn.SetType(OFTReal);
40504050
}
4051+
else if (oFieldDefn.GetType() == OFTDateTime && poDstDriver &&
4052+
EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile"))
4053+
{
4054+
// Just be silent. The shapefile driver will itself emit a
4055+
// warning mentionning it converts DateTime to String.
4056+
}
40514057
else if (!bQuiet)
40524058
{
40534059
CPLError(
@@ -6518,7 +6524,10 @@ bool LayerTranslator::Translate(
65186524
}
65196525

65206526
poDstFeature->Reset();
6521-
if (poDstFeature->SetFrom(poFeature.get(), panMap, TRUE) !=
6527+
6528+
if (poDstFeature->SetFrom(
6529+
poFeature.get(), panMap, /* bForgiving = */ TRUE,
6530+
/* bUseISO8601ForDateTimeAsString = */ true) !=
65226531
OGRERR_NONE)
65236532
{
65246533
if (psOptions->nGroupTransactions)

autotest/utilities/test_ogr2ogr_lib.py

+43
Original file line numberDiff line numberDiff line change
@@ -3169,3 +3169,46 @@ def test_ogr2ogr_lib_transfer_filegdb_relationships(tmp_vsimem):
31693169
assert relationship.GetLeftTableName() == "table6"
31703170
assert relationship.GetRightTableName() == "table7"
31713171
assert relationship.GetMappingTableName() == "composite_many_to_many"
3172+
3173+
3174+
###############################################################################
3175+
3176+
3177+
@gdaltest.enable_exceptions()
3178+
@pytest.mark.require_driver("GPKG")
3179+
@pytest.mark.parametrize("OGR2OGR_USE_ARROW_API", ["YES", "NO"])
3180+
def test_ogr2ogr_lib_datetime_in_shapefile(tmp_vsimem, OGR2OGR_USE_ARROW_API):
3181+
3182+
src_filename = str(tmp_vsimem / "src.gpkg")
3183+
with ogr.GetDriverByName("GPKG").CreateDataSource(src_filename) as src_ds:
3184+
src_lyr = src_ds.CreateLayer("test", geom_type=ogr.wkbNone)
3185+
3186+
field = ogr.FieldDefn("dt", ogr.OFTDateTime)
3187+
src_lyr.CreateField(field)
3188+
f = ogr.Feature(src_lyr.GetLayerDefn())
3189+
f.SetField("dt", "2022-05-31T12:34:56.789+05:30")
3190+
src_lyr.CreateFeature(f)
3191+
3192+
got_msg = []
3193+
3194+
def my_handler(errorClass, errno, msg):
3195+
got_msg.append(msg)
3196+
return
3197+
3198+
out_filename = str(tmp_vsimem / "out.dbf")
3199+
with gdaltest.error_handler(my_handler), gdaltest.config_options(
3200+
{"CPL_DEBUG": "ON", "OGR2OGR_USE_ARROW_API": OGR2OGR_USE_ARROW_API}
3201+
):
3202+
gdal.VectorTranslate(out_filename, src_filename)
3203+
3204+
if OGR2OGR_USE_ARROW_API == "YES":
3205+
assert "OGR2OGR: Using WriteArrowBatch()" in got_msg
3206+
else:
3207+
assert "OGR2OGR: Using WriteArrowBatch()" not in got_msg
3208+
3209+
print(got_msg)
3210+
assert "Field dt created as String field, though DateTime requested." in got_msg
3211+
3212+
with ogr.Open(out_filename) as dst_ds:
3213+
dst_lyr = dst_ds.GetLayer(0)
3214+
assert [f.GetField("dt") for f in dst_lyr] == ["2022-05-31T12:34:56.789+05:30"]

ogr/ogrsf_frmts/shape/ogrshapelayer.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -2086,11 +2086,11 @@ OGRErr OGRShapeLayer::CreateField(const OGRFieldDefn *poFieldDefn,
20862086
case OFTDateTime:
20872087
CPLError(
20882088
CE_Warning, CPLE_NotSupported,
2089-
"Field %s create as date field, though DateTime requested.",
2089+
"Field %s created as String field, though DateTime requested.",
20902090
szNewFieldName);
2091-
chType = 'D';
2092-
nWidth = 8;
2093-
oModFieldDefn.SetType(OFTDate);
2091+
chType = 'C';
2092+
nWidth = static_cast<int>(strlen("YYYY-MM-DDTHH:MM:SS.sss+HH:MM"));
2093+
oModFieldDefn.SetType(OFTString);
20942094
break;
20952095

20962096
default:

0 commit comments

Comments
 (0)