This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.2
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.2 by this push:
new b9de0dc4e6d branch-4.2: [fix](function) Align timezone offset parsing
across FE and BE #68979 (#70137)
b9de0dc4e6d is described below
commit b9de0dc4e6d974230f8d8c17db933c9afe215395
Author: morrySnow <[email protected]>
AuthorDate: Wed Nov 4 08:37:39 2026 +0800
branch-4.2: [fix](function) Align timezone offset parsing across FE and BE
#68979 (#70137)
picked from master #68979
Co-authored-by: Mryange <[email protected]>
---
.../function/cast/cast_to_datetimev2_impl.hpp | 39 +-
be/src/util/timezone_utils.cpp | 35 +-
be/src/util/timezone_utils.h | 3 +
be/test/util/timezone_utils_test.cpp | 27 +
.../org/apache/doris/common/util/TimeUtils.java | 43 +-
.../apache/doris/common/util/TimeZoneParser.java | 118 ++
.../executable/DateTimeExtractAndTransform.java | 38 +-
.../trees/expressions/literal/DateLiteral.java | 31 +-
.../trees/expressions/literal/DateTimeLiteral.java | 6 +-
.../expressions/literal/StringLikeLiteral.java | 24 -
.../literal/format/DateTimeChecker.java | 17 +-
.../doris/common/util/TimeZoneParserTest.java | 124 ++
.../literal/TimeStampNsLiteralTest.java | 2 +
.../datetimev2/test_timezone_parser_contract.out | 1504 ++++++++++++++++++++
.../test_timezone_parser_contract.groovy | 129 ++
.../fold_constant/fe_constant_cast_to_date.groovy | 2 +-
.../fe_constant_cast_to_datetime.groovy | 2 +-
17 files changed, 2011 insertions(+), 133 deletions(-)
diff --git a/be/src/exprs/function/cast/cast_to_datetimev2_impl.hpp
b/be/src/exprs/function/cast/cast_to_datetimev2_impl.hpp
index 2885e64b0c9..32a7ed948ef 100644
--- a/be/src/exprs/function/cast/cast_to_datetimev2_impl.hpp
+++ b/be/src/exprs/function/cast/cast_to_datetimev2_impl.hpp
@@ -706,7 +706,7 @@ FRAC:
"invalid hour offset '{}'",
std::string {ptr, end});
}
SET_PARAMS_RET_FALSE_IFN(
- part[0] < (type == DataTimeCastEnumType::TIMESTAMP_TZ ?
24U : 15U),
+ part[0] < (type == DataTimeCastEnumType::TIMESTAMP_TZ ?
19U : 15U),
"invalid hour offset '{}'", part[0]);
if (ptr < end) {
if (*ptr == ':') {
@@ -732,20 +732,19 @@ FRAC:
"invalid minute offset '{}'",
part[1]);
}
}
- if constexpr (type == DataTimeCastEnumType::TIMESTAMP_TZ) {
- // Wire offsets include historical zones outside the session
fixed-zone range.
- // Use the exact offset even when it has no seconds (for
example, Guam's -14:21).
- const auto offset = static_cast<int>(part[0] * 3600 + part[1]
* 60 + second_offset);
- parsed_tz = cctz::fixed_time_zone(cctz::seconds(sign == '-' ?
-offset : offset));
- } else {
+ if constexpr (type == DataTimeCastEnumType::DATE_TIME) {
SET_PARAMS_RET_FALSE_IFN(part[0] != 14 || part[1] == 0,
"invalid timezone offset '{}'",
combine_tz_offset(sign, part[0],
part[1]));
- SET_PARAMS_RET_FALSE_IFN(
- TimezoneUtils::find_cctz_time_zone(
- combine_tz_offset(sign, part[0], part[1]),
parsed_tz),
- "invalid timezone offset '{}'",
combine_tz_offset(sign, part[0], part[1]));
}
+ if constexpr (type == DataTimeCastEnumType::TIMESTAMP_TZ) {
+ SET_PARAMS_RET_FALSE_IFN(part[0] != 18 || (part[1] == 0 &&
second_offset == 0),
+ "invalid timezone offset '{}'",
+ combine_tz_offset(sign, part[0],
part[1]));
+ }
+ const auto offset = static_cast<int>(part[0] * 3600 + part[1] * 60
+ second_offset);
+ parsed_tz =
+ TimezoneUtils::create_fixed_offset_time_zone(sign == '-' ?
-offset : offset);
} else {
// timezone name
const auto* start = ptr;
@@ -992,7 +991,7 @@ inline bool
CastToDatetimeV2::from_string_non_strict_mode_internal(
PROPAGATE_FALSE((consume_digit<UInt32, 2>(ptr, end,
hour_offset)));
}
SET_PARAMS_RET_FALSE_IFN(
- hour_offset < (type == DataTimeCastEnumType::TIMESTAMP_TZ
? 24U : 15U),
+ hour_offset < (type == DataTimeCastEnumType::TIMESTAMP_TZ
? 19U : 15U),
"invalid hour offset '{}'", hour_offset);
if (ptr < end) {
if (*ptr == ':') {
@@ -1015,21 +1014,21 @@ inline bool
CastToDatetimeV2::from_string_non_strict_mode_internal(
"invalid minute offset {}", minute_offset);
}
}
- if constexpr (type == DataTimeCastEnumType::TIMESTAMP_TZ) {
- // Match strict parsing: a serialized historical offset is not
a session setting.
- const auto offset =
- static_cast<int>(hour_offset * 3600 + minute_offset *
60 + second_offset);
- parsed_tz = cctz::fixed_time_zone(cctz::seconds(sign == '-' ?
-offset : offset));
- } else {
+ if constexpr (type == DataTimeCastEnumType::DATE_TIME) {
SET_PARAMS_RET_FALSE_IFN(hour_offset != 14 || minute_offset ==
0,
"invalid timezone offset '{}'",
combine_tz_offset(sign, hour_offset,
minute_offset));
+ }
+ if constexpr (type == DataTimeCastEnumType::TIMESTAMP_TZ) {
SET_PARAMS_RET_FALSE_IFN(
- TimezoneUtils::find_cctz_time_zone(
- combine_tz_offset(sign, hour_offset,
minute_offset), parsed_tz),
+ hour_offset != 18 || (minute_offset == 0 &&
second_offset == 0),
"invalid timezone offset '{}'",
combine_tz_offset(sign, hour_offset, minute_offset));
}
+ const auto offset =
+ static_cast<int>(hour_offset * 3600 + minute_offset * 60 +
second_offset);
+ parsed_tz =
+ TimezoneUtils::create_fixed_offset_time_zone(sign == '-' ?
-offset : offset);
} else {
// timezone name
const auto* start = ptr;
diff --git a/be/src/util/timezone_utils.cpp b/be/src/util/timezone_utils.cpp
index 0a11c185445..04a98204326 100644
--- a/be/src/util/timezone_utils.cpp
+++ b/be/src/util/timezone_utils.cpp
@@ -51,17 +51,27 @@ namespace fs = std::filesystem;
namespace doris {
using ZoneList = std::unordered_map<std::string, cctz::time_zone>;
+using FixedZoneList = std::unordered_map<int32_t, cctz::time_zone>;
RE2 time_zone_offset_format_reg(R"(^[+-]{1}\d{2}\:\d{2}$)"); // visiting is
thread-safe
// for ut, make it never nullptr.
std::unique_ptr<ZoneList> lower_zone_cache_ = std::make_unique<ZoneList>();
+std::unique_ptr<FixedZoneList> fixed_zone_cache_ =
std::make_unique<FixedZoneList>();
const std::string TimezoneUtils::default_time_zone = "+08:00";
static const char* tzdir = "/usr/share/zoneinfo"; // default value, may change
by TZDIR env var
+cctz::time_zone TimezoneUtils::create_fixed_offset_time_zone(int32_t
offset_seconds) {
+ if (auto it = fixed_zone_cache_->find(offset_seconds); it !=
fixed_zone_cache_->end()) {
+ return it->second;
+ }
+ return cctz::fixed_time_zone(cctz::seconds(offset_seconds));
+}
+
void TimezoneUtils::clear_timezone_caches() {
lower_zone_cache_->clear();
+ fixed_zone_cache_->clear();
}
size_t TimezoneUtils::cache_size() {
return lower_zone_cache_->size();
@@ -131,28 +141,33 @@ void TimezoneUtils::load_offsets_to_cache() {
static constexpr int supported_minutes[] = {0, 30, 45};
for (int hour = -12; hour <= +14; hour++) {
for (int minute : supported_minutes) {
+ if ((hour == -12 || hour == 14) && minute != 0) {
+ continue;
+ }
char min_str[3];
snprintf(min_str, sizeof(min_str), "%02d", minute);
std::string offset_str = (hour >= 0 ? "+" : "") +
to_hour_string(hour) + ':' + min_str;
cctz::time_zone result;
- // Rejected endpoint minutes must not be cached as the default UTC
zone.
- if (!parse_tz_offset_string(offset_str, result)) {
- continue;
- }
+ CHECK(parse_tz_offset_string(offset_str, result));
lower_zone_cache_->emplace(offset_str, result);
+ const int offset_seconds = hour * 3600 + (hour < 0 ? -minute :
minute) * 60;
+ fixed_zone_cache_->emplace(offset_seconds, result);
}
}
// -00 for hour is also valid
std::string offset_str = "-00:00";
cctz::time_zone result;
- parse_tz_offset_string(offset_str, result);
+ CHECK(parse_tz_offset_string(offset_str, result));
lower_zone_cache_->emplace(offset_str, result);
+ fixed_zone_cache_->emplace(0, result);
offset_str = "-00:30";
- parse_tz_offset_string(offset_str, result);
+ CHECK(parse_tz_offset_string(offset_str, result));
lower_zone_cache_->emplace(offset_str, result);
+ fixed_zone_cache_->emplace(-30 * 60, result);
offset_str = "-00:45";
- parse_tz_offset_string(offset_str, result);
+ CHECK(parse_tz_offset_string(offset_str, result));
lower_zone_cache_->emplace(offset_str, result);
+ fixed_zone_cache_->emplace(-45 * 60, result);
}
bool TimezoneUtils::find_cctz_time_zone(const std::string& timezone,
cctz::time_zone& ctz) {
@@ -233,8 +248,8 @@ static bool normalize_offset_string(const std::string&
timezone, bool allow_hour
hour = std::stoi(std::string(rest));
}
- // Session fixed offsets include the endpoints only when their minutes are
zero.
- if (minute >= 60 || hour * 60 + minute > (positive ? 14 : 12) * 60) {
+ const int limit = positive ? 14 : 12;
+ if (hour > limit || (hour == limit && minute != 0) || minute >= 60) {
return false;
}
@@ -283,7 +298,7 @@ bool TimezoneUtils::parse_tz_offset_string(const
std::string& timezone, cctz::ti
const int minute = std::stoi(value.substr(4, 2).as_string());
int offset = hour * 60 * 60 + minute * 60;
offset *= positive ? 1 : -1;
- ctz = cctz::fixed_time_zone(cctz::seconds(offset));
+ ctz = create_fixed_offset_time_zone(offset);
return true;
}
return false;
diff --git a/be/src/util/timezone_utils.h b/be/src/util/timezone_utils.h
index 1f37c7e2e9e..99fcf9b2afa 100644
--- a/be/src/util/timezone_utils.h
+++ b/be/src/util/timezone_utils.h
@@ -37,6 +37,9 @@ public:
static bool find_cctz_time_zone(const std::string& timezone,
cctz::time_zone& ctz);
+ // The caller validates the offset according to its parsing policy.
+ static cctz::time_zone create_fixed_offset_time_zone(int32_t
offset_seconds);
+
static bool try_get_fixed_offset_seconds(const cctz::time_zone& timezone,
int32_t* offset_seconds);
diff --git a/be/test/util/timezone_utils_test.cpp
b/be/test/util/timezone_utils_test.cpp
index e2c29203342..6983f74a907 100644
--- a/be/test/util/timezone_utils_test.cpp
+++ b/be/test/util/timezone_utils_test.cpp
@@ -183,6 +183,33 @@ TEST(TimezoneUtilsTest, FindTimezone) {
EXPECT_FALSE(TimezoneUtils::find_cctz_time_zone(tzname, result));
}
+TEST(TimezoneUtilsTest, OffsetBoundariesWithAndWithoutCache) {
+ for (bool preload : {false, true}) {
+ TimezoneUtils::clear_timezone_caches();
+ if (preload) {
+ TimezoneUtils::load_timezones_to_cache();
+ }
+ for (const auto* prefix : {"", "UTC", "GMT", "utc", "gmt"}) {
+ for (const auto* offset : {"+14:01", "+14:30", "+14:45", "-12:01",
"-12:30", "-12:45",
+ "+15:00", "-13:00", "+08:60"}) {
+ const std::string input = std::string(prefix) + offset;
+ cctz::time_zone result =
cctz::fixed_time_zone(cctz::seconds(3600));
+ EXPECT_FALSE(TimezoneUtils::find_cctz_time_zone(input,
result)) << input;
+ EXPECT_EQ(
+ result.lookup(cctz::convert(cctz::civil_second(2024,
1, 1), result)).offset,
+ 3600)
+ << input;
+ }
+ for (const auto* offset : {"+14:00", "-12:00", "+08:01", "+08:15",
"-00:30"}) {
+ cctz::time_zone result;
+ EXPECT_TRUE(
+ TimezoneUtils::find_cctz_time_zone(std::string(prefix)
+ offset, result));
+ }
+ }
+ }
+ TimezoneUtils::load_timezones_to_cache();
+}
+
TEST(TimezoneUtilsTest, TryGetFixedOffsetSeconds) {
TimezoneUtils::load_timezones_to_cache();
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java
index c808c17b52a..c59623bfe4e 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeUtils.java
@@ -48,7 +48,6 @@ import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;
-import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -108,7 +107,6 @@ public class TimeUtils {
}
private static final Logger LOG = LogManager.getLogger(TimeUtils.class);
- private static final Pattern TIMEZONE_OFFSET_FORMAT_REG =
Pattern.compile("^[+-]?\\d{1,2}:\\d{2}$");
static {
Map<String, String> timeZoneMap = new
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
@@ -329,42 +327,18 @@ public class TimeUtils {
// Check if the time zone_value is valid
public static String checkTimeZoneValidAndStandardize(String value) throws
DdlException {
- Function<String, String> standardizeValue = s -> {
- boolean positive = s.charAt(0) != '-';
- String[] parts = s.replaceAll("[+-]", "").split(":");
- return (positive ? "+" : "-") + String.format("%02d:%02d",
- Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
- };
-
try {
- if (value == null) {
-
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_TIME_ZONE, "null");
- }
- // match offset type, such as +08:00, -07:00
- Matcher matcher = TIMEZONE_OFFSET_FORMAT_REG.matcher(value);
- // it supports offset and region timezone type, and short zone ids
- boolean match = matcher.matches();
- if (!value.contains("/") && !timeZoneAliasMap.containsKey(value)
&& !match) {
- if ((value.startsWith("GMT") || value.startsWith("UTC"))
- &&
TIMEZONE_OFFSET_FORMAT_REG.matcher(value.substring(3)).matches()) {
- value = value.substring(0, 3) +
standardizeValue.apply(value.substring(3));
- } else {
-
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_TIME_ZONE, value);
- }
+ String input = value;
+ if (input != null && !input.isEmpty() &&
Character.isDigit(input.charAt(0))) {
+ input = "+" + input;
}
- if (match) {
- value = standardizeValue.apply(value);
-
- // timezone offsets around the world extended from -12:00 to
+14:00
- int tz = Integer.parseInt(value.substring(1, 3)) * 100 +
Integer.parseInt(value.substring(4, 6));
- if (value.charAt(0) == '-' && tz > 1200) {
-
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_TIME_ZONE, value);
- } else if (value.charAt(0) == '+' && tz > 1400) {
-
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_TIME_ZONE, value);
+ String normalized = TimeZoneParser.normalize(input,
TimeZoneParser.Usage.SESSION);
+ for (String alias : timeZoneAliasMap.keySet()) {
+ if (alias.equalsIgnoreCase(value)) {
+ return alias;
}
}
- ZoneId.of(value, timeZoneAliasMap);
- return value;
+ return normalized;
} catch (DateTimeException ex) {
ErrorReport.reportDdlException(ErrorCode.ERR_UNKNOWN_TIME_ZONE,
value);
}
@@ -433,4 +407,3 @@ public class TimeUtils {
return convertToDateV2(dateTime.getYear(), dateTime.getMonthValue(),
dateTime.getDayOfMonth());
}
}
-
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeZoneParser.java
b/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeZoneParser.java
new file mode 100644
index 00000000000..4e17490522e
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/TimeZoneParser.java
@@ -0,0 +1,118 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.common.util;
+
+import java.time.DateTimeException;
+import java.time.ZoneId;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Doris timezone syntax, independent of the Java timezone database's input
grammar. */
+public final class TimeZoneParser {
+ public enum Usage {
+ SESSION, DATETIME, TIMESTAMPTZ
+ }
+
+ private static final Pattern OFFSET =
Pattern.compile("^([+-])([0-9]{1,2})(?::([0-9]{2}))?$");
+ private static final Pattern TEXT_OFFSET = Pattern.compile(
+ "^([+-])([0-9]{1,2})(?::?([0-9]{2}))?(?::([0-9]{2}))?$");
+ private static final Map<String, String> REGION_NAMES;
+
+ static {
+ Map<String, String> names = new HashMap<>();
+ for (String region : ZoneId.getAvailableZoneIds()) {
+ names.put(region.toLowerCase(Locale.ROOT), region);
+ }
+ REGION_NAMES = Collections.unmodifiableMap(names);
+ }
+
+ private TimeZoneParser() {
+ }
+
+ public static String normalize(String value, Usage usage) {
+ if (value == null || value.isEmpty()) {
+ throw new DateTimeException("Empty timezone");
+ }
+ String name = findAlias(value);
+ if (name != null) {
+ return name;
+ }
+ String region = findRegion(value, usage);
+ if (region != null) {
+ return region;
+ }
+ String upper = value.toUpperCase(Locale.ROOT);
+ // Java's standard UTC names are not present in SHORT_IDS.
+ if (upper.equals("UT") || upper.equals("Z")) {
+ return "UTC";
+ }
+ boolean prefixed = upper.startsWith("UTC") || upper.startsWith("GMT");
+ String offset = prefixed ? value.substring(3) : value;
+ Matcher matcher = (usage == Usage.SESSION || prefixed ? OFFSET :
TEXT_OFFSET).matcher(offset);
+ if (!matcher.matches()
+ || (usage == Usage.SESSION && !prefixed && matcher.group(3) ==
null)) {
+ throw new DateTimeException("Invalid timezone: " + value);
+ }
+ boolean negative = "-".equals(matcher.group(1));
+ int hour = Integer.parseInt(matcher.group(2));
+ int minute = matcher.group(3) == null ? 0 :
Integer.parseInt(matcher.group(3));
+ int second = !prefixed && usage != Usage.SESSION && matcher.group(4)
!= null
+ ? Integer.parseInt(matcher.group(4)) : 0;
+ // Prefixed offsets have the same contract as session offsets in BE.
+ Usage policy = prefixed ? Usage.SESSION : usage;
+ int limit = policy == Usage.SESSION ? (negative ? 12 : 14)
+ : policy == Usage.DATETIME ? 14 : 18;
+ if (hour > limit || minute >= 60 || second >= 60
+ || (policy != Usage.TIMESTAMPTZ && hour == limit && minute !=
0)
+ || (policy == Usage.TIMESTAMPTZ && hour == limit && (minute !=
0 || second != 0))
+ || (policy == Usage.DATETIME
+ && (matcher.group(4) != null || (minute != 0 && minute
!= 30 && minute != 45)))) {
+ throw new DateTimeException("Invalid timezone offset: " + value);
+ }
+ String normalized = String.format(Locale.ROOT, "%s%02d:%02d", negative
? "-" : "+", hour, minute);
+ if (second != 0) {
+ normalized += String.format(Locale.ROOT, ":%02d", second);
+ }
+ return prefixed ? upper.substring(0, 3) + normalized : normalized;
+ }
+
+ private static String findAlias(String value) {
+ for (String alias : TimeUtils.timeZoneAliasMap.keySet()) {
+ if (alias.equalsIgnoreCase(value)) {
+ return TimeUtils.getCanonicalTimeZone(alias);
+ }
+ }
+ return null;
+ }
+
+ private static String findRegion(String value, Usage usage) {
+ String region = REGION_NAMES.get(value.toLowerCase(Locale.ROOT));
+ if (usage == Usage.SESSION && !value.equals(region)) {
+ return null;
+ }
+ return region;
+ }
+
+ public static ZoneId parse(String value, Usage usage) {
+ return ZoneId.of(normalize(value, usage));
+ }
+}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
index 7a1e2a32f6e..001a15f509d 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeExtractAndTransform.java
@@ -17,6 +17,7 @@
package org.apache.doris.nereids.trees.expressions.functions.executable;
+import org.apache.doris.common.util.TimeZoneParser;
import org.apache.doris.nereids.exceptions.AnalysisException;
import
org.apache.doris.nereids.rules.expression.rules.SupportJavaDateFormatter;
import org.apache.doris.nereids.trees.expressions.ExecFunction;
@@ -67,9 +68,7 @@ import java.time.YearMonth;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
-import java.time.format.ResolverStyle;
import java.time.format.TextStyle;
import java.time.temporal.ChronoUnit;
import java.time.temporal.WeekFields;
@@ -1102,44 +1101,13 @@ public class DateTimeExtractAndTransform {
private static LocalDateTime convertTz(LocalDateTime datetime,
StringLikeLiteral fromTz,
StringLikeLiteral toTz) {
- // Validate timezone offset ranges before parsing
- validateTimezoneOffset(fromTz.getStringValue());
- validateTimezoneOffset(toTz.getStringValue());
-
- DateTimeFormatter zoneFormatter = new DateTimeFormatterBuilder()
- .parseCaseInsensitive()
- .appendZoneOrOffsetId()
- .toFormatter()
- .withResolverStyle(ResolverStyle.STRICT);
- ZoneId fromZone =
ZoneId.from(zoneFormatter.parse(fromTz.getStringValue()));
- ZoneId toZone =
ZoneId.from(zoneFormatter.parse(toTz.getStringValue()));
+ ZoneId fromZone = TimeZoneParser.parse(fromTz.getStringValue(),
TimeZoneParser.Usage.SESSION);
+ ZoneId toZone = TimeZoneParser.parse(toTz.getStringValue(),
TimeZoneParser.Usage.SESSION);
Instant instant = DateTimeLiteral.convertLocalToInstant(datetime,
fromZone);
return LocalDateTime.ofInstant(instant, toZone);
}
- private static void validateTimezoneOffset(String timezone) {
- // Pattern to match offset format like +HH:MM or -HH:MM
- if (timezone.matches("^[+-]\\d{2}:\\d{2}$")) {
- boolean positive = timezone.charAt(0) == '+';
- int hour = Integer.parseInt(timezone.substring(1, 3));
- int minute = Integer.parseInt(timezone.substring(4, 6));
-
- if (!positive && hour > 12) {
- throw new AnalysisException("Invalid timezone offset: " +
timezone
- + ". Timezone offsets must be between -12:00 and
+14:00");
- } else if (positive && hour > 14) {
- throw new AnalysisException("Invalid timezone offset: " +
timezone
- + ". Timezone offsets must be between -12:00 and
+14:00");
- }
-
- if (minute != 0 && minute != 15 && minute != 30 && minute != 45) {
- throw new AnalysisException("Invalid timezone offset: " +
timezone
- + ". Minute part should be 00, 15, 30, or 45");
- }
- }
- }
-
@ExecFunction(name = "weekday")
public static Expression weekDay(DateV2Literal date) {
return new TinyIntLiteral((byte)
((date.toJavaDateType().getDayOfWeek().getValue() + 6) % 7));
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
index 08f43907d46..4ae683c042c 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
@@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.expressions.literal;
import org.apache.doris.analysis.LiteralExpr;
import org.apache.doris.catalog.Type;
+import org.apache.doris.common.util.TimeZoneParser;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.exceptions.CastException;
import org.apache.doris.nereids.trees.expressions.Expression;
@@ -155,6 +156,11 @@ public class DateLiteral extends Literal implements
ComparableLiteral {
}
private static Result<String, AnalysisException> normalize(String s, int
maxFractionDigits) {
+ return normalize(s, maxFractionDigits, TimeZoneParser.Usage.DATETIME);
+ }
+
+ private static Result<String, AnalysisException> normalize(String s, int
maxFractionDigits,
+ TimeZoneParser.Usage usage) {
// merge consecutive space
if (s.contains(" ")) {
s = s.replaceAll(" +", " ");
@@ -276,7 +282,10 @@ public class DateLiteral extends Literal implements
ComparableLiteral {
}
// trim use to remove any blank before zone id or zone offset
- sb.append(s.substring(i).trim());
+ String zone = s.substring(i).trim();
+ if (!zone.isEmpty()) {
+ sb.append(TimeZoneParser.normalize(zone, usage));
+ }
return Result.ok(sb.toString());
}
@@ -304,10 +313,15 @@ public class DateLiteral extends Literal implements
ComparableLiteral {
/** parseDateTime */
public static Result<TemporalAccessor, AnalysisException>
parseDateTime(String s) {
- return parseDateTime(s, 7);
+ return parseDateTime(s, 7, TimeZoneParser.Usage.DATETIME);
}
static Result<TemporalAccessor, AnalysisException> parseDateTime(String s,
int maxFractionDigits) {
+ return parseDateTime(s, maxFractionDigits,
TimeZoneParser.Usage.DATETIME);
+ }
+
+ static Result<TemporalAccessor, AnalysisException> parseDateTime(String s,
int maxFractionDigits,
+ TimeZoneParser.Usage usage) {
String originalString = s;
try {
// fast parse '2022-01-01'
@@ -340,13 +354,22 @@ public class DateLiteral extends Literal implements
ComparableLiteral {
}
if (!containsPunctuation) {
s = normalizeBasic(s);
+ boolean hasTimeSeparator = s.length() > 8 && s.charAt(8) ==
'T';
+ int zoneStart = 0;
+ while (zoneStart < s.length() &&
(Character.isDigit(s.charAt(zoneStart))
+ || (hasTimeSeparator && zoneStart == 8) ||
s.charAt(zoneStart) == '.')) {
+ zoneStart++;
+ }
+ if (zoneStart < s.length() && s.charAt(zoneStart) != ' ') {
+ s = s.substring(0, zoneStart) +
TimeZoneParser.normalize(s.substring(zoneStart), usage);
+ }
boolean parseNanoseconds = maxFractionDigits > 7;
if (parseNanoseconds) {
s = DateUtils.truncateFractionalSecondForJavaParser(s);
}
// mysql reject "20200219 010101" "200219 010101", can't use '
' spilt basic date time.
- if (!s.contains("T")) {
+ if (!hasTimeSeparator) {
dateTime = (parseNanoseconds
?
DateTimeFormatterUtils.TIMESTAMP_NS_BASIC_FORMATTER_WITHOUT_T
:
DateTimeFormatterUtils.BASIC_FORMATTER_WITHOUT_T).parse(s);
@@ -358,7 +381,7 @@ public class DateLiteral extends Literal implements
ComparableLiteral {
return Result.ok(dateTime);
}
- Result<String, AnalysisException> normalizeResult = normalize(s,
maxFractionDigits);
+ Result<String, AnalysisException> normalizeResult = normalize(s,
maxFractionDigits, usage);
if (normalizeResult.isError()) {
return normalizeResult.cast();
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
index 4819de8e608..1b1a7aaf73e 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
@@ -19,6 +19,7 @@ package org.apache.doris.nereids.trees.expressions.literal;
import org.apache.doris.analysis.LiteralExpr;
import org.apache.doris.catalog.Type;
+import org.apache.doris.common.util.TimeZoneParser;
import org.apache.doris.nereids.exceptions.AnalysisException;
import org.apache.doris.nereids.exceptions.CastException;
import org.apache.doris.nereids.trees.expressions.Expression;
@@ -222,7 +223,10 @@ public class DateTimeLiteral extends DateLiteral {
}
protected void init(String s) throws AnalysisException {
- TemporalAccessor temporal = parseDateTime(s).get();
+ TemporalAccessor temporal = parseDateTime(s, 7,
+ this.dataType instanceof TimeStampTzType
+ ? TimeZoneParser.Usage.TIMESTAMPTZ
+ : TimeZoneParser.Usage.DATETIME).get();
year = DateUtils.getOrDefault(temporal, ChronoField.YEAR);
month = DateUtils.getOrDefault(temporal, ChronoField.MONTH_OF_YEAR);
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
index 3ea2506e487..b37e3baf920 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/StringLikeLiteral.java
@@ -303,9 +303,6 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
? strictMatcher.group("fraction2") :
strictMatcher.group("fraction1");
tz = strictMatcher.group("tz");
}
- if (tz != null && tz.equalsIgnoreCase("CST")) {
- tz = "+08:00";
- }
return getDateTimeLiteral(year, month, date, hour, minute, second,
fraction, tz, targetType);
} else if (!strictCast) {
Matcher unStrictMatcher = dateUnStrictPattern.matcher(value);
@@ -318,9 +315,6 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
second = unStrictMatcher.group("second");
fraction = unStrictMatcher.group("fraction");
tz = unStrictMatcher.group("tz");
- if (tz != null && tz.equalsIgnoreCase("CST")) {
- tz = "+08:00";
- }
return getDateTimeLiteral(year, month, date, hour, minute,
second, fraction, tz, targetType);
}
}
@@ -339,17 +333,6 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
String second, String fraction, String tz, DataType targetType) {
String year4 = year2ToYear4(year);
tz = tz == null ? "" : tz;
- if ((tz.startsWith("+") || tz.startsWith("-")) && !tz.contains(":")) {
- if (tz.length() == 2) {
- tz = String.format("%s0%s:00", tz.charAt(0), tz.charAt(1));
- } else if (tz.length() == 3) {
- tz = String.format("%s%s:00", tz.charAt(0), tz.substring(1,
3));
- } else if (tz.length() == 4) {
- tz = String.format("%s0%s:%s", tz.charAt(0), tz.charAt(1),
tz.substring(2, 4));
- } else {
- tz = String.format("%s%s:%s", tz.charAt(0), tz.substring(1,
3), tz.substring(3, 5));
- }
- }
hour = hour == null ? "00" : hour;
minute = minute == null ? "00" : minute;
second = second == null ? "00" : second;
@@ -357,13 +340,6 @@ public abstract class StringLikeLiteral extends Literal
implements ComparableLit
if (fraction.endsWith(".")) {
fraction = fraction.substring(0, fraction.length() - 1);
}
- if (tz.contains(":")) {
- int hourOffset = Integer.parseInt(tz.substring(1,
tz.indexOf(":")));
- int minuteOffset = Integer.parseInt(tz.substring(tz.indexOf(":") +
1));
- if (hourOffset > 14 || hourOffset == 14 && minuteOffset > 0) {
- throw new CastException("Time zone offset couldn't be larger
than 14:00");
- }
- }
String format = String.format("%s-%s-%sT%s:%s:%s%s%s", year4, month,
date, hour, minute, second, fraction, tz);
if (targetType.isDateType()) {
try {
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DateTimeChecker.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DateTimeChecker.java
index 6336c746491..b8247bff98a 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DateTimeChecker.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/format/DateTimeChecker.java
@@ -109,7 +109,8 @@ public class DateTimeChecker extends FormatChecker {
// Find the separator between date and time parts (' ' or 'T')
int timeSeparatorIndex = -1;
for (int i = 0; i < str.length(); i++) {
- if (str.charAt(i) == ' ' || str.charAt(i) == 'T') {
+ // A date ends within the first ten characters; later 'T' belongs
to a zone name.
+ if (str.charAt(i) == ' ' || (str.charAt(i) == 'T' && i <= 10)) {
timeSeparatorIndex = i;
break;
}
@@ -160,6 +161,18 @@ public class DateTimeChecker extends FormatChecker {
}
private FormatChecker timeZone() {
+ return or(namedTimeZone(), offsetTimeZone());
+ }
+
+ private FormatChecker namedTimeZone() {
+ return and(
+ atLeast(1, Character::isLetter),
+ atLeast(0, c -> Character.isLetterOrDigit(c) || c == '/' || c
== '_'
+ || c == '-' || c == '+')
+ );
+ }
+
+ private FormatChecker offsetTimeZone() {
// Z or +08:00 or UTC-01:00
return and(
// timezone: Europe/London, America/New_York
@@ -167,7 +180,7 @@ public class DateTimeChecker extends FormatChecker {
option(
and(
chars(c -> c == '+' || c == '-'),
- digit(1, 2),
+ digit(1, 4),
option(
and(
ch(':'),
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/common/util/TimeZoneParserTest.java
b/fe/fe-core/src/test/java/org/apache/doris/common/util/TimeZoneParserTest.java
new file mode 100644
index 00000000000..91d58c3dd36
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/common/util/TimeZoneParserTest.java
@@ -0,0 +1,124 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.common.util;
+
+import org.apache.doris.common.DdlException;
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
+import org.apache.doris.nereids.trees.expressions.literal.TimestampTzLiteral;
+import
org.apache.doris.nereids.trees.expressions.literal.format.DateTimeChecker;
+import org.apache.doris.nereids.types.TimeStampTzType;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.time.DateTimeException;
+
+class TimeZoneParserTest {
+ @Test
+ void sessionBoundaries() {
+ for (String prefix : new String[] {"", "UTC", "GMT", "utc", "gmt"}) {
+ for (String offset : new String[] {"+14:01", "+14:30", "+14:45",
"-12:01", "-12:30",
+ "-12:45", "+15:00", "-13:00", "+08:60"}) {
+ Assertions.assertThrows(DateTimeException.class,
+ () -> TimeZoneParser.parse(prefix + offset,
TimeZoneParser.Usage.SESSION), prefix + offset);
+ }
+ for (String offset : new String[] {"+14:00", "-12:00", "+08:01",
"+08:15", "-00:30"}) {
+ Assertions.assertNotNull(TimeZoneParser.parse(prefix + offset,
TimeZoneParser.Usage.SESSION));
+ }
+ }
+ }
+
+ @Test
+ void offsetSyntaxCannotBypassValidation() {
+ for (TimeZoneParser.Usage usage : TimeZoneParser.Usage.values()) {
+ for (String value : new String[] {"UTC8", "GMT8:30", "UTC0",
"GMT0:00"}) {
+ Assertions.assertThrows(DateTimeException.class,
+ () -> TimeZoneParser.normalize(value, usage), usage +
": " + value);
+ }
+ }
+ for (String value : new String[] {"+00:00:00", "-00:00:00", "+0000",
"+00"}) {
+ Assertions.assertThrows(DateTimeException.class,
+ () -> TimeZoneParser.normalize(value,
TimeZoneParser.Usage.SESSION), value);
+ }
+ Assertions.assertThrows(DateTimeException.class,
+ () -> TimeZoneParser.normalize("+00:00:00",
TimeZoneParser.Usage.DATETIME));
+ Assertions.assertEquals("+00:00",
+ TimeZoneParser.normalize("+00:00:00",
TimeZoneParser.Usage.TIMESTAMPTZ));
+ for (String value : new String[] {"UT", "ut", "Z", "z"}) {
+ Assertions.assertEquals("UTC", TimeZoneParser.normalize(value,
TimeZoneParser.Usage.DATETIME));
+ }
+ }
+
+ @Test
+ void namesAndSyntax() throws Exception {
+ Assertions.assertEquals("UTC",
TimeUtils.checkTimeZoneValidAndStandardize("utc"));
+ Assertions.assertThrows(DdlException.class,
+ () ->
TimeUtils.checkTimeZoneValidAndStandardize("asia/shanghai"));
+ for (TimeZoneParser.Usage usage : new TimeZoneParser.Usage[] {
+ TimeZoneParser.Usage.DATETIME,
TimeZoneParser.Usage.TIMESTAMPTZ}) {
+ Assertions.assertEquals("Asia/Shanghai",
TimeZoneParser.normalize("asia/shanghai", usage));
+ Assertions.assertEquals("America/Los_Angeles",
TimeZoneParser.normalize("america/los_angeLES", usage));
+ Assertions.assertEquals("Europe/Paris",
TimeZoneParser.normalize("Europe/pARIS", usage));
+ }
+ for (String value : new String[] {"+8", "+08", "+0800", "+8:00"}) {
+ Assertions.assertEquals("+08:00", TimeZoneParser.normalize(value,
TimeZoneParser.Usage.DATETIME));
+ }
+ for (String value : new String[] {"+14:30", "-14:45", "+08:01",
"+08:15", "+08:00:01"}) {
+ Assertions.assertThrows(DateTimeException.class,
+ () -> TimeZoneParser.normalize(value,
TimeZoneParser.Usage.DATETIME));
+ }
+ Assertions.assertEquals("-14:00", TimeZoneParser.normalize("-14:00",
TimeZoneParser.Usage.DATETIME));
+ Assertions.assertEquals("+08:05:43",
+ TimeZoneParser.normalize("+08:05:43",
TimeZoneParser.Usage.TIMESTAMPTZ));
+ Assertions.assertEquals("+18:00",
+ TimeZoneParser.normalize("+18:00",
TimeZoneParser.Usage.TIMESTAMPTZ));
+ for (String value : new String[] {"+18:01", "+19:00", "-18:01",
"-19:00"}) {
+ Assertions.assertThrows(DateTimeException.class,
+ () -> TimeZoneParser.normalize(value,
TimeZoneParser.Usage.TIMESTAMPTZ));
+ }
+ }
+
+ @Test
+ void literalSuffixes() {
+ Assertions.assertTrue(DateTimeChecker.hasTimeZone("2024-01-02 12:00:00
America/Port-au-Prince"));
+ Assertions.assertTrue(DateTimeChecker.hasTimeZone("2024-01-02 12:00:00
Etc/GMT+3"));
+ Assertions.assertTrue(DateTimeChecker.hasTimeZone("2024-01-02
12:00:00+0800"));
+ Assertions.assertDoesNotThrow(() -> new DateTimeV2Literal("2024-01-02
12:00:00-14:00"));
+ Assertions.assertDoesNotThrow(() -> new DateTimeV2Literal("2024-01-02
12:00:00+8:30"));
+ Assertions.assertDoesNotThrow(() -> new DateTimeV2Literal("2024-01-02
12:00:00 UTC+8"));
+ Assertions.assertDoesNotThrow(() -> new TimestampTzLiteral("1900-01-01
08:05:43+08:05:43"));
+ Assertions.assertDoesNotThrow(() -> new
TimestampTzLiteral("20240102120000+0800"));
+ for (String suffix : new String[] {"UTC", "CST", "Asia/Shanghai",
+ "GMT0", "EST5EDT", "W-SU"}) {
+ Assertions.assertTrue(DateTimeChecker.hasTimeZone("2024-01-02
12:00:00 " + suffix), suffix);
+ Assertions.assertTrue(DateTimeChecker.hasTimeZone("20240102120000"
+ suffix), suffix);
+ Assertions.assertEquals(new TimestampTzLiteral("2024-01-02
12:00:00 " + suffix).getValue(),
+ new TimestampTzLiteral("20240102120000" +
suffix).getValue(), suffix);
+ Assertions.assertEquals(new TimestampTzLiteral("2024-01-02
12:00:00 " + suffix).getValue(),
+ new TimestampTzLiteral("20240102T120000" +
suffix).getValue(), suffix);
+ Assertions.assertEquals(new TimestampTzLiteral("2024-01-02
12:00:00 " + suffix).getValue(),
+
TimestampTzLiteral.fromTimeZone(TimeStampTzType.SYSTEM_DEFAULT,
+ "20240102120000" + suffix, "+08:00").getValue(),
suffix);
+ }
+ Assertions.assertThrows(AnalysisException.class,
+ () -> new DateTimeV2Literal("2024-01-02 12:00:00+08:01"));
+ Assertions.assertThrows(AnalysisException.class,
+ () -> new TimestampTzLiteral("2024-01-02 12:00:00 GMT-13:00"));
+ }
+}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeStampNsLiteralTest.java
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeStampNsLiteralTest.java
index b2bdc40ca98..ccbcf0d124b 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeStampNsLiteralTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/TimeStampNsLiteralTest.java
@@ -77,6 +77,8 @@ class TimeStampNsLiteralTest {
TimeStampNsLiteral withTimeZone = new TimeStampNsLiteral(
"2024-01-02 03:04:05.123456789+00:00");
Assertions.assertEquals(123456789, withTimeZone.getNanoSecond());
+ Assertions.assertThrows(Exception.class,
+ () -> new TimeStampNsLiteral("2024-01-02
03:04:05.123456789+08:01"));
TimeStampNsLiteral rounded = new TimeStampNsLiteral(
"2024-01-02 03:04:05.9999999995");
diff --git
a/regression-test/data/datatype_p0/datetimev2/test_timezone_parser_contract.out
b/regression-test/data/datatype_p0/datetimev2/test_timezone_parser_contract.out
new file mode 100644
index 00000000000..cb61013a144
--- /dev/null
+++
b/regression-test/data/datatype_p0/datetimev2/test_timezone_parser_contract.out
@@ -0,0 +1,1504 @@
+-- This file is automatically generated. You should know what you did if you
want to edit this
+-- !literal_0_0_0 --
+2024-01-02T12:00
+
+-- !literal_0_0_1 --
+2024-01-02T12:30
+
+-- !literal_0_0_2 --
+2024-01-01T22:00
+
+-- !literal_0_0_3 --
+2024-01-03T00:00
+
+-- !literal_0_0_4 --
+2024-01-03T01:00
+
+-- !literal_0_0_5 --
+2024-01-03T02:00
+
+-- !literal_0_0_6 --
+2024-01-02T04:00
+
+-- !literal_0_0_7 --
+2024-01-02T04:00
+
+-- !literal_0_0_8 --
+2024-01-02T04:00
+
+-- !literal_0_0_9 --
+2024-01-02T03:30
+
+-- !literal_0_0_10 --
+2024-01-02T03:15
+
+-- !literal_0_0_11 --
+\N
+
+-- !literal_0_0_12 --
+\N
+
+-- !literal_0_0_13 --
+\N
+
+-- !literal_0_0_14 --
+\N
+
+-- !literal_0_0_15 --
+\N
+
+-- !literal_0_0_16 --
+\N
+
+-- !literal_0_0_17 --
+2024-01-02T12:00
+
+-- !literal_0_0_18 --
+2024-01-02T12:00
+
+-- !literal_0_0_19 --
+2024-01-02T12:00
+
+-- !literal_0_0_20 --
+2024-01-02T12:00
+
+-- !literal_0_0_21 --
+2024-01-02T12:00
+
+-- !literal_0_0_22 --
+2024-01-02T04:00
+
+-- !literal_0_0_23 --
+2024-01-02T04:00
+
+-- !literal_0_0_24 --
+2024-01-02T04:00
+
+-- !literal_0_0_25 --
+2024-01-02T04:00
+
+-- !literal_0_0_26 --
+2024-01-02T15:00
+
+-- !literal_0_0_27 --
+2024-01-02T17:00
+
+-- !literal_0_0_28 --
+\N
+
+-- !literal_0_0_29 --
+2024-01-02T03:59
+
+-- !literal_0_0_30 --
+\N
+
+-- !literal_0_0_31 --
+2024-01-02T04:00
+
+-- !literal_0_0_32 --
+\N
+
+-- !literal_0_0_33 --
+\N
+
+-- !literal_0_0_34 --
+\N
+
+-- !literal_0_0_35 --
+\N
+
+-- !literal_0_0_36 --
+\N
+
+-- !literal_0_0_37 --
+\N
+
+-- !literal_0_0_38 --
+2024-01-02T12:00
+
+-- !literal_0_0_39 --
+2024-01-02T17:00
+
+-- !literal_0_0_40 --
+2024-01-02T09:00
+
+-- !literal_0_0_41 --
+\N
+
+-- !literal_0_0_42 --
+\N
+
+-- !literal_0_0_43 --
+\N
+
+-- !literal_0_0_44 --
+\N
+
+-- !literal_0_0_45 --
+\N
+
+-- !literal_0_0_46 --
+\N
+
+-- !literal_0_0_47 --
+1900-01-01T00:00
+
+-- !literal_0_0_48 --
+1900-01-01T00:00
+
+-- !literal_0_0_49 --
+\N
+
+-- !literal_0_0_50 --
+2024-01-02T04:00
+
+-- !literal_0_0_51 --
+2024-01-02T03:30
+
+-- !literal_0_0_52 --
+2024-01-02T12:00
+
+-- !literal_0_0_53 --
+2024-01-02T12:00
+
+-- !literal_0_0_54 --
+\N
+
+-- !literal_0_1_0 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_1 --
+2024-01-02 12:30:00.000000Z
+
+-- !literal_0_1_2 --
+2024-01-01 22:00:00.000000Z
+
+-- !literal_0_1_3 --
+2024-01-03 00:00:00.000000Z
+
+-- !literal_0_1_4 --
+2024-01-03 01:00:00.000000Z
+
+-- !literal_0_1_5 --
+2024-01-03 02:00:00.000000Z
+
+-- !literal_0_1_6 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_7 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_8 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_9 --
+2024-01-02 03:30:00.000000Z
+
+-- !literal_0_1_10 --
+2024-01-02 03:15:00.000000Z
+
+-- !literal_0_1_11 --
+2024-01-01 21:30:00.000000Z
+
+-- !literal_0_1_12 --
+2024-01-03 02:45:00.000000Z
+
+-- !literal_0_1_13 --
+2024-01-02 03:59:00.000000Z
+
+-- !literal_0_1_14 --
+2024-01-02 03:45:00.000000Z
+
+-- !literal_0_1_15 --
+\N
+
+-- !literal_0_1_16 --
+\N
+
+-- !literal_0_1_17 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_18 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_19 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_20 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_21 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_22 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_23 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_24 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_25 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_26 --
+2024-01-02 15:00:00.000000Z
+
+-- !literal_0_1_27 --
+2024-01-02 17:00:00.000000Z
+
+-- !literal_0_1_28 --
+\N
+
+-- !literal_0_1_29 --
+2024-01-02 03:59:00.000000Z
+
+-- !literal_0_1_30 --
+\N
+
+-- !literal_0_1_31 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_32 --
+2024-01-02 03:54:17.000000Z
+
+-- !literal_0_1_33 --
+2024-01-03 02:21:00.000000Z
+
+-- !literal_0_1_34 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_35 --
+2024-01-01 18:00:00.000000Z
+
+-- !literal_0_1_36 --
+\N
+
+-- !literal_0_1_37 --
+\N
+
+-- !literal_0_1_38 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_39 --
+2024-01-02 17:00:00.000000Z
+
+-- !literal_0_1_40 --
+2024-01-02 09:00:00.000000Z
+
+-- !literal_0_1_41 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_42 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_43 --
+\N
+
+-- !literal_0_1_44 --
+\N
+
+-- !literal_0_1_45 --
+\N
+
+-- !literal_0_1_46 --
+\N
+
+-- !literal_0_1_47 --
+1900-01-01 00:00:00.000000Z
+
+-- !literal_0_1_48 --
+1900-01-01 00:00:00.000000Z
+
+-- !literal_0_1_49 --
+1900-01-01 00:00:00.000000Z
+
+-- !literal_0_1_50 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_0_1_51 --
+2024-01-02 03:30:00.000000Z
+
+-- !literal_0_1_52 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_53 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_0_1_54 --
+\N
+
+-- !literal_1_0_0 --
+2024-01-02T12:00
+
+-- !literal_1_0_1 --
+2024-01-02T12:30
+
+-- !literal_1_0_2 --
+2024-01-01T22:00
+
+-- !literal_1_0_3 --
+2024-01-03T00:00
+
+-- !literal_1_0_4 --
+2024-01-03T01:00
+
+-- !literal_1_0_5 --
+2024-01-03T02:00
+
+-- !literal_1_0_6 --
+2024-01-02T04:00
+
+-- !literal_1_0_7 --
+2024-01-02T04:00
+
+-- !literal_1_0_8 --
+2024-01-02T04:00
+
+-- !literal_1_0_9 --
+2024-01-02T03:30
+
+-- !literal_1_0_10 --
+2024-01-02T03:15
+
+-- !literal_1_0_11 --
+\N
+
+-- !literal_1_0_12 --
+\N
+
+-- !literal_1_0_13 --
+\N
+
+-- !literal_1_0_14 --
+\N
+
+-- !literal_1_0_15 --
+\N
+
+-- !literal_1_0_16 --
+\N
+
+-- !literal_1_0_17 --
+2024-01-02T12:00
+
+-- !literal_1_0_18 --
+2024-01-02T12:00
+
+-- !literal_1_0_19 --
+2024-01-02T12:00
+
+-- !literal_1_0_20 --
+2024-01-02T12:00
+
+-- !literal_1_0_21 --
+2024-01-02T12:00
+
+-- !literal_1_0_22 --
+2024-01-02T04:00
+
+-- !literal_1_0_23 --
+2024-01-02T04:00
+
+-- !literal_1_0_24 --
+2024-01-02T04:00
+
+-- !literal_1_0_25 --
+2024-01-02T04:00
+
+-- !literal_1_0_26 --
+2024-01-02T15:00
+
+-- !literal_1_0_27 --
+2024-01-02T17:00
+
+-- !literal_1_0_28 --
+\N
+
+-- !literal_1_0_29 --
+2024-01-02T03:59
+
+-- !literal_1_0_30 --
+\N
+
+-- !literal_1_0_31 --
+2024-01-02T04:00
+
+-- !literal_1_0_32 --
+\N
+
+-- !literal_1_0_33 --
+\N
+
+-- !literal_1_0_34 --
+\N
+
+-- !literal_1_0_35 --
+\N
+
+-- !literal_1_0_36 --
+\N
+
+-- !literal_1_0_37 --
+\N
+
+-- !literal_1_0_38 --
+2024-01-02T12:00
+
+-- !literal_1_0_39 --
+2024-01-02T17:00
+
+-- !literal_1_0_40 --
+2024-01-02T09:00
+
+-- !literal_1_0_41 --
+\N
+
+-- !literal_1_0_42 --
+\N
+
+-- !literal_1_0_43 --
+\N
+
+-- !literal_1_0_44 --
+\N
+
+-- !literal_1_0_45 --
+\N
+
+-- !literal_1_0_46 --
+\N
+
+-- !literal_1_0_47 --
+1900-01-01T00:00
+
+-- !literal_1_0_48 --
+1900-01-01T00:00
+
+-- !literal_1_0_49 --
+\N
+
+-- !literal_1_0_50 --
+2024-01-02T04:00
+
+-- !literal_1_0_51 --
+2024-01-02T03:30
+
+-- !literal_1_0_52 --
+2024-01-02T12:00
+
+-- !literal_1_0_53 --
+2024-01-02T12:00
+
+-- !literal_1_0_54 --
+\N
+
+-- !literal_1_1_0 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_1 --
+2024-01-02 12:30:00.000000+00:00
+
+-- !literal_1_1_2 --
+2024-01-01 22:00:00.000000+00:00
+
+-- !literal_1_1_3 --
+2024-01-03 00:00:00.000000+00:00
+
+-- !literal_1_1_4 --
+2024-01-03 01:00:00.000000+00:00
+
+-- !literal_1_1_5 --
+2024-01-03 02:00:00.000000+00:00
+
+-- !literal_1_1_6 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_7 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_8 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_9 --
+2024-01-02 03:30:00.000000+00:00
+
+-- !literal_1_1_10 --
+2024-01-02 03:15:00.000000+00:00
+
+-- !literal_1_1_11 --
+2024-01-01 21:30:00.000000+00:00
+
+-- !literal_1_1_12 --
+2024-01-03 02:45:00.000000+00:00
+
+-- !literal_1_1_13 --
+2024-01-02 03:59:00.000000+00:00
+
+-- !literal_1_1_14 --
+2024-01-02 03:45:00.000000+00:00
+
+-- !literal_1_1_15 --
+\N
+
+-- !literal_1_1_16 --
+\N
+
+-- !literal_1_1_17 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_18 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_19 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_20 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_21 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_22 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_23 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_24 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_25 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_26 --
+2024-01-02 15:00:00.000000+00:00
+
+-- !literal_1_1_27 --
+2024-01-02 17:00:00.000000+00:00
+
+-- !literal_1_1_28 --
+\N
+
+-- !literal_1_1_29 --
+2024-01-02 03:59:00.000000+00:00
+
+-- !literal_1_1_30 --
+\N
+
+-- !literal_1_1_31 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_32 --
+2024-01-02 03:54:17.000000+00:00
+
+-- !literal_1_1_33 --
+2024-01-03 02:21:00.000000+00:00
+
+-- !literal_1_1_34 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_35 --
+2024-01-01 18:00:00.000000+00:00
+
+-- !literal_1_1_36 --
+\N
+
+-- !literal_1_1_37 --
+\N
+
+-- !literal_1_1_38 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_39 --
+2024-01-02 17:00:00.000000+00:00
+
+-- !literal_1_1_40 --
+2024-01-02 09:00:00.000000+00:00
+
+-- !literal_1_1_41 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_42 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_43 --
+\N
+
+-- !literal_1_1_44 --
+\N
+
+-- !literal_1_1_45 --
+\N
+
+-- !literal_1_1_46 --
+\N
+
+-- !literal_1_1_47 --
+1900-01-01 00:00:00.000000+00:00
+
+-- !literal_1_1_48 --
+1900-01-01 00:00:00.000000+00:00
+
+-- !literal_1_1_49 --
+1900-01-01 00:00:00.000000+00:00
+
+-- !literal_1_1_50 --
+2024-01-02 04:00:00.000000+00:00
+
+-- !literal_1_1_51 --
+2024-01-02 03:30:00.000000+00:00
+
+-- !literal_1_1_52 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_53 --
+2024-01-02 12:00:00.000000+00:00
+
+-- !literal_1_1_54 --
+\N
+
+-- !literal_2_0_0 --
+2024-01-02T12:00
+
+-- !literal_2_0_1 --
+2024-01-02T12:30
+
+-- !literal_2_0_2 --
+2024-01-01T22:00
+
+-- !literal_2_0_3 --
+2024-01-03T00:00
+
+-- !literal_2_0_4 --
+2024-01-03T01:00
+
+-- !literal_2_0_5 --
+2024-01-03T02:00
+
+-- !literal_2_0_6 --
+2024-01-02T04:00
+
+-- !literal_2_0_7 --
+2024-01-02T04:00
+
+-- !literal_2_0_8 --
+2024-01-02T04:00
+
+-- !literal_2_0_9 --
+2024-01-02T03:30
+
+-- !literal_2_0_10 --
+2024-01-02T03:15
+
+-- !literal_2_0_11 --
+\N
+
+-- !literal_2_0_12 --
+\N
+
+-- !literal_2_0_13 --
+\N
+
+-- !literal_2_0_14 --
+\N
+
+-- !literal_2_0_15 --
+\N
+
+-- !literal_2_0_16 --
+\N
+
+-- !literal_2_0_17 --
+2024-01-02T12:00
+
+-- !literal_2_0_18 --
+2024-01-02T12:00
+
+-- !literal_2_0_19 --
+2024-01-02T12:00
+
+-- !literal_2_0_20 --
+2024-01-02T12:00
+
+-- !literal_2_0_21 --
+2024-01-02T12:00
+
+-- !literal_2_0_22 --
+2024-01-02T04:00
+
+-- !literal_2_0_23 --
+2024-01-02T04:00
+
+-- !literal_2_0_24 --
+2024-01-02T04:00
+
+-- !literal_2_0_25 --
+2024-01-02T04:00
+
+-- !literal_2_0_26 --
+2024-01-02T15:00
+
+-- !literal_2_0_27 --
+2024-01-02T17:00
+
+-- !literal_2_0_28 --
+\N
+
+-- !literal_2_0_29 --
+2024-01-02T03:59
+
+-- !literal_2_0_30 --
+\N
+
+-- !literal_2_0_31 --
+2024-01-02T04:00
+
+-- !literal_2_0_32 --
+\N
+
+-- !literal_2_0_33 --
+\N
+
+-- !literal_2_0_34 --
+\N
+
+-- !literal_2_0_35 --
+\N
+
+-- !literal_2_0_36 --
+\N
+
+-- !literal_2_0_37 --
+\N
+
+-- !literal_2_0_38 --
+2024-01-02T12:00
+
+-- !literal_2_0_39 --
+2024-01-02T17:00
+
+-- !literal_2_0_40 --
+2024-01-02T09:00
+
+-- !literal_2_0_41 --
+\N
+
+-- !literal_2_0_42 --
+\N
+
+-- !literal_2_0_43 --
+\N
+
+-- !literal_2_0_44 --
+\N
+
+-- !literal_2_0_45 --
+\N
+
+-- !literal_2_0_46 --
+\N
+
+-- !literal_2_0_47 --
+1900-01-01T00:00
+
+-- !literal_2_0_48 --
+1900-01-01T00:00
+
+-- !literal_2_0_49 --
+\N
+
+-- !literal_2_0_50 --
+2024-01-02T04:00
+
+-- !literal_2_0_51 --
+2024-01-02T03:30
+
+-- !literal_2_0_52 --
+2024-01-02T12:00
+
+-- !literal_2_0_53 --
+2024-01-02T12:00
+
+-- !literal_2_0_54 --
+\N
+
+-- !literal_2_1_0 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_1 --
+2024-01-02 12:30:00.000000Z
+
+-- !literal_2_1_2 --
+2024-01-01 22:00:00.000000Z
+
+-- !literal_2_1_3 --
+2024-01-03 00:00:00.000000Z
+
+-- !literal_2_1_4 --
+2024-01-03 01:00:00.000000Z
+
+-- !literal_2_1_5 --
+2024-01-03 02:00:00.000000Z
+
+-- !literal_2_1_6 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_7 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_8 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_9 --
+2024-01-02 03:30:00.000000Z
+
+-- !literal_2_1_10 --
+2024-01-02 03:15:00.000000Z
+
+-- !literal_2_1_11 --
+2024-01-01 21:30:00.000000Z
+
+-- !literal_2_1_12 --
+2024-01-03 02:45:00.000000Z
+
+-- !literal_2_1_13 --
+2024-01-02 03:59:00.000000Z
+
+-- !literal_2_1_14 --
+2024-01-02 03:45:00.000000Z
+
+-- !literal_2_1_15 --
+\N
+
+-- !literal_2_1_16 --
+\N
+
+-- !literal_2_1_17 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_18 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_19 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_20 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_21 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_22 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_23 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_24 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_25 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_26 --
+2024-01-02 15:00:00.000000Z
+
+-- !literal_2_1_27 --
+2024-01-02 17:00:00.000000Z
+
+-- !literal_2_1_28 --
+\N
+
+-- !literal_2_1_29 --
+2024-01-02 03:59:00.000000Z
+
+-- !literal_2_1_30 --
+\N
+
+-- !literal_2_1_31 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_32 --
+2024-01-02 03:54:17.000000Z
+
+-- !literal_2_1_33 --
+2024-01-03 02:21:00.000000Z
+
+-- !literal_2_1_34 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_35 --
+2024-01-01 18:00:00.000000Z
+
+-- !literal_2_1_36 --
+\N
+
+-- !literal_2_1_37 --
+\N
+
+-- !literal_2_1_38 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_39 --
+2024-01-02 17:00:00.000000Z
+
+-- !literal_2_1_40 --
+2024-01-02 09:00:00.000000Z
+
+-- !literal_2_1_41 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_42 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_43 --
+\N
+
+-- !literal_2_1_44 --
+\N
+
+-- !literal_2_1_45 --
+\N
+
+-- !literal_2_1_46 --
+\N
+
+-- !literal_2_1_47 --
+1900-01-01 00:00:00.000000Z
+
+-- !literal_2_1_48 --
+1900-01-01 00:00:00.000000Z
+
+-- !literal_2_1_49 --
+1900-01-01 00:00:00.000000Z
+
+-- !literal_2_1_50 --
+2024-01-02 04:00:00.000000Z
+
+-- !literal_2_1_51 --
+2024-01-02 03:30:00.000000Z
+
+-- !literal_2_1_52 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_53 --
+2024-01-02 12:00:00.000000Z
+
+-- !literal_2_1_54 --
+\N
+
+-- !slots_0 --
+0 2024-01-02T12:00
+1 2024-01-02T12:30
+2 2024-01-01T22:00
+3 2024-01-03T00:00
+4 2024-01-03T01:00
+5 2024-01-03T02:00
+6 2024-01-02T04:00
+7 2024-01-02T04:00
+8 2024-01-02T04:00
+9 2024-01-02T03:30
+10 2024-01-02T03:15
+11 \N
+12 \N
+13 \N
+14 \N
+15 \N
+16 \N
+17 2024-01-02T12:00
+18 2024-01-02T12:00
+19 2024-01-02T12:00
+20 2024-01-02T12:00
+21 2024-01-02T12:00
+22 2024-01-02T04:00
+23 2024-01-02T04:00
+24 2024-01-02T04:00
+25 2024-01-02T04:00
+26 2024-01-02T15:00
+27 2024-01-02T17:00
+28 \N
+29 2024-01-02T03:59
+30 \N
+31 2024-01-02T04:00
+32 \N
+33 \N
+34 \N
+35 \N
+36 \N
+37 \N
+38 2024-01-02T12:00
+39 2024-01-02T17:00
+40 2024-01-02T09:00
+41 \N
+42 \N
+43 \N
+44 \N
+45 \N
+46 \N
+47 1900-01-01T00:00
+48 1900-01-01T00:00
+49 \N
+50 2024-01-02T04:00
+51 2024-01-02T03:30
+52 2024-01-02T12:00
+53 2024-01-02T12:00
+54 \N
+
+-- !lambda_0 --
+0 ["2024-01-02 12:00:00.000000"]
+1 ["2024-01-02 12:30:00.000000"]
+2 ["2024-01-01 22:00:00.000000"]
+3 ["2024-01-03 00:00:00.000000"]
+4 ["2024-01-03 01:00:00.000000"]
+5 ["2024-01-03 02:00:00.000000"]
+6 ["2024-01-02 04:00:00.000000"]
+7 ["2024-01-02 04:00:00.000000"]
+8 ["2024-01-02 04:00:00.000000"]
+9 ["2024-01-02 03:30:00.000000"]
+10 ["2024-01-02 03:15:00.000000"]
+11 [null]
+12 [null]
+13 [null]
+14 [null]
+15 [null]
+16 [null]
+17 ["2024-01-02 12:00:00.000000"]
+18 ["2024-01-02 12:00:00.000000"]
+19 ["2024-01-02 12:00:00.000000"]
+20 ["2024-01-02 12:00:00.000000"]
+21 ["2024-01-02 12:00:00.000000"]
+22 ["2024-01-02 04:00:00.000000"]
+23 ["2024-01-02 04:00:00.000000"]
+24 ["2024-01-02 04:00:00.000000"]
+25 ["2024-01-02 04:00:00.000000"]
+26 ["2024-01-02 15:00:00.000000"]
+27 ["2024-01-02 17:00:00.000000"]
+28 [null]
+29 ["2024-01-02 03:59:00.000000"]
+30 [null]
+31 ["2024-01-02 04:00:00.000000"]
+32 [null]
+33 [null]
+34 [null]
+35 [null]
+36 [null]
+37 [null]
+38 ["2024-01-02 12:00:00.000000"]
+39 ["2024-01-02 17:00:00.000000"]
+40 ["2024-01-02 09:00:00.000000"]
+41 [null]
+42 [null]
+43 [null]
+44 [null]
+45 [null]
+46 [null]
+47 ["1900-01-01 00:00:00.000000"]
+48 ["1900-01-01 00:00:00.000000"]
+49 [null]
+50 ["2024-01-02 04:00:00.000000"]
+51 ["2024-01-02 03:30:00.000000"]
+52 ["2024-01-02 12:00:00.000000"]
+53 ["2024-01-02 12:00:00.000000"]
+54 [null]
+
+-- !slots_1 --
+0 2024-01-02 12:00:00.000000+00:00
+1 2024-01-02 12:30:00.000000+00:00
+2 2024-01-01 22:00:00.000000+00:00
+3 2024-01-03 00:00:00.000000+00:00
+4 2024-01-03 01:00:00.000000+00:00
+5 2024-01-03 02:00:00.000000+00:00
+6 2024-01-02 04:00:00.000000+00:00
+7 2024-01-02 04:00:00.000000+00:00
+8 2024-01-02 04:00:00.000000+00:00
+9 2024-01-02 03:30:00.000000+00:00
+10 2024-01-02 03:15:00.000000+00:00
+11 2024-01-01 21:30:00.000000+00:00
+12 2024-01-03 02:45:00.000000+00:00
+13 2024-01-02 03:59:00.000000+00:00
+14 2024-01-02 03:45:00.000000+00:00
+15 \N
+16 \N
+17 2024-01-02 12:00:00.000000+00:00
+18 2024-01-02 12:00:00.000000+00:00
+19 2024-01-02 12:00:00.000000+00:00
+20 2024-01-02 12:00:00.000000+00:00
+21 2024-01-02 12:00:00.000000+00:00
+22 2024-01-02 04:00:00.000000+00:00
+23 2024-01-02 04:00:00.000000+00:00
+24 2024-01-02 04:00:00.000000+00:00
+25 2024-01-02 04:00:00.000000+00:00
+26 2024-01-02 15:00:00.000000+00:00
+27 2024-01-02 17:00:00.000000+00:00
+28 \N
+29 2024-01-02 03:59:00.000000+00:00
+30 \N
+31 2024-01-02 04:00:00.000000+00:00
+32 2024-01-02 03:54:17.000000+00:00
+33 2024-01-03 02:21:00.000000+00:00
+34 2024-01-02 04:00:00.000000+00:00
+35 2024-01-01 18:00:00.000000+00:00
+36 \N
+37 \N
+38 2024-01-02 12:00:00.000000+00:00
+39 2024-01-02 17:00:00.000000+00:00
+40 2024-01-02 09:00:00.000000+00:00
+41 2024-01-02 12:00:00.000000+00:00
+42 2024-01-02 12:00:00.000000+00:00
+43 \N
+44 \N
+45 \N
+46 \N
+47 1900-01-01 00:00:00.000000+00:00
+48 1900-01-01 00:00:00.000000+00:00
+49 1900-01-01 00:00:00.000000+00:00
+50 2024-01-02 04:00:00.000000+00:00
+51 2024-01-02 03:30:00.000000+00:00
+52 2024-01-02 12:00:00.000000+00:00
+53 2024-01-02 12:00:00.000000+00:00
+54 \N
+
+-- !lambda_1 --
+0 ["2024-01-02 12:00:00.000000+00:00"]
+1 ["2024-01-02 12:30:00.000000+00:00"]
+2 ["2024-01-01 22:00:00.000000+00:00"]
+3 ["2024-01-03 00:00:00.000000+00:00"]
+4 ["2024-01-03 01:00:00.000000+00:00"]
+5 ["2024-01-03 02:00:00.000000+00:00"]
+6 ["2024-01-02 04:00:00.000000+00:00"]
+7 ["2024-01-02 04:00:00.000000+00:00"]
+8 ["2024-01-02 04:00:00.000000+00:00"]
+9 ["2024-01-02 03:30:00.000000+00:00"]
+10 ["2024-01-02 03:15:00.000000+00:00"]
+11 ["2024-01-01 21:30:00.000000+00:00"]
+12 ["2024-01-03 02:45:00.000000+00:00"]
+13 ["2024-01-02 03:59:00.000000+00:00"]
+14 ["2024-01-02 03:45:00.000000+00:00"]
+15 [null]
+16 [null]
+17 ["2024-01-02 12:00:00.000000+00:00"]
+18 ["2024-01-02 12:00:00.000000+00:00"]
+19 ["2024-01-02 12:00:00.000000+00:00"]
+20 ["2024-01-02 12:00:00.000000+00:00"]
+21 ["2024-01-02 12:00:00.000000+00:00"]
+22 ["2024-01-02 04:00:00.000000+00:00"]
+23 ["2024-01-02 04:00:00.000000+00:00"]
+24 ["2024-01-02 04:00:00.000000+00:00"]
+25 ["2024-01-02 04:00:00.000000+00:00"]
+26 ["2024-01-02 15:00:00.000000+00:00"]
+27 ["2024-01-02 17:00:00.000000+00:00"]
+28 [null]
+29 ["2024-01-02 03:59:00.000000+00:00"]
+30 [null]
+31 ["2024-01-02 04:00:00.000000+00:00"]
+32 ["2024-01-02 03:54:17.000000+00:00"]
+33 ["2024-01-03 02:21:00.000000+00:00"]
+34 ["2024-01-02 04:00:00.000000+00:00"]
+35 ["2024-01-01 18:00:00.000000+00:00"]
+36 [null]
+37 [null]
+38 ["2024-01-02 12:00:00.000000+00:00"]
+39 ["2024-01-02 17:00:00.000000+00:00"]
+40 ["2024-01-02 09:00:00.000000+00:00"]
+41 ["2024-01-02 12:00:00.000000+00:00"]
+42 ["2024-01-02 12:00:00.000000+00:00"]
+43 [null]
+44 [null]
+45 [null]
+46 [null]
+47 ["1900-01-01 00:00:00.000000+00:00"]
+48 ["1900-01-01 00:00:00.000000+00:00"]
+49 ["1900-01-01 00:00:00.000000+00:00"]
+50 ["2024-01-02 04:00:00.000000+00:00"]
+51 ["2024-01-02 03:30:00.000000+00:00"]
+52 ["2024-01-02 12:00:00.000000+00:00"]
+53 ["2024-01-02 12:00:00.000000+00:00"]
+54 [null]
+
+-- !session_literal_0_0 --
+2024-01-02 12:00:00.000000+08:00
+
+-- !session_literal_0_1 --
+2024-01-03 01:00:00.000000+08:00
+
+-- !session_literal_0_2 --
+2024-01-02 23:00:00.000000+08:00
+
+-- !session_literal_1_0 --
+2024-01-02 12:00:00.000000+08:00
+
+-- !session_literal_1_1 --
+2024-01-03 01:00:00.000000+08:00
+
+-- !session_literal_1_2 --
+2024-01-02 23:00:00.000000+08:00
+
+-- !session_slots --
+0 2024-01-02 20:00:00.000000+08:00
+1 2024-01-02 20:30:00.000000+08:00
+2 2024-01-02 06:00:00.000000+08:00
+3 2024-01-03 08:00:00.000000+08:00
+4 2024-01-03 09:00:00.000000+08:00
+5 2024-01-03 10:00:00.000000+08:00
+6 2024-01-02 12:00:00.000000+08:00
+7 2024-01-02 12:00:00.000000+08:00
+8 2024-01-02 12:00:00.000000+08:00
+9 2024-01-02 11:30:00.000000+08:00
+10 2024-01-02 11:15:00.000000+08:00
+11 2024-01-02 05:30:00.000000+08:00
+12 2024-01-03 10:45:00.000000+08:00
+13 2024-01-02 11:59:00.000000+08:00
+14 2024-01-02 11:45:00.000000+08:00
+15 \N
+16 \N
+17 2024-01-02 20:00:00.000000+08:00
+18 2024-01-02 20:00:00.000000+08:00
+19 2024-01-02 20:00:00.000000+08:00
+20 2024-01-02 20:00:00.000000+08:00
+21 2024-01-02 20:00:00.000000+08:00
+22 2024-01-02 12:00:00.000000+08:00
+23 2024-01-02 12:00:00.000000+08:00
+24 2024-01-02 12:00:00.000000+08:00
+25 2024-01-02 12:00:00.000000+08:00
+26 2024-01-02 23:00:00.000000+08:00
+27 2024-01-03 01:00:00.000000+08:00
+28 \N
+29 2024-01-02 11:59:00.000000+08:00
+30 \N
+31 2024-01-02 12:00:00.000000+08:00
+32 2024-01-02 11:54:17.000000+08:00
+33 2024-01-03 10:21:00.000000+08:00
+34 2024-01-02 12:00:00.000000+08:00
+35 2024-01-02 02:00:00.000000+08:00
+36 \N
+37 \N
+38 2024-01-02 20:00:00.000000+08:00
+39 2024-01-03 01:00:00.000000+08:00
+40 2024-01-02 17:00:00.000000+08:00
+41 2024-01-02 20:00:00.000000+08:00
+42 2024-01-02 20:00:00.000000+08:00
+43 \N
+44 \N
+45 \N
+46 \N
+47 1900-01-01 08:00:00.000000+08:00
+48 1900-01-01 08:00:00.000000+08:00
+49 1900-01-01 08:00:00.000000+08:00
+50 2024-01-02 12:00:00.000000+08:00
+51 2024-01-02 11:30:00.000000+08:00
+52 2024-01-02 20:00:00.000000+08:00
+53 2024-01-02 20:00:00.000000+08:00
+54 \N
+
+-- !session_zone_0 --
+UTC 2024-01-02T12:00
+
+-- !session_zone_1 --
+UTC 2024-01-02T12:00
+
+-- !session_zone_2 --
+Zulu 2024-01-02T12:00
+
+-- !session_zone_3 --
+CST 2024-01-02T20:00
+
+-- !session_zone_4 --
+Asia/Shanghai 2024-01-02T20:00
+
+-- !session_zone_5 --
+UTC+08:00 2024-01-02T20:00
+
+-- !session_zone_6 --
+GMT-06:00 2024-01-02T06:00
+
+-- !session_zone_7 --
++14:00 2024-01-03T02:00
+
+-- !session_zone_8 --
+-12:00 2024-01-02T00:00
+
+-- !convert_0_0_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_0_0_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_0_0_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_0_0_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_0_0_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_0_1_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_0_1_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_0_1_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_0_1_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_0_1_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_0_2_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_0_2_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_0_2_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_0_2_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_0_2_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_0_3_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_0_3_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_0_3_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_0_3_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_0_3_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_0_4_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_0_4_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_0_4_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_0_4_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_0_4_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_1_0_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_1_0_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_1_0_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_1_0_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_1_0_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_1_1_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_1_1_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_1_1_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_1_1_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_1_1_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_1_2_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_1_2_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_1_2_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_1_2_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_1_2_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_1_3_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_1_3_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_1_3_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_1_3_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_1_3_4 --
+2024-01-02T12:30:00.123456
+
+-- !convert_1_4_0 --
+2024-01-01T22:00:00.123456
+
+-- !convert_1_4_1 --
+2024-01-03T00:00:00.123456
+
+-- !convert_1_4_2 --
+2024-01-02T03:59:00.123456
+
+-- !convert_1_4_3 --
+2024-01-02T03:45:00.123456
+
+-- !convert_1_4_4 --
+2024-01-02T12:30:00.123456
+
+-- !strict_0 --
+2024-01-03T02:00
+
+-- !strict_1 --
+2024-01-02T03:30
+
+-- !strict_2 --
+2024-01-02T04:00
+
+-- !strict_timestamptz_0_0 --
+2024-01-01 18:00:00.000000Z
+
+-- !strict_timestamptz_0_1 --
+2024-01-03 06:00:00.000000Z
+
+-- !strict_timestamptz_0_2 --
+2024-01-02 03:54:17.000000Z
+
+-- !strict_timestamptz_0_3 --
+2024-01-02 12:00:00.000000Z
+
+-- !strict_timestamptz_1_0 --
+2024-01-01 18:00:00.000000+00:00
+
+-- !strict_timestamptz_1_1 --
+2024-01-03 06:00:00.000000+00:00
+
+-- !strict_timestamptz_1_2 --
+2024-01-02 03:54:17.000000+00:00
+
+-- !strict_timestamptz_1_3 --
+2024-01-02 12:00:00.000000+00:00
+
diff --git
a/regression-test/suites/datatype_p0/datetimev2/test_timezone_parser_contract.groovy
b/regression-test/suites/datatype_p0/datetimev2/test_timezone_parser_contract.groovy
new file mode 100644
index 00000000000..ba63c9955fb
--- /dev/null
+++
b/regression-test/suites/datatype_p0/datetimev2/test_timezone_parser_contract.groovy
@@ -0,0 +1,129 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_timezone_parser_contract") {
+ sql "DROP TABLE IF EXISTS timezone_parser_contract_inputs"
+ sql """CREATE TABLE timezone_parser_contract_inputs (id INT, v STRING)
+ DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1
+ PROPERTIES ('replication_num'='1')"""
+
+ def suffixes = ["+00:00", "-00:30", "+14:00", "-12:00", "-13:00", "-14:00",
+ "+8", "+08", "+0800", "+8:30", "+08:45", "+14:30",
"-14:45",
+ "+08:01", "+08:15", "+08:60", "+24:00", "UTC", "utc",
"GMT", "Z",
+ "zulu", "CST", "cst", "Asia/Shanghai", "asia/shanghai",
"Etc/GMT+3",
+ "America/Port-au-Prince", "America/Does_not_exist",
"UTC+08:01",
+ "GMT-13:00", "UTC+8", "+08:05:43", "-14:21", "+08:00:00",
"+18:00", "+18:01",
+ "+19:00", "GMT0", "EST5EDT", "W-SU",
+ "+00:00:00", "-00:00:00", "UTC8", "GMT8:30", "UTC0",
"GMT0:00"]
+ def inputs = suffixes.collect { "2024-01-02 12:00:00 ${it}" }
+ inputs.addAll(["1900-01-01 08:05:43 CST", "1900-01-01 08:05:43
Asia/Shanghai",
+ "1900-01-01 08:05:43+08:05:43", "20240102120000+0800",
"20240102T120000+8:30",
+ "20240102120000UTC", "20240102T120000UTC"])
+ inputs.add(null)
+ sql "INSERT INTO timezone_parser_contract_inputs VALUES " +
inputs.withIndex().collect { v, id ->
+ "(${id}, ${v == null ? 'NULL' : "'${v}'"})"
+ }.join(",")
+ sql "SET enable_sql_cache=false"
+ sql "SET time_zone='+00:00'"
+ sql "SET enable_strict_cast=false"
+
+ // Literal folding requests, folding disabled, stored slots and Lambda
inputs.
+ [[false, false], [false, true], [true, false]].eachWithIndex { settings,
path ->
+ sql "SET enable_fold_constant_by_be=${settings[0]}"
+ sql "SET debug_skip_fold_constant=${settings[1]}"
+ ["DATETIME(6)", "TIMESTAMPTZ(6)"].eachWithIndex { type, typeId ->
+ inputs.eachWithIndex { value, id ->
+ def literal = value == null ? "NULL" : "'${value}'"
+ "qt_literal_${path}_${typeId}_${id}"("SELECT CAST(${literal}
AS ${type})")
+ }
+ }
+ }
+ sql "SET enable_fold_constant_by_be=false"
+ sql "SET debug_skip_fold_constant=true"
+ ["DATETIME(6)", "TIMESTAMPTZ(6)"].eachWithIndex { type, typeId ->
+ "qt_slots_${typeId}"("SELECT id, CAST(v AS ${type}) FROM
timezone_parser_contract_inputs ORDER BY id")
+ "qt_lambda_${typeId}"("SELECT id, array_map(x -> CAST(x AS ${type}),
ARRAY(v)) FROM timezone_parser_contract_inputs ORDER BY id")
+ }
+ sql "SET time_zone='+08:00'"
+ [false, true].eachWithIndex { skip, path ->
+ sql "SET debug_skip_fold_constant=${skip}"
+ ["+0800", "America/Port-au-Prince", "Etc/GMT+3"].eachWithIndex {
suffix, id ->
+ "qt_session_literal_${path}_${id}"("SELECT CAST('2024-01-02
12:00:00 ${suffix}' AS TIMESTAMPTZ(6))")
+ }
+ }
+ sql "SET debug_skip_fold_constant=true"
+ qt_session_slots "SELECT id, CAST(v AS TIMESTAMPTZ(6)) FROM
timezone_parser_contract_inputs ORDER BY id"
+
+ ["utc", "Z", "Zulu", "cst", "Asia/Shanghai", "UTC+8", "GMT-6", "+14:00",
"-12:00"].eachWithIndex { zone, id ->
+ sql "SET time_zone='${zone}'"
+ "qt_session_zone_${id}"("SELECT @@time_zone, CAST('2024-01-02
12:00:00+00:00' AS DATETIME(6))")
+ }
+ sql "SET time_zone='+00:00'"
+ ["UTC8", "GMT8:30", "UTC0", "GMT0:00", "+00:00:00", "-00:00:00"].each {
zone ->
+ test {
+ sql "SET time_zone='${zone}'"
+ exception "Unknown or incorrect time zone"
+ }
+ }
+ [false, true].eachWithIndex { skip, path ->
+ sql "SET debug_skip_fold_constant=${skip}"
+ ["", "UTC", "GMT", "utc", "gmt"].eachWithIndex { prefix, prefixId ->
+ ["+14:00", "-12:00", "+08:01", "+08:15", "-00:30"].eachWithIndex {
offset, id ->
+ "qt_convert_${path}_${prefixId}_${id}"("SELECT
CONVERT_TZ(CAST('2024-01-02 12:00:00.123456' AS DATETIME(6)),
'${prefix}${offset}', 'UTC')")
+ }
+ ["+14:01", "+14:30", "+14:45", "-12:01", "-12:30", "-12:45",
"+15:00", "-13:00", "+08:60"].each { offset ->
+ test {
+ sql "SELECT CONVERT_TZ(CAST('2024-01-02 12:00:00' AS
DATETIME(6)), '${prefix}${offset}', 'UTC')"
+ exception "timezone"
+ }
+ test {
+ sql "SET time_zone='${prefix}${offset}'"
+ exception "Unknown or incorrect time zone"
+ }
+ }
+ }
+ }
+ sql "SET debug_skip_fold_constant=true"
+ test {
+ sql "SELECT CONVERT_TZ(CAST('2024-01-02 12:00:00' AS DATETIME(6)),
split_part(v, ' ', 3), 'UTC') FROM timezone_parser_contract_inputs WHERE id=11"
+ exception "timezone"
+ }
+ sql "SET debug_skip_fold_constant=true"
+ sql "SET enable_strict_cast=true"
+ ["-14:00", "+8:30", "UTC+8"].eachWithIndex { suffix, id ->
+ "qt_strict_${id}"("SELECT CAST('2024-01-02 12:00:00 ${suffix}' AS
DATETIME(6))")
+ }
+ ["+14:30", "+08:01", "+08:60", "+00:00:00", "UTC8", "GMT8:30"].each {
suffix ->
+ test {
+ sql "SELECT CAST('2024-01-02 12:00:00 ${suffix}' AS DATETIME(6))"
+ exception "parse"
+ }
+ }
+ [false, true].eachWithIndex { skip, path ->
+ sql "SET debug_skip_fold_constant=${skip}"
+ ["+18:00", "-18:00", "+08:05:43", "20240102120000UTC"].eachWithIndex {
suffix, id ->
+ def value = suffix.startsWith("2024") ? suffix : "2024-01-02
12:00:00 ${suffix}"
+ "qt_strict_timestamptz_${path}_${id}"("SELECT CAST('${value}' AS
TIMESTAMPTZ(6))")
+ }
+ ["+18:01", "-18:01", "+18:00:01", "-18:00:01", "+19:00",
"-19:00"].each { suffix ->
+ test {
+ sql "SELECT CAST('2024-01-02 12:00:00 ${suffix}' AS
TIMESTAMPTZ(6))"
+ exception "parse"
+ }
+ }
+ }
+}
diff --git
a/regression-test/suites/nereids_p0/expression/fold_constant/fe_constant_cast_to_date.groovy
b/regression-test/suites/nereids_p0/expression/fold_constant/fe_constant_cast_to_date.groovy
index 6f9e4382b29..1475e5055fc 100644
---
a/regression-test/suites/nereids_p0/expression/fold_constant/fe_constant_cast_to_date.groovy
+++
b/regression-test/suites/nereids_p0/expression/fold_constant/fe_constant_cast_to_date.groovy
@@ -112,7 +112,7 @@ suite("fe_constant_cast_to_date") {
}
test {
sql """select cast("2024-05-01T00:00+14:30" as date)"""
- exception "Time zone offset couldn't be larger than 14:00"
+ exception "date/datetime literal [2024-05-01T00:00:00+14:30] is
invalid"
}
test {
sql """select cast("2024-05-01T00:00+08:25" as date)"""
diff --git
a/regression-test/suites/nereids_p0/expression/fold_constant/fe_constant_cast_to_datetime.groovy
b/regression-test/suites/nereids_p0/expression/fold_constant/fe_constant_cast_to_datetime.groovy
index 22dae2e6384..84629b0a013 100644
---
a/regression-test/suites/nereids_p0/expression/fold_constant/fe_constant_cast_to_datetime.groovy
+++
b/regression-test/suites/nereids_p0/expression/fold_constant/fe_constant_cast_to_datetime.groovy
@@ -112,7 +112,7 @@ suite("fe_constant_cast_to_datetime") {
}
test {
sql """select cast("2024-05-01T00:00+14:30" as datetime)"""
- exception "Time zone offset couldn't be larger than 14:00"
+ exception "date/datetime literal [2024-05-01T00:00:00+14:30] is
invalid"
}
test {
sql """select cast("2024-05-01T00:00+08:25" as datetime)"""
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]