Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix time "shift" with time zone by converting it to UTC in CAST FORMAT #2388 #7835

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 48 additions & 7 deletions src/common/cvt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1745,14 +1745,32 @@ static void string_to_format_datetime_pattern_matcher(std::string_view pattern,
}
else if (pattern == "YY")
{
int year = parse_string_to_get_int(str, strLength, strOffset, 2);
outTimes.tm_year = (year > 45 ? 1900 + year : 2000 + year) - 1900;
tm currentTm;
TimeStamp::getCurrentTimeStamp().decode(&currentTm);
// Set 2 last digits to zero
int currentAge = (currentTm.tm_year + 1900) / 100 * 100;

outTimes.tm_year = parse_string_to_get_int(str, strLength, strOffset, 2);
outTimes.tm_year += outTimes.tm_year < (currentTm.tm_year + 1900 - 50) % 100
? currentAge
: currentAge - 100;

outTimes.tm_year -= 1900;
return;
}
else if (pattern == "YYY")
{
int year = parse_string_to_get_int(str, strLength, strOffset, 3);
outTimes.tm_year = (year > 450 ? 1000 + year : 2000 + year) - 1900;
tm currentTm;
TimeStamp::getCurrentTimeStamp().decode(&currentTm);
// Set 3 last digits to zero
int currentThousand = (currentTm.tm_year + 1900) / 1000 * 1000;

outTimes.tm_year = parse_string_to_get_int(str, strLength, strOffset, 3);
outTimes.tm_year += outTimes.tm_year < (currentTm.tm_year + 1900 - 500) % 1000
? currentThousand
: currentThousand - 1000;

outTimes.tm_year -= 1900;
return;
}
else if (pattern == "YYYY")
Expand Down Expand Up @@ -2020,7 +2038,8 @@ static void string_to_format_datetime_pattern_matcher(std::string_view pattern,
}


ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb)
ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb,
const EXPECT_DATETIME expectedType)
{
if (!DTYPE_IS_TEXT(desc->dsc_dtype))
cb->err(Arg::Gds(isc_invalid_data_type_for_date_format));
Expand Down Expand Up @@ -2080,6 +2099,9 @@ ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::
break;
}

if (stringOffset >= stringLength)
cb->err(Arg::Gds(isc_data_for_format_is_exhausted) << string(formatUpper.c_str() + formatOffset));

pattern = std::string_view(formatUpper.c_str() + formatOffset, i - formatOffset + 1);
bool isFound = false;
for (int j = 0; j < FB_NELEM(TO_STRING_PATTERNS); j++)
Expand Down Expand Up @@ -2119,16 +2141,35 @@ ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::
cb->err(Arg::Gds(isc_trailing_part_of_string) << string(stringUpper.c_str() + stringOffset));

ISC_TIMESTAMP_TZ timestampTZ;
timestampTZ.utc_timestamp = NoThrowTimeStamp::encode_timestamp(&times, fractions);

ISC_USHORT sessionTimeZone = cb->getSessionTimeZone();

if (timezoneOffsetInMinutes == uninitializedTimezoneOffsetValue && timezoneId == TimeZoneTrie::UninitializedTimezoneId)
timestampTZ.time_zone = cb->getSessionTimeZone();
timestampTZ.time_zone = sessionTimeZone;
else if (timezoneId != TimeZoneTrie::UninitializedTimezoneId)
timestampTZ.time_zone = timezoneId;
else
{
timestampTZ.time_zone = TimeZoneUtil::makeFromOffset(sign(timezoneOffsetInMinutes),
abs(timezoneOffsetInMinutes) / 60, abs(timezoneOffsetInMinutes) % 60);
}
timestampTZ.utc_timestamp = NoThrowTimeStamp::encode_timestamp(&times, fractions);

if (expectedType == expect_sql_time_tz || expectedType == expect_timestamp_tz || timestampTZ.time_zone != sessionTimeZone)
TimeZoneUtil::localTimeStampToUtc(timestampTZ);

if (timestampTZ.time_zone != sessionTimeZone)
{
if (expectedType == expect_sql_time)
{
ISC_TIME_TZ timeTz;
timeTz.utc_time = timestampTZ.utc_timestamp.timestamp_time;
timeTz.time_zone = timestampTZ.time_zone;
timestampTZ.utc_timestamp.timestamp_time = TimeZoneUtil::timeTzToTime(timeTz, cb);
}
else if (expectedType == expect_timestamp)
*(ISC_TIMESTAMP*) &timestampTZ = TimeZoneUtil::timeStampTzToTimeStamp(timestampTZ, sessionTimeZone);
}

return timestampTZ;
}
Expand Down
3 changes: 2 additions & 1 deletion src/common/cvt.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ void CVT_string_to_datetime(const dsc*, ISC_TIMESTAMP_TZ*, bool*, const Firebird
bool, Firebird::Callbacks*);
const UCHAR* CVT_get_bytes(const dsc*, unsigned&);
Firebird::string CVT_datetime_to_format_string(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb);
ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb);
ISC_TIMESTAMP_TZ CVT_string_to_format_datetime(const dsc* desc, const Firebird::string& format, Firebird::Callbacks* cb,
const Firebird::EXPECT_DATETIME expectedType);

#endif //COMMON_CVT_H
Loading
Loading