@@ -287,8 +287,13 @@ py::dict DuckDBPyResult::FetchNumpyInternal(bool stream, idx_t vectors_per_chunk
287287 return res;
288288}
289289
290+ static void ReplaceDFColumn (PandasDataFrame &df, const char *col_name, idx_t idx, const py::handle &new_value) {
291+ df.attr (" drop" )(" columns" _a = col_name, " inplace" _a = true );
292+ df.attr (" insert" )(idx, col_name, new_value, " allow_duplicates" _a = false );
293+ }
294+
290295// TODO: unify these with an enum/flag to indicate which conversions to do
291- void DuckDBPyResult::ChangeToTZType (PandasDataFrame &df) {
296+ void DuckDBPyResult::ConvertDateTimeTypes (PandasDataFrame &df, bool date_as_object) const {
292297 auto names = df.attr (" columns" ).cast <vector<string>>();
293298
294299 for (idx_t i = 0 ; i < result->ColumnCount (); i++) {
@@ -297,8 +302,10 @@ void DuckDBPyResult::ChangeToTZType(PandasDataFrame &df) {
297302 auto utc_local = df[names[i].c_str ()].attr (" dt" ).attr (" tz_localize" )(" UTC" );
298303 auto new_value = utc_local.attr (" dt" ).attr (" tz_convert" )(result->client_properties .time_zone );
299304 // We need to create the column anew because the exact dt changed to a new timezone
300- df.attr (" drop" )(" columns" _a = names[i].c_str (), " inplace" _a = true );
301- df.attr (" __setitem__" )(names[i].c_str (), new_value);
305+ ReplaceDFColumn (df, names[i].c_str (), i, new_value);
306+ } else if (date_as_object && result->types [i] == LogicalType::DATE) {
307+ auto new_value = df[names[i].c_str ()].attr (" dt" ).attr (" date" );
308+ ReplaceDFColumn (df, names[i].c_str (), i, new_value);
302309 }
303310 }
304311}
@@ -374,20 +381,11 @@ PandasDataFrame DuckDBPyResult::FrameFromNumpy(bool date_as_object, const py::ha
374381 }
375382
376383 PandasDataFrame df = py::cast<PandasDataFrame>(pandas.attr (" DataFrame" ).attr (" from_dict" )(o));
377- // Unfortunately we have to do a type change here for timezones since these types are not supported by numpy
378- ChangeToTZType (df);
384+ // Convert TZ and (optionally) Date types
385+ ConvertDateTimeTypes (df, date_as_object );
379386
380387 auto names = df.attr (" columns" ).cast <vector<string>>();
381388 D_ASSERT (result->ColumnCount () == names.size ());
382- if (date_as_object) {
383- for (idx_t i = 0 ; i < result->ColumnCount (); i++) {
384- if (result->types [i] == LogicalType::DATE) {
385- auto new_value = df[names[i].c_str ()].attr (" dt" ).attr (" date" );
386- df.attr (" drop" )(" columns" _a = names[i].c_str (), " inplace" _a = true );
387- df.attr (" __setitem__" )(names[i].c_str (), new_value);
388- }
389- }
390- }
391389 return df;
392390}
393391
0 commit comments