From 90d85c9a778b3fb46561a9d71e005839dec8092b Mon Sep 17 00:00:00 2001 From: Alexey Arno Date: Fri, 3 Jul 2015 14:55:51 +0300 Subject: [PATCH] dbms: Server: Support for multiple time zones: development [#METR-15618] --- .../DB/Functions/FunctionsConversion.h | 143 ++++++++++-------- dbms/include/DB/Functions/FunctionsDateTime.h | 26 ++-- .../0_stateless/00189_time_zones.reference | 8 +- .../queries/0_stateless/00189_time_zones.sql | 4 +- libs/libcommon/src/DateLUT.cpp | 2 +- libs/libcommon/src/DateLUTImpl.cpp | 11 +- 6 files changed, 110 insertions(+), 84 deletions(-) diff --git a/dbms/include/DB/Functions/FunctionsConversion.h b/dbms/include/DB/Functions/FunctionsConversion.h index e8c466e2391..447a5489105 100644 --- a/dbms/include/DB/Functions/FunctionsConversion.h +++ b/dbms/include/DB/Functions/FunctionsConversion.h @@ -242,26 +242,34 @@ struct ConvertImpl } }; -time_t convert_time(time_t remote_time, DateLUTImpl & remote_date_lut, DateLUTImpl & local_date_lut) +namespace details { namespace { + +/** Пусть source_timestamp представляет дату и время в исходном часовом поясе соответствующем + * объекту from_date_lut. Эта функция возвращает timestamp представлящий те же дату и время + * в часовом поясе соответствующем объекту to_date_lut. + */ +time_t convertTimestamp(time_t source_timestamp, DateLUTImpl & from_date_lut, DateLUTImpl & to_date_lut) { - if (&remote_date_lut == &local_date_lut) - return remote_time; + if (&from_date_lut == &to_date_lut) + return source_timestamp; else { - const auto & values = remote_date_lut.getValues(remote_time); - return local_date_lut.makeDateTime(values.year, values.month, values.day_of_month, - remote_date_lut.toHourInaccurate(remote_time), - remote_date_lut.toMinuteInaccurate(remote_time), - remote_date_lut.toSecondInaccurate(remote_time)); + const auto & values = from_date_lut.getValues(source_timestamp); + return to_date_lut.makeDateTime(values.year, values.month, values.day_of_month, + from_date_lut.toHourInaccurate(source_timestamp), + from_date_lut.toMinuteInaccurate(source_timestamp), + from_date_lut.toSecondInaccurate(source_timestamp)); } } -struct DateTimeConverter +/** Функции для преобразования даты + времени в строку. + */ +struct DateTimeToStringConverter { - static void vector_vector(const typename ColumnVector::Container_t & vec_from, - const ColumnString::Chars_t & data, - const ColumnString::Offsets_t & offsets, - ColumnString & vec_to) + using FromFieldType = typename DataTypeDateTime::FieldType; + + static void vector_vector(const PODArray & vec_from, const ColumnString::Chars_t & data, + const ColumnString::Offsets_t & offsets, ColumnString & vec_to) { auto & local_date_lut = DateLUT::instance(); @@ -281,7 +289,7 @@ struct DateTimeConverter const std::string time_zone(reinterpret_cast(&data[prev_offset]), cur_offset - prev_offset - 1); auto & remote_date_lut = DateLUT::instance(time_zone); - auto ti = convert_time(vec_from[i], remote_date_lut, local_date_lut); + auto ti = convertTimestamp(vec_from[i], remote_date_lut, local_date_lut); formatImpl(ti, write_buffer); writeChar(0, write_buffer); offsets_to[i] = write_buffer.count(); @@ -291,8 +299,7 @@ struct DateTimeConverter data_to.resize(write_buffer.count()); } - static void vector_constant(const typename ColumnVector::Container_t & vec_from, - const std::string & data, + static void vector_constant(const PODArray & vec_from, const std::string & data, ColumnString & vec_to) { auto & local_date_lut = DateLUT::instance(); @@ -308,7 +315,7 @@ struct DateTimeConverter for (size_t i = 0; i < size; ++i) { - auto ti = convert_time(vec_from[i], remote_date_lut, local_date_lut); + auto ti = convertTimestamp(vec_from[i], remote_date_lut, local_date_lut); formatImpl(ti, write_buffer); writeChar(0, write_buffer); offsets_to[i] = write_buffer.count(); @@ -316,7 +323,7 @@ struct DateTimeConverter data_to.resize(write_buffer.count()); } - static void constant_vector(DataTypeDateTime::FieldType from, const ColumnString::Chars_t & data, + static void constant_vector(FromFieldType from, const ColumnString::Chars_t & data, const ColumnString::Offsets_t & offsets, ColumnString & vec_to) { @@ -338,7 +345,7 @@ struct DateTimeConverter const std::string time_zone(reinterpret_cast(&data[prev_offset]), cur_offset - prev_offset - 1); auto & remote_date_lut = DateLUT::instance(time_zone); - auto ti = convert_time(from, remote_date_lut, local_date_lut); + auto ti = convertTimestamp(from, remote_date_lut, local_date_lut); formatImpl(ti, write_buffer); writeChar(0, write_buffer); offsets_to[i] = write_buffer.count(); @@ -348,29 +355,32 @@ struct DateTimeConverter data_to.resize(write_buffer.count()); } - static void constant_constant(DataTypeDateTime::FieldType from, const std::string & data, std::string & to) + static void constant_constant(FromFieldType from, const std::string & data, std::string & to) { auto & local_date_lut = DateLUT::instance(); auto & remote_date_lut = DateLUT::instance(data); std::vector buf; WriteBufferFromVector > write_buffer(buf); - auto ti = convert_time(from, remote_date_lut, local_date_lut); + auto ti = convertTimestamp(from, remote_date_lut, local_date_lut); formatImpl(ti, write_buffer); to = std::string(&buf[0], write_buffer.count()); } }; +}} + template struct ConvertImpl { - typedef typename DataTypeDateTime::FieldType FromFieldType; + using Op = details::DateTimeToStringConverter; + using FromFieldType = Op::FromFieldType; static void execute(Block & block, const ColumnNumbers & arguments, size_t result) { const ColumnPtr source_col = block.getByPosition(arguments[0]).column; - const ColumnVector * sources = typeid_cast *>(&*source_col); - const ColumnConst * const_source = typeid_cast *>(&*source_col); + const auto * sources = typeid_cast *>(&*source_col); + const auto * const_source = typeid_cast *>(&*source_col); if (arguments.size() == 1) { @@ -382,12 +392,12 @@ struct ConvertImpl auto & vec_from = sources->getData(); auto & vec_to = *col_to; - DateTimeConverter::vector_constant(vec_from, "", vec_to); + Op::vector_constant(vec_from, "", vec_to); } else if (const_source) { std::string res; - DateTimeConverter::constant_constant(const_source->getData(), "", res); + Op::constant_constant(const_source->getData(), "", res); block.getByPosition(result).column = new ColumnConstString(const_source->size(), res); } else @@ -400,8 +410,8 @@ struct ConvertImpl else if (arguments.size() == 2) { const ColumnPtr time_zone_col = block.getByPosition(arguments[1]).column; - const ColumnString * time_zones = typeid_cast(&*time_zone_col); - const ColumnConstString * const_time_zone = typeid_cast(&*time_zone_col); + const auto * time_zones = typeid_cast(&*time_zone_col); + const auto * const_time_zone = typeid_cast(&*time_zone_col); if (sources) { @@ -412,9 +422,9 @@ struct ConvertImpl auto & vec_to = *col_to; if (time_zones) - DateTimeConverter::vector_vector(vec_from, time_zones->getChars(), time_zones->getOffsets(), vec_to); + Op::vector_vector(vec_from, time_zones->getChars(), time_zones->getOffsets(), vec_to); else if (const_time_zone) - DateTimeConverter::vector_constant(vec_from, const_time_zone->getData(), vec_to); + Op::vector_constant(vec_from, const_time_zone->getData(), vec_to); else throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName() + " of second argument of function " + Name::name, @@ -428,12 +438,12 @@ struct ConvertImpl block.getByPosition(result).column = col_to; auto & vec_to = *col_to; - DateTimeConverter::constant_vector(const_source->getData(), time_zones->getChars(), time_zones->getOffsets(), vec_to); + Op::constant_vector(const_source->getData(), time_zones->getChars(), time_zones->getOffsets(), vec_to); } else if (const_time_zone) { std::string res; - DateTimeConverter::constant_constant(const_source->getData(), const_time_zone->getData(), res); + Op::constant_constant(const_source->getData(), const_time_zone->getData(), res); block.getByPosition(result).column = new ColumnConstString(const_source->size(), res); } else @@ -446,6 +456,8 @@ struct ConvertImpl + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); } + else + throw Exception("Internal error.", ErrorCodes::LOGICAL_ERROR); } }; @@ -510,11 +522,16 @@ struct ConvertImpl } }; -struct TimeConverter +namespace details { namespace { + +/** Функции для преобразования строк в timestamp. + */ +struct StringToTimestampConverter { + using ToFieldType = typename DataTypeInt32::FieldType; + static void vector_vector(const ColumnString::Chars_t & vec_from, const ColumnString::Chars_t & data, - const ColumnString::Offsets_t & offsets, - typename ColumnVector::Container_t & vec_to) + const ColumnString::Offsets_t & offsets, PODArray & vec_to) { auto & local_date_lut = DateLUT::instance(); ReadBuffer read_buffer(const_cast(reinterpret_cast(&vec_from[0])), vec_from.size(), 0); @@ -531,7 +548,7 @@ struct TimeConverter const std::string time_zone(reinterpret_cast(&data[prev_offset]), cur_offset - prev_offset - 1); auto & remote_date_lut = DateLUT::instance(time_zone); - auto ti = convert_time(x, local_date_lut, remote_date_lut); + auto ti = convertTimestamp(x, local_date_lut, remote_date_lut); vec_to[i] = ti; readChar(zero, read_buffer); @@ -543,7 +560,7 @@ struct TimeConverter } static void vector_constant(const ColumnString::Chars_t & vec_from, const std::string & data, - typename ColumnVector::Container_t & vec_to) + PODArray & vec_to) { auto & local_date_lut = DateLUT::instance(); auto & remote_date_lut = DateLUT::instance(data); @@ -555,7 +572,7 @@ struct TimeConverter DataTypeDateTime::FieldType x = 0; parseImpl(x, read_buffer); - auto ti = convert_time(x, local_date_lut, remote_date_lut); + auto ti = convertTimestamp(x, local_date_lut, remote_date_lut); vec_to[i] = ti; readChar(zero, read_buffer); @@ -565,8 +582,7 @@ struct TimeConverter } static void constant_vector(const std::string & from, const ColumnString::Chars_t & data, - const ColumnString::Offsets_t & offsets, - typename ColumnVector::Container_t & vec_to) + const ColumnString::Offsets_t & offsets, PODArray & vec_to) { auto & local_date_lut = DateLUT::instance(); @@ -582,14 +598,14 @@ struct TimeConverter const std::string time_zone(reinterpret_cast(&data[prev_offset]), cur_offset - prev_offset - 1); auto & remote_date_lut = DateLUT::instance(time_zone); - auto ti = convert_time(x, local_date_lut, remote_date_lut); + auto ti = convertTimestamp(x, local_date_lut, remote_date_lut); vec_to[i] = ti; prev_offset = cur_offset; } } - static void constant_constant(const std::string & from, const std::string & data, DataTypeInt32::FieldType & to) + static void constant_constant(const std::string & from, const std::string & data, ToFieldType & to) { auto & local_date_lut = DateLUT::instance(); auto & remote_date_lut = DateLUT::instance(data); @@ -598,28 +614,31 @@ struct TimeConverter DataTypeDateTime::FieldType x = 0; parseImpl(x, read_buffer); - to = convert_time(x, local_date_lut, remote_date_lut); + to = convertTimestamp(x, local_date_lut, remote_date_lut); } }; +}} + struct NameToUnixTimestamp { static constexpr auto name = "toUnixTimestamp"; }; template<> struct ConvertImpl { - typedef typename DataTypeInt32::FieldType ToFieldType; + using Op = details::StringToTimestampConverter; + using ToFieldType = Op::ToFieldType; static void execute(Block & block, const ColumnNumbers & arguments, size_t result) { const ColumnPtr source_col = block.getByPosition(arguments[0]).column; - const ColumnString * sources = typeid_cast(&*source_col); - const ColumnConstString * const_source = typeid_cast(&*source_col); + const auto * sources = typeid_cast(&*source_col); + const auto * const_source = typeid_cast(&*source_col); if (arguments.size() == 1) { if (sources) { - ColumnVector * col_to = new ColumnVector; + auto * col_to = new ColumnVector; block.getByPosition(result).column = col_to; auto & vec_from = sources->getChars(); @@ -627,13 +646,13 @@ struct ConvertImpl size_t size = sources->size(); vec_to.resize(size); - TimeConverter::vector_constant(vec_from, "", vec_to); + Op::vector_constant(vec_from, "", vec_to); } else if (const_source) { - DataTypeInt32::FieldType res; - TimeConverter::constant_constant(const_source->getData(), "", res); - block.getByPosition(result).column = new ColumnConst(const_source->size(), res); + ToFieldType res; + Op::constant_constant(const_source->getData(), "", res); + block.getByPosition(result).column = new ColumnConst(const_source->size(), res); } else { @@ -645,12 +664,12 @@ struct ConvertImpl else if (arguments.size() == 2) { const ColumnPtr time_zone_col = block.getByPosition(arguments[1]).column; - const ColumnString * time_zones = typeid_cast(&*time_zone_col); - const ColumnConstString * const_time_zone = typeid_cast(&*time_zone_col); + const auto * time_zones = typeid_cast(&*time_zone_col); + const auto * const_time_zone = typeid_cast(&*time_zone_col); if (sources) { - ColumnVector * col_to = new ColumnVector; + auto * col_to = new ColumnVector; block.getByPosition(result).column = col_to; auto & vec_from = sources->getChars(); @@ -659,9 +678,9 @@ struct ConvertImpl vec_to.resize(size); if (time_zones) - TimeConverter::vector_vector(vec_from, time_zones->getChars(), time_zones->getOffsets(), vec_to); + Op::vector_vector(vec_from, time_zones->getChars(), time_zones->getOffsets(), vec_to); else if (const_time_zone) - TimeConverter::vector_constant(vec_from, const_time_zone->getData(), vec_to); + Op::vector_constant(vec_from, const_time_zone->getData(), vec_to); else throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName() + " of second argument of function " + NameToUnixTimestamp::name, @@ -671,19 +690,19 @@ struct ConvertImpl { if (time_zones) { - ColumnVector * col_to = new ColumnVector; + auto * col_to = new ColumnVector; block.getByPosition(result).column = col_to; auto & vec_to = col_to->getData(); vec_to.resize(time_zones->getOffsets().size()); - TimeConverter::constant_vector(const_source->getData(), time_zones->getChars(), time_zones->getOffsets(), vec_to); + Op::constant_vector(const_source->getData(), time_zones->getChars(), time_zones->getOffsets(), vec_to); } else if (const_time_zone) { - DataTypeInt32::FieldType res; - TimeConverter::constant_constant(const_source->getData(), const_time_zone->getData(), res); - block.getByPosition(result).column = new ColumnConst(const_source->size(), res); + ToFieldType res; + Op::constant_constant(const_source->getData(), const_time_zone->getData(), res); + block.getByPosition(result).column = new ColumnConst(const_source->size(), res); } else throw Exception("Illegal column " + block.getByPosition(arguments[1]).column->getName() @@ -695,6 +714,8 @@ struct ConvertImpl + " of first argument of function " + NameToUnixTimestamp::name, ErrorCodes::ILLEGAL_COLUMN); } + else + throw Exception("Internal error.", ErrorCodes::LOGICAL_ERROR); } }; diff --git a/dbms/include/DB/Functions/FunctionsDateTime.h b/dbms/include/DB/Functions/FunctionsDateTime.h index eb4076f94b2..8e104c6729d 100644 --- a/dbms/include/DB/Functions/FunctionsDateTime.h +++ b/dbms/include/DB/Functions/FunctionsDateTime.h @@ -232,8 +232,8 @@ struct ToRelativeSecondNumImpl template struct Transformer { - static void vector_vector(const typename ColumnVector::Container_t & vec_from, const ColumnString::Chars_t & data, - const ColumnString::Offsets_t & offsets, typename ColumnVector::Container_t & vec_to) + static void vector_vector(const PODArray & vec_from, const ColumnString::Chars_t & data, + const ColumnString::Offsets_t & offsets, PODArray & vec_to) { auto & local_date_lut = DateLUT::instance(); ColumnString::Offset_t prev_offset = 0; @@ -248,8 +248,8 @@ struct Transformer } } - static void vector_constant(const typename ColumnVector::Container_t & vec_from, const std::string & data, - typename ColumnVector::Container_t & vec_to) + static void vector_constant(const PODArray & vec_from, const std::string & data, + PODArray & vec_to) { auto & local_date_lut = DateLUT::instance(); auto & remote_date_lut = DateLUT::instance(data); @@ -258,7 +258,7 @@ struct Transformer } static void constant_vector(const FromType & from, const ColumnString::Chars_t & data, - const ColumnString::Offsets_t & offsets, typename ColumnVector::Container_t & vec_to) + const ColumnString::Offsets_t & offsets, PODArray & vec_to) { auto & local_date_lut = DateLUT::instance(); ColumnString::Offset_t prev_offset = 0; @@ -289,14 +289,14 @@ struct DateTimeTransformImpl using Op = Transformer; const ColumnPtr source_col = block.getByPosition(arguments[0]).column; - const ColumnVector * sources = typeid_cast *>(&*source_col); - const ColumnConst * const_source = typeid_cast *>(&*source_col); + const auto * sources = typeid_cast *>(&*source_col); + const auto * const_source = typeid_cast *>(&*source_col); if (arguments.size() == 1) { if (sources) { - ColumnVector * col_to = new ColumnVector; + auto * col_to = new ColumnVector; block.getByPosition(result).column = col_to; auto & vec_from = sources->getData(); @@ -322,12 +322,12 @@ struct DateTimeTransformImpl else if (arguments.size() == 2) { const ColumnPtr time_zone_col = block.getByPosition(arguments[1]).column; - const ColumnString * time_zones = typeid_cast(&*time_zone_col); - const ColumnConstString * const_time_zone = typeid_cast(&*time_zone_col); + const auto * time_zones = typeid_cast(&*time_zone_col); + const auto * const_time_zone = typeid_cast(&*time_zone_col); if (sources) { - ColumnVector * col_to = new ColumnVector; + auto * col_to = new ColumnVector; block.getByPosition(result).column = col_to; auto & vec_from = sources->getData(); @@ -347,7 +347,7 @@ struct DateTimeTransformImpl { if (time_zones) { - ColumnVector * col_to = new ColumnVector; + auto * col_to = new ColumnVector; block.getByPosition(result).column = col_to; auto & vec_to = col_to->getData(); @@ -371,6 +371,8 @@ struct DateTimeTransformImpl + " of first argument of function " + Name::name, ErrorCodes::ILLEGAL_COLUMN); } + else + throw Exception("Internal error.", ErrorCodes::LOGICAL_ERROR); } }; diff --git a/dbms/tests/queries/0_stateless/00189_time_zones.reference b/dbms/tests/queries/0_stateless/00189_time_zones.reference index 32c941f69ff..f1d2ea9c2a7 100644 --- a/dbms/tests/queries/0_stateless/00189_time_zones.reference +++ b/dbms/tests/queries/0_stateless/00189_time_zones.reference @@ -23,11 +23,11 @@ 1970-01-02 09:00:00 1970-01-02 10:00:00 1970-01-02 18:00:00 1970-01-02 18:00:00 1970-01-02 01:30:00 1970-01-02 01:30:00 -2014-09-29 2014-09-01 2014-07-01 1970-01-02 21:50:00 +2015-07-13 2015-07-01 2015-07-01 1970-01-02 19:30:00 2014-12-22 2014-12-01 2014-10-01 1970-01-02 21:00:00 2014-12-29 2015-01-01 2015-01-01 1970-01-02 12:00:00 +2014-09-29 2014-09-01 2014-07-01 1970-01-02 21:50:00 2015-03-09 2015-03-01 2015-01-01 1970-01-02 02:00:00 -2015-07-13 2015-07-01 2015-07-01 1970-01-02 19:30:00 2014-09-29 2014-09-01 2014-10-01 1970-01-02 11:20:00 2014-12-22 2014-12-01 2014-10-01 1970-01-02 13:30:00 2014-12-29 2015-01-01 2015-01-01 1970-01-02 01:30:00 @@ -68,11 +68,11 @@ 1426415400 1426415400 1426415400 -1412113800 +1436934600 1419811200 1420102800 +1412113800 1426455000 -1436934600 1426393800 1426426200 1426415400 diff --git a/dbms/tests/queries/0_stateless/00189_time_zones.sql b/dbms/tests/queries/0_stateless/00189_time_zones.sql index a2ea41b195e..fef2ef11c6b 100644 --- a/dbms/tests/queries/0_stateless/00189_time_zones.sql +++ b/dbms/tests/queries/0_stateless/00189_time_zones.sql @@ -54,7 +54,7 @@ INSERT INTO foo(x, y) VALUES(1419800400, 'Europe/London'); INSERT INTO foo(x, y) VALUES(1436956200, 'Asia/Tokyo'); INSERT INTO foo(x, y) VALUES(1426415400, 'Pacific/Pitcairn'); -SELECT toMonday(toDateTime(x), y), toStartOfMonth(toDateTime(x), y), toStartOfQuarter(toDateTime(x), y), toTime(toDateTime(x), y) FROM foo ORDER BY x ASC; +SELECT toMonday(toDateTime(x), y), toStartOfMonth(toDateTime(x), y), toStartOfQuarter(toDateTime(x), y), toTime(toDateTime(x), y) FROM foo ORDER BY y ASC; SELECT toMonday(toDateTime(x), 'Europe/Paris'), toStartOfMonth(toDateTime(x), 'Europe/London'), toStartOfQuarter(toDateTime(x), 'Asia/Tokyo'), toTime(toDateTime(x), 'Pacific/Pitcairn') FROM foo ORDER BY x ASC; SELECT toMonday(toDateTime(1426415400), y), toStartOfMonth(toDateTime(1426415400), y), toStartOfQuarter(toDateTime(1426415400), y), toTime(toDateTime(1426415400), y) FROM foo ORDER BY y ASC; @@ -84,6 +84,6 @@ SELECT toUnixTimestamp(toString(toDateTime(1426415400), 'Europe/London'), 'Europ SELECT toUnixTimestamp(toString(toDateTime(1426415400), 'Asia/Tokyo'), 'Asia/Tokyo'); SELECT toUnixTimestamp(toString(toDateTime(1426415400), 'Pacific/Pitcairn'), 'Pacific/Pitcairn'); -SELECT toUnixTimestamp(toString(toDateTime(x)), y) FROM foo ORDER BY x ASC; +SELECT toUnixTimestamp(toString(toDateTime(x)), y) FROM foo ORDER BY y ASC; SELECT toUnixTimestamp(toString(toDateTime(1426415400)), y) FROM foo ORDER BY y ASC; SELECT toUnixTimestamp(toString(toDateTime(x)), 'Europe/Paris') FROM foo ORDER BY x ASC; diff --git a/libs/libcommon/src/DateLUT.cpp b/libs/libcommon/src/DateLUT.cpp index 4094223c583..f9596b47fdb 100644 --- a/libs/libcommon/src/DateLUT.cpp +++ b/libs/libcommon/src/DateLUT.cpp @@ -12,7 +12,7 @@ DateLUT::DateLUT() std::unique_ptr tz(TimeZone::createDefault()); if (tz == nullptr) - throw Poco::Exception("Failed to query the host time zone."); + throw Poco::Exception("Failed to determine the host time zone."); UnicodeString u_out; tz->getID(u_out); diff --git a/libs/libcommon/src/DateLUTImpl.cpp b/libs/libcommon/src/DateLUTImpl.cpp index 1045845dd7b..9b40cebea3b 100644 --- a/libs/libcommon/src/DateLUTImpl.cpp +++ b/libs/libcommon/src/DateLUTImpl.cpp @@ -72,12 +72,15 @@ GDateTimePtr toNextDay(const GTimeZonePtr & p_tz, const GDateTimePtr & p_dt) dt = g_date_time_add_days(dt, 1); if (dt == nullptr) - throw Poco::Exception("Null pointer"); + throw Poco::Exception("Failed to create GDateTime object."); + + GDateTimePtr p_next_dt = GDateTimePtr(dt); + GDateTime * next_dt = p_next_dt.get(); dt = g_date_time_new(p_tz.get(), - g_date_time_get_year(dt), - g_date_time_get_month(dt), - g_date_time_get_day_of_month(dt), + g_date_time_get_year(next_dt), + g_date_time_get_month(next_dt), + g_date_time_get_day_of_month(next_dt), 0, 0, 0); if (dt == nullptr) throw Poco::Exception("Failed to create GDateTime object.");