diff --git a/src/core/providers/ogr/qgsogrprovider.cpp b/src/core/providers/ogr/qgsogrprovider.cpp index d8e4df969413..dafce60ba407 100644 --- a/src/core/providers/ogr/qgsogrprovider.cpp +++ b/src/core/providers/ogr/qgsogrprovider.cpp @@ -1615,10 +1615,12 @@ bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f, Flags flags, QgsFeatureId } case OFTDateTime: { - const QDateTime dt = attrVal.toDateTime(); + QDateTime dt = attrVal.toDateTime(); if ( dt.isValid() ) { ok = true; + if ( mConvertLocalTimeToUTC && dt.timeSpec() == Qt::LocalTime ) + dt = dt.toUTC(); const QDate date = dt.date(); const QTime time = dt.time(); OGR_F_SetFieldDateTimeEx( feature.get(), ogrAttributeId, @@ -2577,10 +2579,12 @@ bool QgsOgrProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_ } case OFTDateTime: { - const QDateTime dt = it2->toDateTime(); + QDateTime dt = it2->toDateTime(); if ( dt.isValid() ) { ok = true; + if ( mConvertLocalTimeToUTC && dt.timeSpec() == Qt::LocalTime ) + dt = dt.toUTC(); const QDate date = dt.date(); const QTime time = dt.time(); OGR_F_SetFieldDateTimeEx( of.get(), f, @@ -4013,6 +4017,11 @@ void QgsOgrProvider::open( OpenMode mode ) mGDALDriverName = mOgrOrigLayer->driverName(); mShareSameDatasetAmongLayers = QgsOgrProviderUtils::canDriverShareSameDatasetAmongLayers( mGDALDriverName ); + // Should we set it to true unconditionally? as OGR doesn't do any time + // zone conversion for local time. For now, only do that for GeoPackage + // since it requires UTC. + mConvertLocalTimeToUTC = ( mGDALDriverName == QLatin1String( "GPKG" ) ); + QgsDebugMsgLevel( "OGR opened using Driver " + mGDALDriverName, 2 ); mOgrLayer = mOgrOrigLayer.get(); diff --git a/src/core/providers/ogr/qgsogrprovider.h b/src/core/providers/ogr/qgsogrprovider.h index 3d880ea1e407..21756f72171f 100644 --- a/src/core/providers/ogr/qgsogrprovider.h +++ b/src/core/providers/ogr/qgsogrprovider.h @@ -349,6 +349,9 @@ class QgsOgrProvider final: public QgsVectorDataProvider void invalidateNetworkCache(); bool mShapefileHadSpatialIndex = false; + + //! Whether to convert Qt DateTime with local time to UTC + bool mConvertLocalTimeToUTC = false; }; ///@endcond diff --git a/tests/src/python/test_provider_ogr_gpkg.py b/tests/src/python/test_provider_ogr_gpkg.py index 14fdb0c96ad7..30af4c59111c 100644 --- a/tests/src/python/test_provider_ogr_gpkg.py +++ b/tests/src/python/test_provider_ogr_gpkg.py @@ -2715,6 +2715,34 @@ def testDateTimeTimeZoneMilliseconds(self): got = [feat for feat in vl.getFeatures()] self.assertEqual(got[0]["dt"], new_dt) + def testWriteDateTimeFromLocalTime(self): + + tmpfile = os.path.join(self.basetestpath, 'testWriteDateTimeFromLocalTime.gpkg') + ds = ogr.GetDriverByName('GPKG').CreateDataSource(tmpfile) + lyr = ds.CreateLayer('test', geom_type=ogr.wkbNone) + lyr.CreateField(ogr.FieldDefn('dt', ogr.OFTDateTime)) + ds = None + + vl = QgsVectorLayer(tmpfile, 'test', 'ogr') + + f = QgsFeature(vl.fields()) + dt = QDateTime(QDate(2023, 1, 28), QTime(12, 34, 56, 789), Qt.TimeSpec.LocalTime) + f.setAttribute(1, dt) + self.assertTrue(vl.startEditing()) + self.assertTrue(vl.addFeatures([f])) + self.assertTrue(vl.commitChanges()) + + got = [feat for feat in vl.getFeatures()] + self.assertEqual(got[0]["dt"], dt.toUTC()) + + self.assertTrue(vl.startEditing()) + dt = QDateTime(QDate(2024, 1, 1), QTime(12, 34, 56, 789), Qt.TimeSpec.LocalTime) + self.assertTrue(vl.changeAttributeValue(1, 1, dt)) + self.assertTrue(vl.commitChanges()) + + got = [feat for feat in vl.getFeatures()] + self.assertEqual(got[0]["dt"], dt.toUTC()) + def testTransactionModeAutoWithFilter(self): temp_dir = QTemporaryDir()