From 4295c29e9a12134a024fcd3e669c4f881064c2b3 Mon Sep 17 00:00:00 2001 From: MeanSquaredError <35379301+MeanSquaredError@users.noreply.github.com> Date: Mon, 24 Jul 2023 07:40:18 +0300 Subject: [PATCH] Fix serialization of PostgreSQL time data types (#504) * Use a non-UTC timezone when testing the PostgreSQL timezone support. * Fix serialization of time of day values for PostgreSQL * Fix serialization of PostgreSQL values for "timestamp with time zone" and "time with time zone" fields. --- include/sqlpp11/postgresql/prepared_statement.h | 10 ++++------ include/sqlpp11/postgresql/serializer.h | 7 +++++++ tests/postgresql/usage/TimeZone.cpp | 3 ++- tests/postgresql/usage/make_test_connection.h | 4 ++-- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/sqlpp11/postgresql/prepared_statement.h b/include/sqlpp11/postgresql/prepared_statement.h index ab5f1c14..4cd8d6f8 100644 --- a/include/sqlpp11/postgresql/prepared_statement.h +++ b/include/sqlpp11/postgresql/prepared_statement.h @@ -199,10 +199,9 @@ namespace sqlpp { const auto time = ::date::make_time(*value) ; - // Timezone handling - always treat the value as UTC. - // It is assumed that the database timezone is set to UTC, too. + // Timezone handling - always treat the local value as UTC. std::ostringstream os; - os << time; + os << time << "+00"; _handle->paramValues[index] = os.str(); if (_handle->debug()) { @@ -225,10 +224,9 @@ namespace sqlpp const auto time = ::date::make_time(::sqlpp::chrono::floor<::std::chrono::microseconds>(*value - dp)); const auto ymd = ::date::year_month_day{dp}; - // Timezone handling - always treat the value as UTC. - // It is assumed that the database timezone is set to UTC, too. + // Timezone handling - always treat the local value as UTC. std::ostringstream os; - os << ymd << ' ' << time; + os << ymd << ' ' << time << "+00"; _handle->paramValues[index] = os.str(); if (_handle->debug()) { diff --git a/include/sqlpp11/postgresql/serializer.h b/include/sqlpp11/postgresql/serializer.h index 57337098..e801e7c5 100644 --- a/include/sqlpp11/postgresql/serializer.h +++ b/include/sqlpp11/postgresql/serializer.h @@ -65,6 +65,13 @@ namespace sqlpp context << "TIMESTAMP WITH TIME ZONE '" << ymd << ' ' << time << "+00'"; return context; } + + template + postgresql::context_t& serialize(const time_of_day_operand& t, postgresql::context_t& context) + { + context << "TIME WITH TIME ZONE '" << ::date::make_time(t._t) << "+00'"; + return context; + } } #endif diff --git a/tests/postgresql/usage/TimeZone.cpp b/tests/postgresql/usage/TimeZone.cpp index dfa0383d..5ff2d7f9 100644 --- a/tests/postgresql/usage/TimeZone.cpp +++ b/tests/postgresql/usage/TimeZone.cpp @@ -131,7 +131,8 @@ int TimeZone(int, char*[]) { namespace sql = sqlpp::postgresql; - auto dbc = sql::make_test_connection(); + // We use a time zone with non-zero offset from UTC in order to catch serialization/parsing bugs + auto dbc = sql::make_test_connection("+1"); dbc.execute("DROP TABLE IF EXISTS tabdatetime;"); dbc.execute( diff --git a/tests/postgresql/usage/make_test_connection.h b/tests/postgresql/usage/make_test_connection.h index eb308316..81cf8f9a 100644 --- a/tests/postgresql/usage/make_test_connection.h +++ b/tests/postgresql/usage/make_test_connection.h @@ -51,7 +51,7 @@ namespace sqlpp } // Starts a connection and sets the time zone to UTC - inline ::sqlpp::postgresql::connection make_test_connection() + inline ::sqlpp::postgresql::connection make_test_connection(const std::string &tz = "UTC") { namespace sql = sqlpp::postgresql; @@ -69,7 +69,7 @@ namespace sqlpp throw; } - db.execute(R"(SET TIME ZONE 'UTC';)"); + db.execute("SET TIME ZONE " + tz + ";"); return db; }