Skip to content

Commit 2118b22

Browse files
committed
ogr2ogr: GPKG/FlatGeoBuf -> other format: in Arrow code path, use DATETIME_AS_STRING to preserve origin timezone
Fixes #11212
1 parent 4a8ab2d commit 2118b22

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

apps/ogr2ogr_lib.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3997,7 +3997,8 @@ static int GetArrowGeomFieldIndex(const struct ArrowSchema *psLayerSchema,
39973997
/************************************************************************/
39983998

39993999
static CPLStringList
4000-
BuildGetArrowStreamOptions(const GDALVectorTranslateOptions *psOptions,
4000+
BuildGetArrowStreamOptions(OGRLayer *poSrcLayer, OGRLayer *poDstLayer,
4001+
const GDALVectorTranslateOptions *psOptions,
40014002
bool bPreserveFID)
40024003
{
40034004
CPLStringList aosOptionsGetArrowStream;
@@ -4021,6 +4022,31 @@ BuildGetArrowStreamOptions(const GDALVectorTranslateOptions *psOptions,
40214022
"MAX_FEATURES_IN_BATCH",
40224023
CPLSPrintf("%d", psOptions->nGroupTransactions));
40234024
}
4025+
4026+
auto poSrcDS = poSrcLayer->GetDataset();
4027+
auto poDstDS = poDstLayer->GetDataset();
4028+
if (poSrcDS && poDstDS)
4029+
{
4030+
auto poSrcDriver = poSrcDS->GetDriver();
4031+
auto poDstDriver = poDstDS->GetDriver();
4032+
4033+
const auto IsArrowNativeDriver = [](GDALDriver *poDriver)
4034+
{
4035+
return EQUAL(poDriver->GetDescription(), "ARROW") ||
4036+
EQUAL(poDriver->GetDescription(), "PARQUET") ||
4037+
EQUAL(poDriver->GetDescription(), "ADBC");
4038+
};
4039+
4040+
if (poSrcDriver && poDstDriver && !IsArrowNativeDriver(poSrcDriver) &&
4041+
!IsArrowNativeDriver(poDstDriver))
4042+
{
4043+
// For non-Arrow-native drivers, request DateTime as string, to
4044+
// allow mix of timezones
4045+
aosOptionsGetArrowStream.SetNameValue(GAS_OPT_DATETIME_AS_STRING,
4046+
"YES");
4047+
}
4048+
}
4049+
40244050
return aosOptionsGetArrowStream;
40254051
}
40264052

@@ -4085,8 +4111,8 @@ bool SetupTargetLayer::CanUseWriteArrowBatch(
40854111
}
40864112
}
40874113

4088-
const CPLStringList aosGetArrowStreamOptions(
4089-
BuildGetArrowStreamOptions(psOptions, bPreserveFID));
4114+
const CPLStringList aosGetArrowStreamOptions(BuildGetArrowStreamOptions(
4115+
poSrcLayer, poDstLayer, psOptions, bPreserveFID));
40904116
if (poSrcLayer->GetArrowStream(streamSrc.get(),
40914117
aosGetArrowStreamOptions.List()))
40924118
{

autotest/utilities/test_ogr2ogr_lib.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2958,3 +2958,54 @@ def test_ogr2ogr_lib_explodecollections_empty_geoms(input_wkt, expected_output_w
29582958
out_lyr = out_ds.GetLayer(0)
29592959
f = out_lyr.GetNextFeature()
29602960
assert f.GetGeometryRef().ExportToIsoWkt() == expected_output_wkt
2961+
2962+
2963+
###############################################################################
2964+
2965+
2966+
@gdaltest.enable_exceptions()
2967+
@pytest.mark.require_driver("GPKG")
2968+
def test_ogr2ogr_lib_arrow_datetime_as_string(tmp_vsimem):
2969+
2970+
src_filename = str(tmp_vsimem / "src.gpkg")
2971+
with ogr.GetDriverByName("GPKG").CreateDataSource(src_filename) as src_ds:
2972+
src_lyr = src_ds.CreateLayer("test", geom_type=ogr.wkbNone)
2973+
2974+
field = ogr.FieldDefn("dt", ogr.OFTDateTime)
2975+
src_lyr.CreateField(field)
2976+
2977+
f = ogr.Feature(src_lyr.GetLayerDefn())
2978+
src_lyr.CreateFeature(f)
2979+
2980+
f = ogr.Feature(src_lyr.GetLayerDefn())
2981+
f.SetField("dt", "2022-05-31T12:34:56.789Z")
2982+
src_lyr.CreateFeature(f)
2983+
2984+
f = ogr.Feature(src_lyr.GetLayerDefn())
2985+
f.SetField("dt", "2022-05-31T12:34:56")
2986+
src_lyr.CreateFeature(f)
2987+
2988+
f = ogr.Feature(src_lyr.GetLayerDefn())
2989+
f.SetField("dt", "2022-05-31T12:34:56+12:30")
2990+
src_lyr.CreateFeature(f)
2991+
2992+
got_msg = []
2993+
2994+
def my_handler(errorClass, errno, msg):
2995+
got_msg.append(msg)
2996+
return
2997+
2998+
with gdaltest.error_handler(my_handler), gdaltest.config_options(
2999+
{"CPL_DEBUG": "ON", "OGR2OGR_USE_ARROW_API": "YES"}
3000+
):
3001+
dst_ds = gdal.VectorTranslate("", src_filename, format="Memory")
3002+
3003+
assert "OGR2OGR: Using WriteArrowBatch()" in got_msg
3004+
3005+
dst_lyr = dst_ds.GetLayer(0)
3006+
assert [f.GetField("dt") for f in dst_lyr] == [
3007+
None,
3008+
"2022/05/31 12:34:56.789+00",
3009+
"2022/05/31 12:34:56",
3010+
"2022/05/31 12:34:56+1230",
3011+
]

0 commit comments

Comments
 (0)