From 5e0ccdeeb6cef5b791d9a53542e3628ecff20be4 Mon Sep 17 00:00:00 2001 From: Gera Shegalov Date: Fri, 28 Aug 2026 16:04:28 -0700 Subject: [PATCH 1/3] Support yyyyMMdd under CORRECTED policy Signed-off-by: Gera Shegalov --- .../src/main/python/date_time_test.py | 79 +++++++++++++++++-- .../sql/rapids/datetimeExpressions.scala | 7 +- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/integration_tests/src/main/python/date_time_test.py b/integration_tests/src/main/python/date_time_test.py index 7ddca6f222b..f1b71d0b8cc 100644 --- a/integration_tests/src/main/python/date_time_test.py +++ b/integration_tests/src/main/python/date_time_test.py @@ -541,12 +541,16 @@ def test_unsupported_fallback_from_unixtime(data_gen): ('2021-01', 'MM-yyyy'), ('01-02-2022', 'MM/dd/yyyy'), ('99-01-2022', 'MM-dd-yyyy'), + ('20260230', 'yyyyMMdd'), ], ids=idfn) @pytest.mark.parametrize('parser_policy', ["CORRECTED", "EXCEPTION"], ids=idfn) @pytest.mark.parametrize('operator', ["to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"], ids=idfn) def test_string_to_timestamp_functions_ansi_invalid(invalid, fmt, parser_policy, operator): sql = "{operator}(a, '{fmt}')".format(fmt=fmt, operator=operator) - parser_policy_dic = {"spark.sql.legacy.timeParserPolicy": "{}".format(parser_policy)} + parser_policy_dic = { + "spark.sql.legacy.timeParserPolicy": "{}".format(parser_policy), + "spark.rapids.sql.hasExtendedYearValues": False, + } def fun(spark): df = spark.createDataFrame([(invalid,)], "a string") @@ -560,11 +564,15 @@ def fun(spark): def test_string_to_timestamp_functions_ansi_valid(parser_policy): expr_format = "{operator}(date_format(a, '{fmt}'), '{fmt}')" formats = ['yyyy-MM-dd', 'yyyy/MM/dd', 'yyyy-MM', 'yyyy/MM', 'dd/MM/yyyy', 'yyyy-MM-dd HH:mm:ss', - 'MM-dd', 'MM/dd', 'dd-MM', 'dd/MM', 'MM/yyyy', 'MM-yyyy', 'MM/dd/yyyy', 'MM-dd-yyyy'] + 'MM-dd', 'MM/dd', 'dd-MM', 'dd/MM', 'MM/yyyy', 'MM-yyyy', 'MM/dd/yyyy', + 'MM-dd-yyyy', 'yyyyMMdd'] operators = ["to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"] format_operator_pairs = [(fmt, operator) for fmt in formats for operator in operators] expr_list = [expr_format.format(operator=operator, fmt=fmt) for (fmt, operator) in format_operator_pairs] - parser_policy_dic = {"spark.sql.legacy.timeParserPolicy": "{}".format(parser_policy)} + parser_policy_dic = { + "spark.sql.legacy.timeParserPolicy": "{}".format(parser_policy), + "spark.rapids.sql.hasExtendedYearValues": False, + } def fun(spark): df = spark.createDataFrame([(datetime(1970, 8, 12, tzinfo=timezone.utc),)], "a timestamp") @@ -573,6 +581,32 @@ def fun(spark): assert_gpu_and_cpu_are_equal_collect(fun, conf=copy_and_update(parser_policy_dic, ansi_enabled_conf)) +@disable_ansi_mode +def test_string_to_timestamp_functions_corrected_yyyyMMdd(): + data = [ + ("20260625",), # valid + ("20240229",), # valid leap day + ("99991231",), # valid upper four-digit year boundary + ("20260625x",), # trailing character + ("2024101",), # too few digits + ("202606250",), # too many digits + ("20260230",), # invalid day + ("20261301",), # invalid month + ("20260001",), # zero month + ("2026a625",), # non-digit + (" 20260625",), # leading whitespace + ("20260625 ",), # trailing whitespace + ] + operators = ["to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"] + assert_gpu_and_cpu_are_equal_collect( + lambda spark: spark.createDataFrame(data, "a string").selectExpr(*[ + "{}(a, 'yyyyMMdd')".format(operator) for operator in operators + ]), + {'spark.sql.legacy.timeParserPolicy': 'CORRECTED', + 'spark.rapids.sql.hasExtendedYearValues': False, + 'spark.rapids.sql.incompatibleDateFormats.enabled': False}) + + exception_policy_operators = [ "to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"] if not is_before_spark_350(): @@ -581,10 +615,15 @@ def fun(spark): @pytest.mark.parametrize('ansi_enabled', [True, False], ids=['ANSI_ON', 'ANSI_OFF']) @pytest.mark.parametrize('operator', exception_policy_operators, ids=idfn) -def test_string_to_timestamp_functions_exception_policy_disagreement(ansi_enabled, operator): +@pytest.mark.parametrize('input_str,fmt', [ + ("2024-05-06xxx", "yyyy-MM-dd"), + ("20240506xxx", "yyyyMMdd"), +], ids=idfn) +def test_string_to_timestamp_functions_exception_policy_disagreement( + ansi_enabled, operator, input_str, fmt): def fun(spark): - return spark.createDataFrame([("2024-05-06xxx",)], "a string") \ - .selectExpr("{}(a, 'yyyy-MM-dd')".format(operator)) \ + return spark.createDataFrame([(input_str,)], "a string") \ + .selectExpr("{}(a, '{}')".format(operator, fmt)) \ .collect() assert_gpu_and_cpu_error( @@ -592,6 +631,7 @@ def fun(spark): conf={ 'spark.sql.ansi.enabled': ansi_enabled, 'spark.sql.legacy.timeParserPolicy': 'EXCEPTION', + 'spark.rapids.sql.hasExtendedYearValues': False, 'spark.rapids.sql.incompatibleDateFormats.enabled': False, }, error_message="different result") @@ -887,6 +927,33 @@ def test_to_timestamp_unset_policy_corrected_default(): lambda spark: spark.createDataFrame(data, "a string") .select(f.to_timestamp(f.col("a"), "yyyy-MM-dd HH:mm:ss"))) + +@disable_ansi_mode # ANSI mode is tested separately. +@tz_sensitive_test +@pytest.mark.skipif(is_before_spark_400(), + reason="Spark 4.0+ defaults timeParserPolicy to CORRECTED") +def test_to_timestamp_yyyyMMdd_unset_policy_corrected_default(): + data = [("20260625",), ("20260625x",), ("2024101",), ("20260230",)] + assert_gpu_and_cpu_are_equal_collect( + lambda spark: spark.createDataFrame(data, "a string") + .select(f.to_timestamp(f.col("a"), "yyyyMMdd")), + {'spark.rapids.sql.hasExtendedYearValues': False}) + + +@disable_ansi_mode +@allow_non_gpu('ProjectExec', 'GetTimestamp') +@pytest.mark.parametrize('parser_policy', ['CORRECTED', 'EXCEPTION'], ids=idfn) +def test_to_timestamp_yyyyMMdd_extended_year_fallback(parser_policy): + data = [("+123450101",), ("-00010101",)] + assert_gpu_fallback_collect( + lambda spark: spark.createDataFrame(data, "a string") + .selectExpr("cast(to_timestamp(a, 'yyyyMMdd') as string)"), + 'GetTimestamp', + {'spark.sql.legacy.timeParserPolicy': parser_policy, + 'spark.sql.session.timeZone': 'UTC', + 'spark.rapids.sql.hasExtendedYearValues': True, + 'spark.rapids.sql.expression.cpuBridge.enabled': False}) + @tz_sensitive_test @pytest.mark.parametrize("ansi_enabled", [True, False], ids=['ANSI_ON', 'ANSI_OFF']) def test_to_date(ansi_enabled): diff --git a/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/datetimeExpressions.scala b/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/datetimeExpressions.scala index 4a81f240396..fd72683f135 100644 --- a/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/datetimeExpressions.scala +++ b/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/datetimeExpressions.scala @@ -30,7 +30,7 @@ import com.nvidia.spark.rapids.RapidsPluginImplicits._ import com.nvidia.spark.rapids.jni.{Arithmetic, CastException, CastStrings, DateTimeUtils, GpuTimeZoneDB} import com.nvidia.spark.rapids.shims.{NullIntolerantShim, ShimBinaryExpression, ShimExpression, - TruncTimestampShims} + TruncTimestampShims, YearParseUtil} import org.apache.spark.sql.catalyst.expressions.{BinaryExpression, ExpectsInputTypes, Expression, FromUnixTime, FromUTCTimestamp, ImplicitCastInputTypes, MonthsBetween, TimeZoneAwareExpression, ToUTCTimestamp, TruncDate, TruncTimestamp} import org.apache.spark.sql.catalyst.util.DateTimeConstants @@ -417,6 +417,10 @@ abstract class UnixTimeExprMeta[A <: BinaryExpression with TimeZoneAwareExpressi sparkFormat, expr.left.dataType == DataTypes.StringType, allowLegacyFormattingOnlyFormats = allowLegacyFormattingOnlyFormats) + // The fused parser only accepts an unsigned four-digit year for this packed format. + if (expr.left.dataType == DataTypes.StringType && sparkFormat == "yyyyMMdd") { + YearParseUtil.tagParseStringAsDate(conf, this) + } case None => willNotWorkOnGpu("format has to be a string literal") } @@ -617,6 +621,7 @@ object GpuToTimestamp { "MM-yyyy", "MM/dd/yyyy", "MM-dd-yyyy", + "yyyyMMdd", "MMyyyy" ) From 1e574136df12756294d2c30db5a9ae1df4fc02d3 Mon Sep 17 00:00:00 2001 From: Gera Shegalov Date: Fri, 28 Aug 2026 20:22:10 -0700 Subject: [PATCH 2/3] Fix yyyyMMdd legacy integration tests Signed-off-by: Gera Shegalov --- integration_tests/src/main/python/date_time_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/integration_tests/src/main/python/date_time_test.py b/integration_tests/src/main/python/date_time_test.py index f1b71d0b8cc..fd88b80ed4f 100644 --- a/integration_tests/src/main/python/date_time_test.py +++ b/integration_tests/src/main/python/date_time_test.py @@ -779,6 +779,7 @@ def test_formats_for_legacy_mode(input_format, output_format): from tab '''.format(input_format=input_format, output_format=output_format), {'spark.sql.legacy.timeParserPolicy': 'LEGACY', + 'spark.rapids.sql.hasExtendedYearValues': False, 'spark.rapids.sql.incompatibleDateFormats.enabled': True}) From 18bd19761bcc4225d0dbb1ac12dee5a31547941e Mon Sep 17 00:00:00 2001 From: Gera Shegalov Date: Tue, 1 Sep 2026 17:15:09 -0700 Subject: [PATCH 3/3] Respect EXCEPTION datetime format semantics Signed-off-by: Gera Shegalov --- .../src/main/python/date_time_test.py | 77 ++++++++++++++++--- .../com/nvidia/spark/rapids/DateUtils.scala | 17 +++- .../sql/rapids/datetimeExpressions.scala | 32 +++++--- 3 files changed, 100 insertions(+), 26 deletions(-) diff --git a/integration_tests/src/main/python/date_time_test.py b/integration_tests/src/main/python/date_time_test.py index fd88b80ed4f..49cf7e725da 100644 --- a/integration_tests/src/main/python/date_time_test.py +++ b/integration_tests/src/main/python/date_time_test.py @@ -541,7 +541,6 @@ def test_unsupported_fallback_from_unixtime(data_gen): ('2021-01', 'MM-yyyy'), ('01-02-2022', 'MM/dd/yyyy'), ('99-01-2022', 'MM-dd-yyyy'), - ('20260230', 'yyyyMMdd'), ], ids=idfn) @pytest.mark.parametrize('parser_policy', ["CORRECTED", "EXCEPTION"], ids=idfn) @pytest.mark.parametrize('operator', ["to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"], ids=idfn) @@ -565,7 +564,7 @@ def test_string_to_timestamp_functions_ansi_valid(parser_policy): expr_format = "{operator}(date_format(a, '{fmt}'), '{fmt}')" formats = ['yyyy-MM-dd', 'yyyy/MM/dd', 'yyyy-MM', 'yyyy/MM', 'dd/MM/yyyy', 'yyyy-MM-dd HH:mm:ss', 'MM-dd', 'MM/dd', 'dd-MM', 'dd/MM', 'MM/yyyy', 'MM-yyyy', 'MM/dd/yyyy', - 'MM-dd-yyyy', 'yyyyMMdd'] + 'MM-dd-yyyy'] operators = ["to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"] format_operator_pairs = [(fmt, operator) for fmt in formats for operator in operators] expr_list = [expr_format.format(operator=operator, fmt=fmt) for (fmt, operator) in format_operator_pairs] @@ -607,6 +606,36 @@ def test_string_to_timestamp_functions_corrected_yyyyMMdd(): 'spark.rapids.sql.incompatibleDateFormats.enabled': False}) +@pytest.mark.parametrize('operator', + ["to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"], + ids=idfn) +def test_string_to_timestamp_functions_corrected_yyyyMMdd_ansi_valid(operator): + assert_gpu_and_cpu_are_equal_collect( + lambda spark: spark.createDataFrame([("20260625",)], "a string") + .selectExpr("{}(a, 'yyyyMMdd')".format(operator)), + {'spark.sql.ansi.enabled': True, + 'spark.sql.legacy.timeParserPolicy': 'CORRECTED', + 'spark.rapids.sql.hasExtendedYearValues': False, + 'spark.rapids.sql.incompatibleDateFormats.enabled': False}) + + +@pytest.mark.parametrize('operator', + ["to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"], + ids=idfn) +def test_string_to_timestamp_functions_corrected_yyyyMMdd_ansi_invalid(operator): + assert_gpu_and_cpu_error( + lambda spark: spark.createDataFrame([("20260230",)], "a string") + .selectExpr("{}(a, 'yyyyMMdd')".format(operator)) + .collect(), + conf={ + 'spark.sql.ansi.enabled': True, + 'spark.sql.legacy.timeParserPolicy': 'CORRECTED', + 'spark.rapids.sql.hasExtendedYearValues': False, + 'spark.rapids.sql.incompatibleDateFormats.enabled': False, + }, + error_message="Exception") + + exception_policy_operators = [ "to_unix_timestamp", "unix_timestamp", "to_timestamp", "to_date"] if not is_before_spark_350(): @@ -615,15 +644,10 @@ def test_string_to_timestamp_functions_corrected_yyyyMMdd(): @pytest.mark.parametrize('ansi_enabled', [True, False], ids=['ANSI_ON', 'ANSI_OFF']) @pytest.mark.parametrize('operator', exception_policy_operators, ids=idfn) -@pytest.mark.parametrize('input_str,fmt', [ - ("2024-05-06xxx", "yyyy-MM-dd"), - ("20240506xxx", "yyyyMMdd"), -], ids=idfn) -def test_string_to_timestamp_functions_exception_policy_disagreement( - ansi_enabled, operator, input_str, fmt): +def test_string_to_timestamp_functions_exception_policy_disagreement(ansi_enabled, operator): def fun(spark): - return spark.createDataFrame([(input_str,)], "a string") \ - .selectExpr("{}(a, '{}')".format(operator, fmt)) \ + return spark.createDataFrame([("2024-05-06xxx",)], "a string") \ + .selectExpr("{}(a, 'yyyy-MM-dd')".format(operator)) \ .collect() assert_gpu_and_cpu_error( @@ -955,6 +979,37 @@ def test_to_timestamp_yyyyMMdd_extended_year_fallback(parser_policy): 'spark.rapids.sql.hasExtendedYearValues': True, 'spark.rapids.sql.expression.cpuBridge.enabled': False}) + +@disable_ansi_mode +@allow_non_gpu('ProjectExec', 'GetTimestamp') +def test_to_timestamp_yyyyMMdd_exception_policy_fallback(): + conf = { + 'spark.sql.legacy.timeParserPolicy': 'EXCEPTION', + 'spark.rapids.sql.hasExtendedYearValues': False, + 'spark.rapids.sql.expression.cpuBridge.enabled': False, + } + assert_gpu_fallback_collect( + lambda spark: spark.createDataFrame([("20240101",)], "a string") + .selectExpr("to_timestamp(a, 'yyyyMMdd')"), + 'GetTimestamp', + conf) + + +@disable_ansi_mode +@allow_non_gpu('ProjectExec', 'GetTimestamp') +def test_to_timestamp_yyyyMMdd_exception_policy_disagreement(): + assert_gpu_and_cpu_error( + lambda spark: spark.createDataFrame([("2024101",)], "a string") + .selectExpr("to_timestamp(a, 'yyyyMMdd')") + .collect(), + conf={ + 'spark.sql.legacy.timeParserPolicy': 'EXCEPTION', + 'spark.rapids.sql.hasExtendedYearValues': False, + 'spark.rapids.sql.expression.cpuBridge.enabled': False, + }, + error_message="different result") + + @tz_sensitive_test @pytest.mark.parametrize("ansi_enabled", [True, False], ids=['ANSI_ON', 'ANSI_OFF']) def test_to_date(ansi_enabled): @@ -995,7 +1050,7 @@ def test_to_date_ansi_exception(): conf=ansi_enabled_conf) supported_date_formats = ['yyyy-MM-dd', 'yyyy-MM', 'yyyy/MM/dd', 'yyyy/MM', 'dd/MM/yyyy', - 'MM-dd', 'MM/dd', 'dd-MM', 'dd/MM'] + 'MM-dd', 'MM/dd', 'dd-MM', 'dd/MM', 'yyyyMMdd'] @pytest.mark.parametrize('date_format', supported_date_formats, ids=idfn) @pytest.mark.parametrize('data_gen', [date_gen], ids=idfn) @allow_non_gpu('DateFormatClass', 'Cast') diff --git a/sql-plugin/src/main/scala/com/nvidia/spark/rapids/DateUtils.scala b/sql-plugin/src/main/scala/com/nvidia/spark/rapids/DateUtils.scala index 4c7bafa28b8..84f309238d0 100644 --- a/sql-plugin/src/main/scala/com/nvidia/spark/rapids/DateUtils.scala +++ b/sql-plugin/src/main/scala/com/nvidia/spark/rapids/DateUtils.scala @@ -26,7 +26,8 @@ import com.nvidia.spark.rapids.shims.DateTimeUtilsShims import org.apache.spark.sql.catalyst.util.DateTimeUtils.localDateToDays import org.apache.spark.sql.internal.SQLConf -import org.apache.spark.sql.rapids.{GpuToTimestamp, LegacyTimeParserPolicy} +import org.apache.spark.sql.rapids.{ExceptionTimeParserPolicy, GpuToTimestamp, + LegacyTimeParserPolicy} /** * Class for helper functions for Date @@ -228,8 +229,16 @@ object DateUtils { } else { GpuToTimestamp.LEGACY_COMPATIBLE_FORMATS } + val timeParserPolicy = GpuOverrides.getTimeParserPolicy + val nonLegacyCompatibleFormats = if (parseString && + timeParserPolicy == ExceptionTimeParserPolicy) { + GpuToTimestamp.EXCEPTION_COMPATIBLE_FORMATS + } else { + // Formatting does not have parser-policy disagreement, so use the CORRECTED set. + GpuToTimestamp.CORRECTED_COMPATIBLE_FORMATS + } var strfFormat: String = null - if (GpuOverrides.getTimeParserPolicy == LegacyTimeParserPolicy) { + if (timeParserPolicy == LegacyTimeParserPolicy) { try { // try and convert the format to cuDF format - this will throw an exception if // the format contains unsupported characters or words @@ -261,9 +270,9 @@ object DateUtils { // the format contains unsupported characters or words strfFormat = toStrf(formatToConvert, parseString) // format parsed ok, so it is either compatible (tested/certified) or incompatible - if (!GpuToTimestamp.CORRECTED_COMPATIBLE_FORMATS.contains(formatToConvert) && + if (!nonLegacyCompatibleFormats.contains(formatToConvert) && !meta.conf.incompatDateFormats) { - meta.willNotWorkOnGpu(s"CORRECTED format '$sparkFormat' on the GPU is not guaranteed " + + meta.willNotWorkOnGpu(s"Format '$sparkFormat' on the GPU is not guaranteed " + s"to produce the same results as Spark on CPU. Set " + s"${RapidsConf.INCOMPATIBLE_DATE_FORMATS.key}=true to force onto GPU.") } diff --git a/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/datetimeExpressions.scala b/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/datetimeExpressions.scala index fd72683f135..b33bc935e42 100644 --- a/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/datetimeExpressions.scala +++ b/sql-plugin/src/main/scala/org/apache/spark/sql/rapids/datetimeExpressions.scala @@ -603,9 +603,9 @@ object ExceptionTimeParserPolicy extends TimeParserPolicy object CorrectedTimeParserPolicy extends TimeParserPolicy object GpuToTimestamp { - // We are compatible with Spark for these formats when the timeParserPolicy is CORRECTED - // or EXCEPTION. It is possible that other formats may be supported but these are the only - // ones that we have tests for. + // We are compatible with Spark for these formats when the timeParserPolicy is CORRECTED. + // It is possible that other formats may be supported but these are the only ones that we + // have tests for. val CORRECTED_COMPATIBLE_FORMATS = Set( "yyyy-MM-dd", "yyyy/MM/dd", @@ -625,6 +625,10 @@ object GpuToTimestamp { "MMyyyy" ) + // EXCEPTION first tries CORRECTED parsing and then probes LEGACY parsing on failure. Formats + // in this set must therefore match Spark under both parsers, including success/failure behavior. + val EXCEPTION_COMPATIBLE_FORMATS = CORRECTED_COMPATIBLE_FORMATS - "yyyyMMdd" + // We are compatible with Spark for these formats when the timeParserPolicy is LEGACY. It // is possible that other formats may be supported but these are the only ones that we have // tests for. @@ -671,12 +675,13 @@ object GpuToTimestamp { } // True iff the fused JNI parser handles this (sparkFormat, policy) combination. - // Today the JNI accepts every entry in CORRECTED_COMPATIBLE_FORMATS / LEGACY_COMPATIBLE_FORMATS. - private def isSimpleSparkFormat(sparkFormat: String, isLegacy: Boolean): Boolean = { - if (isLegacy) { - LEGACY_COMPATIBLE_FORMATS.contains(sparkFormat) - } else { - CORRECTED_COMPATIBLE_FORMATS.contains(sparkFormat) + private def isSimpleSparkFormat( + sparkFormat: String, + timeParserPolicy: TimeParserPolicy): Boolean = { + timeParserPolicy match { + case LegacyTimeParserPolicy => LEGACY_COMPATIBLE_FORMATS.contains(sparkFormat) + case ExceptionTimeParserPolicy => EXCEPTION_COMPATIBLE_FORMATS.contains(sparkFormat) + case CorrectedTimeParserPolicy => CORRECTED_COMPATIBLE_FORMATS.contains(sparkFormat) } } @@ -722,7 +727,12 @@ object GpuToTimestamp { exceptionPolicy: Boolean): ColumnVector = { // `tsVector` will be closed in replaceSpecialDates - val tsVector = if (isSimpleSparkFormat(sparkFormat, isLegacy = false)) { + val timeParserPolicy = if (exceptionPolicy) { + ExceptionTimeParserPolicy + } else { + CorrectedTimeParserPolicy + } + val tsVector = if (isSimpleSparkFormat(sparkFormat, timeParserPolicy)) { // Fused kernel skips the regex+length+cuDF-asTimestamp chain. val parsed = try { val parserPolicy = if (exceptionPolicy) { @@ -782,7 +792,7 @@ object GpuToTimestamp { def parseStringAsTimestampWithLegacyParserPolicy( lhs: GpuColumnVector, sparkFormat: String): ColumnVector = { - if (!isSimpleSparkFormat(sparkFormat, isLegacy = true)) { + if (!isSimpleSparkFormat(sparkFormat, LegacyTimeParserPolicy)) { throw new IllegalStateException(s"Unsupported format $sparkFormat") } CastStrings.parseTimestampWithFormat(lhs.getBase, sparkFormat, true)