@@ -498,6 +498,7 @@ SQLRETURN BindParameters(SQLHANDLE hStmt, const py::list& params,
498498 dtoPtr->hour = static_cast <SQLUSMALLINT>(param.attr (" hour" ).cast <int >());
499499 dtoPtr->minute = static_cast <SQLUSMALLINT>(param.attr (" minute" ).cast <int >());
500500 dtoPtr->second = static_cast <SQLUSMALLINT>(param.attr (" second" ).cast <int >());
501+ // SQL server supports in ns, but python datetime supports in µs
501502 dtoPtr->fraction = static_cast <SQLUINTEGER>(param.attr (" microsecond" ).cast <int >() * 1000 );
502503
503504 py::object utcoffset = tzinfo.attr (" utcoffset" )(param);
@@ -1947,7 +1948,6 @@ SQLRETURN BindParameterArray(SQLHANDLE hStmt,
19471948 break ;
19481949 }
19491950 case SQL_C_TYPE_TIMESTAMP: {
1950- std::cout<<" Binding Timestamp param at index " <<paramIndex<<std::endl;
19511951 SQL_TIMESTAMP_STRUCT* tsArray = AllocateParamBufferArray<SQL_TIMESTAMP_STRUCT>(tempBuffers, paramSetSize);
19521952 strLenOrIndArray = AllocateParamBufferArray<SQLLEN>(tempBuffers, paramSetSize);
19531953 for (size_t i = 0 ; i < paramSetSize; ++i) {
@@ -1971,7 +1971,6 @@ SQLRETURN BindParameterArray(SQLHANDLE hStmt,
19711971 break ;
19721972 }
19731973 case SQL_C_SS_TIMESTAMPOFFSET: {
1974- std::cout<<" Binding DateTimeOffset param at index " <<paramIndex<<std::endl;
19751974 DateTimeOffset* dtoArray = AllocateParamBufferArray<DateTimeOffset>(tempBuffers, paramSetSize);
19761975 strLenOrIndArray = AllocateParamBufferArray<SQLLEN>(tempBuffers, paramSetSize);
19771976
@@ -1994,39 +1993,26 @@ SQLRETURN BindParameterArray(SQLHANDLE hStmt,
19941993 std::to_string (paramIndex));
19951994 }
19961995
1997- // Convert the Python datetime object to UTC before binding.
1998- // This is the crucial step to ensure timezone normalization.
1999- py::object datetimeModule = py::module_::import (" datetime" );
2000- py::object utc_dt = param.attr (" astimezone" )(datetimeModule.attr (" timezone" ).attr (" utc" ));
2001- std::cout<<" !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" <<std::endl;
2002- // --- TEMPORARY DEBUGGING: LOG THE UTC VALUES ---
2003- LOG (" Binding UTC values: {}-{}-{} {}:{}:{}.{} +00:00" ,
2004- utc_dt.attr (" year" ).cast <int >(),
2005- utc_dt.attr (" month" ).cast <int >(),
2006- utc_dt.attr (" day" ).cast <int >(),
2007- utc_dt.attr (" hour" ).cast <int >(),
2008- utc_dt.attr (" minute" ).cast <int >(),
2009- utc_dt.attr (" second" ).cast <int >(),
2010- utc_dt.attr (" microsecond" ).cast <int >()
2011- );
2012-
2013- // Now, populate the C++ struct using the UTC-converted object.
2014- dtoArray[i].year = static_cast <SQLSMALLINT>(utc_dt.attr (" year" ).cast <int >());
2015- dtoArray[i].month = static_cast <SQLUSMALLINT>(utc_dt.attr (" month" ).cast <int >());
2016- dtoArray[i].day = static_cast <SQLUSMALLINT>(utc_dt.attr (" day" ).cast <int >());
2017- dtoArray[i].hour = static_cast <SQLUSMALLINT>(utc_dt.attr (" hour" ).cast <int >());
2018- dtoArray[i].minute = static_cast <SQLUSMALLINT>(utc_dt.attr (" minute" ).cast <int >());
2019- dtoArray[i].second = static_cast <SQLUSMALLINT>(utc_dt.attr (" second" ).cast <int >());
2020- dtoArray[i].fraction = static_cast <SQLUINTEGER>(utc_dt.attr (" microsecond" ).cast <int >() * 1000 );
2021-
2022- // Since we've converted to UTC, the timezone offset is always 0.
2023- dtoArray[i].timezone_hour = 0 ;
2024- dtoArray[i].timezone_minute = 0 ;
1996+ // Populate the C++ struct directly from the Python datetime object.
1997+ dtoArray[i].year = static_cast <SQLSMALLINT>(param.attr (" year" ).cast <int >());
1998+ dtoArray[i].month = static_cast <SQLUSMALLINT>(param.attr (" month" ).cast <int >());
1999+ dtoArray[i].day = static_cast <SQLUSMALLINT>(param.attr (" day" ).cast <int >());
2000+ dtoArray[i].hour = static_cast <SQLUSMALLINT>(param.attr (" hour" ).cast <int >());
2001+ dtoArray[i].minute = static_cast <SQLUSMALLINT>(param.attr (" minute" ).cast <int >());
2002+ dtoArray[i].second = static_cast <SQLUSMALLINT>(param.attr (" second" ).cast <int >());
2003+ // SQL server supports in ns, but python datetime supports in µs
2004+ dtoArray[i].fraction = static_cast <SQLUINTEGER>(param.attr (" microsecond" ).cast <int >() * 1000 );
2005+
2006+ // Compute and preserve the original UTC offset.
2007+ py::object utcoffset = tzinfo.attr (" utcoffset" )(param);
2008+ int total_seconds = static_cast <int >(utcoffset.attr (" total_seconds" )().cast <double >());
2009+ std::div_t div_result = std::div (total_seconds, 3600 );
2010+ dtoArray[i].timezone_hour = static_cast <SQLSMALLINT>(div_result.quot );
2011+ dtoArray[i].timezone_minute = static_cast <SQLSMALLINT>(div (div_result.rem , 60 ).quot );
20252012
20262013 strLenOrIndArray[i] = sizeof (DateTimeOffset);
20272014 }
20282015 }
2029-
20302016 dataPtr = dtoArray;
20312017 bufferLength = sizeof (DateTimeOffset);
20322018 break ;
0 commit comments