This is an automated email from the ASF dual-hosted git repository.

ppa pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 4c998d7bf04 IGNITE-25317 Sql. Improved Cast with Format validation 
(#5977)
4c998d7bf04 is described below

commit 4c998d7bf043538ea42090f2ca4018f50978183d
Author: Max Zhuravkov <[email protected]>
AuthorDate: Thu Jun 12 10:44:58 2025 +0300

    IGNITE-25317 Sql. Improved Cast with Format validation (#5977)
---
 .../engine/datatypes/ItDateTimeCastFormatTest.java | 249 ++++++++-------------
 .../sql/group1/cast/test_cast_format.test          |  25 ++-
 .../group1/types/date/test_incorrect_dates.test    |   3 +-
 .../types/timestamp/test_incorrect_timestamp.test  |   3 +-
 .../sql/engine/exec/exp/IgniteSqlFunctions.java    |  48 +++-
 .../sql/engine/exec/exp/RexToLixTranslator.java    |  24 +-
 .../internal/sql/engine/util/IgniteMethod.java     |  17 +-
 .../engine/exec/exp/IgniteSqlFunctionsTest.java    |  63 +++++-
 8 files changed, 233 insertions(+), 199 deletions(-)

diff --git 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/ItDateTimeCastFormatTest.java
 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/ItDateTimeCastFormatTest.java
index aacf7077253..ab95de174e9 100644
--- 
a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/ItDateTimeCastFormatTest.java
+++ 
b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/datatypes/ItDateTimeCastFormatTest.java
@@ -28,6 +28,7 @@ import java.time.LocalDateTime;
 import java.time.LocalTime;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -126,37 +127,32 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
     private static Stream<DateTimeArgs<LocalDate>> date() {
         return Stream.of(
                 dateTime("2000-01-01", "yyyy-MM-dd", LocalDate.of(2000, 1, 1), 
null),
-                dateTime("2-01-01", "y-MM-dd", LocalDate.of(2, 1, 1), null),
-                dateTime("02-01-01", "y-MM-dd", LocalDate.of(2002, 1, 1), 
null),
+                dateTime("2-01-01", "y-MM-dd", LocalDate.of(2022, 1, 1), null),
+                dateTime("02-01-01", "y-MM-dd", null, "Invalid format. 
Expected literal <-> but got"),
                 dateTime("20-01-01", "yy-MM-dd", LocalDate.of(2020, 1, 1), 
null),
-                dateTime("020-01-01", "yyy-MM-dd", LocalDate.of(20, 1, 1), 
null),
-                dateTime("002-01-01", "yyy-MM-dd", LocalDate.of(2, 1, 1), 
null),
-                dateTime("200-01-01", "yyy-MM-dd", LocalDate.of(200, 1, 1), 
null),
+                dateTime("020-01-01", "yyy-MM-dd", LocalDate.of(2020, 1, 1), 
null),
+                dateTime("002-01-01", "yyy-MM-dd", LocalDate.of(2002, 1, 1), 
null),
+                dateTime("200-01-01", "yyy-MM-dd", LocalDate.of(2200, 1, 1), 
null),
                 dateTime("20-01-01", "yyyy-MM-dd", LocalDate.of(20, 1, 1), 
null),
                 dateTime("9999-01-01", "yyyy-MM-dd", LocalDate.of(9999, 1, 1), 
null),
 
                 dateTime("2000/01-01", "yyyy/MM-dd", LocalDate.of(2000, 1, 1), 
null),
 
-                dateTime("10000-01-01", "yyyy-MM-dd", null, "DATE out of 
range"),
-                dateTime("10000000-01-01", "yyyy-MM-dd", null, "DATE out of 
range"),
+                dateTime("10000-01-01", "yyyy-MM-dd", null, "Invalid format. 
Expected literal <-> but got"),
+                dateTime("10000000-01-01", "yyyy-MM-dd", null, "Invalid 
format. Expected literal <-> but got"),
 
-                // TODO https://issues.apache.org/jira/browse/IGNITE-25339 
Incorrect parsing of RR/RRRR
-                /*
                 dateTime("01-01-01", "RR-MM-dd", LocalDate.of(2001, 1, 1), 
null),
                 dateTime("33-01-01", "RR-MM-dd", LocalDate.of(2033, 1, 1), 
null),
                 dateTime("49-01-01", "RR-MM-dd", LocalDate.of(2049, 1, 1), 
null),
-                */
+
                 dateTime("51-01-01", "RR-MM-dd", LocalDate.of(1951, 1, 1), 
null),
                 dateTime("77-01-01", "RR-MM-dd", LocalDate.of(1977, 1, 1), 
null),
 
-                // TODO https://issues.apache.org/jira/browse/IGNITE-25339 
Incorrect parsing of RR/RRRR
-                /*
                 dateTime("01-01-01", "RRRR-MM-dd", LocalDate.of(2001, 1, 1), 
null),
                 dateTime("33-01-01", "RRRR-MM-dd", LocalDate.of(2033, 1, 1), 
null),
                 dateTime("49-01-01", "RRRR-MM-dd", LocalDate.of(2049, 1, 1), 
null),
                 dateTime("51-01-01", "RRRR-MM-dd", LocalDate.of(1951, 1, 1), 
null),
                 dateTime("77-01-01", "RRRR-MM-dd", LocalDate.of(1977, 1, 1), 
null),
-                */
 
                 dateTime("2001-01-01", "RRRR-MM-dd", LocalDate.of(2001, 1, 1), 
null),
                 dateTime("2033-01-01", "RRRR-MM-dd", LocalDate.of(2033, 1, 1), 
null),
@@ -164,43 +160,34 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                 dateTime("2051-01-01", "RRRR-MM-dd", LocalDate.of(2051, 1, 1), 
null),
                 dateTime("1951-01-01", "RRRR-MM-dd", LocalDate.of(1951, 1, 1), 
null),
 
-                // TODO https://issues.apache.org/jira/browse/IGNITE-25339 
Incorrect parsing of RR/RRRR
-                /*
                 dateTime("001-01-01", "RRRR-MM-dd", LocalDate.of(2001, 1, 1), 
null),
                 dateTime("1-01-01", "RRRR-MM-dd", LocalDate.of(2001, 1, 1), 
null),
                 dateTime("33-01-01", "RRRR-MM-dd", LocalDate.of(2033, 1, 1), 
null),
                 dateTime("033-01-01", "RRRR-MM-dd", LocalDate.of(2033, 1, 1), 
null),
                 dateTime("51-01-01", "RRRR-MM-dd", LocalDate.of(1951, 1, 1), 
null),
                 dateTime("051-01-01", "RRRR-MM-dd", LocalDate.of(1951, 1, 1), 
null),
-                dateTime("077-01-01", "RRRR-MM-dd", LocalDate.of(1973, 1, 1), 
null),
-                */
+                dateTime("077-01-01", "RRRR-MM-dd", LocalDate.of(1977, 1, 1), 
null),
 
                 dateTime("151-01-01", "RRRR-MM-dd", LocalDate.of(151, 1, 1), 
null),
-                dateTime("177-01-01", "RRRR-MM-dd", LocalDate.of(177, 1, 1), 
null)
-        );
+                dateTime("177-01-01", "RRRR-MM-dd", LocalDate.of(177, 1, 1), 
null),
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25319 parse 
accepts incorrect year, month, day fields.
-        /*
-        dateTime("2000-05-07", "yyyy-MM-dddd", null, "Invalid format"),
-        dateTime("2000-05-07", "yyyy-MM-dddd", null, "Invalid format"),
-        dateTime("2000-5-07", "yyyyy-M-dd", null, "Invalid format"),
-        dateTime("2000-005-07", "yyyyy-MMM-dddd", null, "Invalid format"),
+                dateTime("2000-05-07", "yyyy-MM-dddd", null, "Unexpected 
element <D> in pattern"),
+                dateTime("2000-05-07", "yyyy-MM-dddd", null, "Unexpected 
element <D> in pattern"),
+                dateTime("2000-5-07", "yyyyy-M-dd", null, "Element is already 
present: YEAR"),
+                dateTime("2000-005-07", "yyyyy-MMM-dddd", null, "Element is 
already present: YEAR"),
 
-        dateTime("100-05-07", "R-MM-dd", null, "Invalid format"),
-        dateTime("100-05-07", "RRR-MM-dd", null, "Invalid format"),
-        dateTime("100-05-07", "RRRRR-MM-dd", null, "Invalid format"),
-        dateTime("201-01-01", "RR-MM-dd", null, "Invalid format"),
+                dateTime("100-05-07", "R-MM-dd", null, "Unexpected element <R> 
in pattern"),
+                dateTime("100-05-07", "RRR-MM-dd", null, "Unexpected element 
<R> in pattern"),
+                dateTime("100-05-07", "RRRRR-MM-dd", null, "Unexpected element 
<R> in pattern "),
+                dateTime("201-01-01", "RR-MM-dd", null, "Invalid format. 
Expected literal <-> but got"),
 
-        // Different error for in combination with ff/ff0 TIMESTAMP/ TIMESTAMP 
LTZ: Illegal pattern character 'f'
-        dateTime("2000-005-07", "yyyy-MMM-dd", null, "Invalid format")
-        */
+                // Different error combination with ff/ff0 TIMESTAMP/ 
TIMESTAMP LTZ: Illegal pattern character 'f'
+                dateTime("2000-005-07", "yyyy-MMM-dd", null, "Unexpected 
element <M> in pattern"),
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25010
-        /*
-        dateTime("0-0-0", "yyyy-MM-dd", null, "DATE out of range"),
-        dateTime("0000-01-01", "yyyy-MM-dd", null, "DATE out of range"),
-        dateTime("-01-01-01", "yyyy-MM-dd", null, "DATE out of range")
-        */
+                dateTime("0-0-0", "yyyy-MM-dd", null, "Invalid value for 
Year"),
+                dateTime("0000-01-01", "yyyy-MM-dd", null, "Invalid value for 
Year"),
+                dateTime("-01-01-01", "yyyy-MM-dd", null, "Expected field YYYY 
but got")
+        );
     }
 
     // TIME
@@ -208,24 +195,14 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
     @ParameterizedTest
     @MethodSource("time")
     public void timeLiterals(DateTimeArgs<LocalTime> args) {
-        String sqlCast = format("SELECT CAST('{}' AS TIME FORMAT '{}')", 
args.str, args.format);
-
-        // TIME has 0 precision by default
-        boolean subMillis = args.value != null && args.value.getNano() != 0 && 
args.format.contains("ff");
-        Assumptions.assumeFalse(subMillis);
-
-        checkQuery(sqlCast,  args.value, args.error);
+        String sqlCast = format("SELECT CAST('{}' AS TIME(3) FORMAT '{}')", 
args.str, args.format);
+        checkQuery(sqlCast, args.value, args.error);
     }
 
     @ParameterizedTest
     @MethodSource("time")
     public void timeDynamicParams(DateTimeArgs<LocalTime> args) {
-        String sqlCast = format("SELECT CAST(? AS TIME FORMAT '{}')", 
args.format);
-
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313
-        // Nothing but ff3 works due to SimpleDateFormat
-        Assumptions.assumeTrue(!args.format.contains("ff") || 
args.format.contains("ff3"));
-
+        String sqlCast = format("SELECT CAST(? AS TIME(3) FORMAT '{}')", 
args.format);
         checkQuery(sqlCast, args.value, args.error, args.str);
     }
 
@@ -233,16 +210,12 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
     @MethodSource("time")
     public void timeUpdateFromLiteral(DateTimeArgs<LocalTime> args) {
         String sqlCast = format(
-                "UPDATE datetime_cols SET time0_col=CAST(? AS TIME FORMAT 
'{}') WHERE id = 1",
+                "UPDATE datetime_cols SET time0_col=CAST(? AS TIME(4) FORMAT 
'{}') WHERE id = 1",
                 args.format
         );
 
         checkDml(sqlCast, args.error, args.str);
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313
-        // Nothing but ff3 works due to SimpleDateFormat
-        Assumptions.assumeTrue(!args.format.contains("ff") || 
args.format.contains("ff3"));
-
         if (args.value != null) {
             assertQuery("SELECT time0_col FROM datetime_cols WHERE id = 1")
                     .returns(args.value)
@@ -254,12 +227,13 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
     @MethodSource("time")
     public void timeUpdateFromDynamicParam(DateTimeArgs<LocalTime> args) {
         String sqlCast = format(
-                "UPDATE datetime_cols SET time0_col=CAST('{}' AS TIME FORMAT 
'{}') WHERE id = 1",
+                "UPDATE datetime_cols SET time0_col=CAST('{}' AS TIME(3) 
FORMAT '{}') WHERE id = 1",
                 args.str,
                 args.format
         );
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25045 
Insert/Update RexToLix cast translation bug
+        // TODO https://issues.apache.org/jira/browse/IGNITE-25045
+        // Cast to TIME/TIMESTAMP/TIMESTAMP_LTZ ignores target type's precision
         Assumptions.assumeTrue(args.value == null || args.value.getNano() == 
0);
 
         checkDml(sqlCast, args.error);
@@ -273,19 +247,15 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
 
     private static Stream<DateTimeArgs<LocalTime>> time() {
         return Stream.of(
-                // TODO https://issues.apache.org/jira/browse/IGNITE-25314
-                //  Sql. Cast FORMAT. Parsing of hh/h12 format is incorrect
-                /*
                 dateTime("05:02 a.m.", "hh12:mi a.m.", LocalTime.of(5, 2), 
null),
                 dateTime("11:02 a.m.", "hh12:mi a.m.", LocalTime.of(11, 2), 
null),
                 dateTime("12:02 a.m.", "hh12:mi a.m.", LocalTime.of(0, 2), 
null),
-                dateTime("13:02 a.m.", "hh12:mi a.m.", null, "TIME out of 
range"),
+                dateTime("13:02 a.m.", "hh12:mi a.m.", null, "Invalid value 
for HourAmPm"),
 
                 dateTime("05:02 p.m.", "hh12:mi p.m.", LocalTime.of(17, 2), 
null),
                 dateTime("11:02 p.m.", "hh12:mi p.m.", LocalTime.of(23, 2), 
null),
                 dateTime("12:02 p.m.", "hh12:mi p.m.", LocalTime.of(12, 2), 
null),
-                dateTime("13:02 p.m.", "hh12:mi p.m.", null, "TIME out of 
range"),
-                 */
+                dateTime("13:02 p.m.", "hh12:mi p.m.", null, "Invalid value 
for HourAmPm"),
 
                 // hh24
                 dateTime("12:02:03", "hh24:mi:ss", LocalTime.of(12, 2, 3), 
null),
@@ -297,38 +267,29 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                 dateTime("23:02:03.999", "hh24:mi:ss.ff3", LocalTime.of(23, 2, 
3, 999_000_000), null),
                 dateTime("23:02:03.123", "hh24:mi:ss.ff3", LocalTime.of(23, 2, 
3, 123_000_000), null),
 
-                // TODO https://issues.apache.org/jira/browse/IGNITE-25317 
Sub-millsecond fractional format is broken (SimpleDateFormat)
-                /*
-                dateTime("23:02:03.1234", "hh24:mi:ss.ff3", LocalTime.of(23, 
2, 3, 123_400_000), null),
-                dateTime("23:02:03.1234", "hh24:mi:ss.ff4", LocalTime.of(23, 
2, 3, 123_400_000), null),
-                 */
-
-                // TODO https://issues.apache.org/jira/browse/IGNITE-25313  
(SimpleDateFormat)
-                /*
-                dateTime("24:02:03", "hh24:mi:ss", null, "TIME out of range"),
-                dateTime("123:02:03", "hh24:mi:ss", null, "TIME out of range"),
-                dateTime("23:60:03", "hh24:mi:ss", null, "TIME out of range"),
-                dateTime("23:123:03", "hh24:mi:ss", null, "TIME out of range"),
-                dateTime("23:02:60", "hh24:mi:ss", null, "TIME out of range"),
-                dateTime("23:02:123", "hh24:mi:ss", null, "TIME out of range"),
-                */
-
-                dateTime("22:02:03", "hX:mi:ss", null, "Invalid format"),
-                dateTime("22:02:03", "hh:mX:ss", null, "Invalid format"),
-                dateTime("22:02:03", "hh:mm:sX", null, "Invalid format"),
-
-                dateTime("22:02:03", "hh:mm:ss.ff", null, "Illegal pattern 
character 'f'"),
-                dateTime("22:02:03", "hh:mm:ss.ff0", null, "Illegal pattern 
character 'f'"),
-                dateTime("22:02:03", "hh:mm:ss.ff10", null, "Invalid format"),
-
-                dateTime("23:02:03.123", "hh24:mi:ss", null, "Invalid format")
-        );
+                dateTime("23:02:03.1234", "hh24:mi:ss.ff3", null, "Unexpected 
trailing characters after field FF3"),
+                dateTime("23:02:03.1234", "hh24:mi:ss.ff4", LocalTime.of(23, 
2, 3, 123_000_000), null),
+
+                dateTime("24:02:03", "hh24:mi:ss", null, "Invalid value for 
HourOfDay"),
+                dateTime("123:02:03", "hh24:mi:ss", null, "Invalid format. 
Expected literal <:> but got <3>"),
+                dateTime("23:60:03", "hh24:mi:ss", null, "Invalid value for 
MinuteOfHour"),
+                dateTime("23:123:03", "hh24:mi:ss", null, "Invalid format. 
Expected literal <:> but got <3>"),
+                dateTime("23:02:60", "hh24:mi:ss", null, "Invalid value for 
SecondOfMinute"),
+                dateTime("23:02:123", "hh24:mi:ss", null, "Unexpected trailing 
characters after field SS"),
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25315 Max length 
of a fractional part is ignored
-        /*
-        dateTime("23:02:03.12", "hh24:mi:ss.ff3", null, "Invalid format"),
-        dateTime("23:02:03.1234", "hh24:mi:ss.ff3", null, "Invalid format")
-        */
+                dateTime("22:02:03", "hX:mi:ss", null, "Unexpected element 
<HX> in pattern"),
+                dateTime("22:02:03", "hh:mX:ss", null, "Unexpected element 
<MX> in pattern"),
+                dateTime("22:02:03", "hh:mi:sX", null, "Unexpected element 
<SX> in pattern"),
+                dateTime("22:02:03", "hh:mm:ss", null, "Illegal field <MM> for 
format TIME"),
+
+                dateTime("22:02:03", "hh:mi:ss.ff", null, "Unexpected element 
<FF> in pattern"),
+                dateTime("22:02:03", "hh:mi:ss.ff0", null, "Unexpected element 
<FF0> in pattern"),
+                dateTime("22:02:03", "hh:mi:ss.ff10", null, "Unexpected 
character <0> in pattern"),
+
+                dateTime("23:02:03.123", "hh24:mi:ss", null, "Unexpected 
trailing characters after field SS"),
+                dateTime("23:02:03.12", "hh24:mi:ss.ff3",  LocalTime.of(23, 2, 
3, 120_000_000), null),
+                dateTime("23:02:03.1234", "hh24:mi:ss.ff3", null, "Unexpected 
trailing characters after field FF3")
+        );
     }
 
     @ParameterizedTest
@@ -336,7 +297,7 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
     public void timeWithPrecisionLiterals(int precision, 
DateTimeArgs<LocalTime> args) {
         String sqlCast = format("SELECT CAST('{}' AS TIME({}) FORMAT '{}')", 
args.str, precision, args.format);
 
-        checkQuery(sqlCast,  args.value, args.error);
+        checkQuery(sqlCast, args.value, args.error);
     }
 
     // Cast to TIME/TIMESTAMP/TIMESTAMP_LTZ ignores target type's precision
@@ -355,7 +316,7 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
         String col = format("time{}_col", precision);
 
         String sqlCast = format(
-                "UPDATE datetime_cols SET {}=CAST(? AS TIME FORMAT '{}') WHERE 
id = 1",
+                "UPDATE datetime_cols SET {}=CAST(? AS TIME(3) FORMAT '{}') 
WHERE id = 1",
                 col, args.format
         );
 
@@ -377,16 +338,17 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
     public void timeWithPrecisionUpdateFromDynamicParam(int precision, 
DateTimeArgs<LocalTime> args) {
         String col = format("time{}_col", precision);
 
+        // Use TIME(3) to preserve fractional part
         String sqlCast = format(
-                "UPDATE datetime_cols SET {}=CAST('{}' AS TIME FORMAT '{}') 
WHERE id = 1",
+                "UPDATE datetime_cols SET {}=CAST('{}' AS TIME(3) FORMAT '{}') 
WHERE id = 1",
                 col,
                 args.str,
                 args.format
         );
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313 confusing 
submillis parsing
-        boolean subMillis = args.value != null && args.value.getNano() != 0 && 
args.format.contains("ff");
-        Assumptions.assumeFalse(subMillis);
+        // TODO https://issues.apache.org/jira/browse/IGNITE-25045
+        // Cast to TIME/TIMESTAMP/TIMESTAMP_LTZ ignores target type's precision
+        Assumptions.assumeTrue(precision == 3);
 
         checkDml(sqlCast, args.error);
 
@@ -399,7 +361,6 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
 
     private static Stream<Arguments> timeWithPrecision() {
         return Stream.of(
-                /* TODO https://issues.apache.org/jira/browse/IGNITE-25313 
CAST FORMAT confusing behaviour when translating milliseconds
                 // FF1
 
                 Arguments.of(0,
@@ -421,7 +382,6 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                         dateTime("15:32:17.12", "hh24:mi:ss.ff2", 
LocalTime.of(15, 32, 17).withNano(120_000_000), null)),
                 Arguments.of(3,
                         dateTime("15:32:17.12", "hh24:mi:ss.ff2", 
LocalTime.of(15, 32, 17).withNano(120_000_000), null)),
-                 */
 
                 // FF3
                 Arguments.of(0,
@@ -451,7 +411,7 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                         dateTime("15:32:17.500", "hh24:mi:ss.ff3", 
LocalTime.of(15, 32, 17).withNano(500_000_000), null)),
                 Arguments.of(3,
                         dateTime("15:32:17.999", "hh24:mi:ss.ff3", 
LocalTime.of(15, 32, 17).withNano(999_000_000), null))
-                );
+        );
     }
 
     // TIMESTAMP
@@ -461,10 +421,6 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
     public void timestampLiterals(DateTimeArgs<LocalDateTime> args) {
         String sqlCast = format("SELECT CAST('{}' AS TIMESTAMP FORMAT '{}')", 
args.str, args.format);
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313 confusing 
submills parsing
-        boolean subMillis = args.value != null && args.value.getNano() != 0 && 
args.format.contains("ff");
-        Assumptions.assumeFalse(subMillis);
-
         checkQuery(sqlCast, args.value, args.error);
     }
 
@@ -482,22 +438,19 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                 if (d.value != null && t.value != null) {
                     LocalDateTime tsExpected = LocalDateTime.of(d.value, 
t.value);
                     result.add(dateTime(tsStr, tsFmt, tsExpected, null));
-                } else if (isFormatError(d.error)) {
-                    result.add(dateTime(tsStr, tsFmt, null, d.error));
-                } else if (isFormatError(t.error)) {
-                    result.add(dateTime(tsStr, tsFmt, null, t.error));
                 } else {
-                    // TIMESTAMP out of range
-                    result.add(dateTime(tsStr, tsFmt, null, "TIMESTAMP out of 
range"));
+                    result.add(dateTime(tsStr, tsFmt, null, " "));
                 }
             }
         }
 
-        return result.stream();
-    }
+        result.add(new DateTimeArgs<>("2025-10-02 22:15 +02:30", "YYYY-MM-DD 
HH24:MI TZH:TZM",
+                LocalDateTime.of(2025, 10, 2, 19, 45), null));
 
-    private static boolean isFormatError(@Nullable String message) {
-        return message != null && (message.contains("Invalid format") || 
message.contains("Illegal pattern character"));
+        result.add(new DateTimeArgs<>("2025-10-02 22:15 -02:30", "YYYY-MM-DD 
HH24:MI TZH:TZM",
+                LocalDateTime.of(2025, 10, 3, 0, 45), null));
+
+        return result.stream();
     }
 
     @ParameterizedTest
@@ -508,14 +461,17 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                 args.format
         );
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313 confusing 
submills parsing
-        Assumptions.assumeTrue(args.value == null || 
!args.format.contains("ff2"));
+        // TODO https://issues.apache.org/jira/browse/IGNITE-25045
+        // Cast to TIME/TIMESTAMP/TIMESTAMP_LTZ ignores target type's precision
+        boolean subMillis = args.value != null && args.value.getNano() != 0 && 
args.format.contains("ff");
+        Assumptions.assumeFalse(subMillis);
 
         checkDml(sqlCast, args.error, args.str);
 
         if (args.value != null) {
             assertQuery("SELECT timestamp0_col FROM datetime_cols WHERE id = 
1")
-                    .returns(args.value)
+                    // We are writing to timestamp_0, so we should expect a 
timestamp w/o a fractional part.
+                    .returns(args.value.withNano(0))
                     .check();
         }
     }
@@ -528,17 +484,12 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                 args.str, args.format
         );
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313
-        // Nothing but ff3 works due to SimpleDateFormat
-        Assumptions.assumeTrue(!args.format.contains("ff"));
-        // TODO https://issues.apache.org/jira/browse/IGNITE-24889
-        // FF3 does not work due to cast transaction error
-
         checkDml(sqlCast, args.error);
 
         if (args.value != null) {
             assertQuery("SELECT timestamp0_col FROM datetime_cols WHERE id = 
1")
-                    .returns(args.value)
+                    // We are writing to timestamp_0, so we should expect a 
timestamp w/o a fractional part.
+                    .returns(args.value.withNano(0))
                     .check();
         }
     }
@@ -551,9 +502,8 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
         checkQuery(sqlCast, args.value, args.error);
     }
 
-    // TODO https://issues.apache.org/jira/browse/IGNITE-25313 
SimpleDateFormat problems
-    // Cast translation errors
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-24889";)
+    // Cast to TIME/TIMESTAMP/TIMESTAMP_LTZ ignores target type's precision
+    @Disabled("https://issues.apache.org/jira/browse/IGNITE-25045";)
     @ParameterizedTest
     @MethodSource("timestampWithPrecision")
     public void timestampWithPrecisionUpdateFromLiteral(int precision, 
DateTimeArgs<LocalDateTime> args) {
@@ -595,7 +545,6 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
     private static Stream<Arguments> timestampWithPrecision() {
         LocalDate date = LocalDate.of(2020, 2, 5);
         return Stream.of(
-                /* TODO https://issues.apache.org/jira/browse/IGNITE-25313 
CAST FORMAT confusing behaviour when translating milliseconds
                 // FF1
                 Arguments.of(0,
                         dateTime("2020-02-05 15:32:17.1", "yyyy-MM-dd 
hh24:mi:ss.ff1",
@@ -625,8 +574,6 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                         dateTime("2020-02-05 15:32:17.12", "yyyy-MM-dd 
hh24:mi:ss.ff2",
                                 LocalDateTime.of(date, LocalTime.of(15, 32, 
17).withNano(120_000_000)), null)),
 
-                 */
-
                 // FF3
 
                 Arguments.of(0,
@@ -681,10 +628,6 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                 args.str, args.format
         );
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313 confusing 
submillis parsing
-        boolean subMillis = args.value != null && args.value.getNano() != 0 && 
args.format.contains("ff");
-        Assumptions.assumeFalse(subMillis);
-
         checkQuery(sqlCast, args.value, args.error);
     }
 
@@ -697,15 +640,11 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                 args.format
         );
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313 confusing 
submillis parsing
-        boolean subMillis = args.value != null && args.value.getNano() != 0 && 
args.format.contains("ff");
-        Assumptions.assumeFalse(subMillis);
-
         checkDml(sqlCast, args.error, args.str);
 
         if (args.value != null) {
             assertQuery("SELECT timestamp_with_local_time_zone0_col FROM 
datetime_cols WHERE id = 1")
-                    .returns(args.value)
+                    .returns(args.value.truncatedTo(ChronoUnit.MILLIS))
                     .check();
         }
     }
@@ -719,15 +658,11 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
                 args.str, args.format
         );
 
-        // TODO https://issues.apache.org/jira/browse/IGNITE-25313 confusing 
submillis parsing
-        boolean subMillis = args.value != null && args.value.getNano() != 0 && 
args.format.contains("ff");
-        Assumptions.assumeFalse(subMillis);
-
         checkDml(sqlCast, args.error);
 
         if (args.value != null) {
             assertQuery("SELECT timestamp_with_local_time_zone0_col FROM 
datetime_cols WHERE id = 1")
-                    .returns(args.value)
+                    .returns(args.value.truncatedTo(ChronoUnit.MILLIS))
                     .check();
         }
     }
@@ -737,17 +672,14 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
             if (dt.value != null) {
                 Instant expectedInstant = ZonedDateTime.of(dt.value, 
TIME_ZONE_ID).toInstant();
                 return dateTime(dt.str, dt.format, expectedInstant, null);
-            } else if (dt.error != null && dt.error.contains("out of range")) {
-                // TIMESTAMP_WITH_LOCAL_TIME_ZONE out of range
-                return dateTime(dt.str, dt.format, null, 
"TIMESTAMP_WITH_LOCAL_TIME_ZONE out of range");
             } else {
-                return dateTime(dt.str, dt.format, null, dt.error);
+                return dateTime(dt.str, dt.format, null, " ");
             }
         });
     }
 
-    // CAST FORMAT confusing behaviour when translating milliseconds
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-25313";)
+    // Cast to TIME/TIMESTAMP/TIMESTAMP_LTZ ignores target type's precision
+    @Disabled("https://issues.apache.org/jira/browse/IGNITE-25045";)
     @ParameterizedTest
     @MethodSource("timestampLtzWithPrecision")
     public void timestampLtzWithPrecisionLiterals(int precision, 
DateTimeArgs<Instant> args) {
@@ -759,8 +691,8 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
         checkQuery(sqlCast, args.value, args.error);
     }
 
-    // CAST FORMAT confusing behaviour when translating milliseconds
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-25313";)
+    // Cast to TIME/TIMESTAMP/TIMESTAMP_LTZ ignores target type's precision
+    @Disabled("https://issues.apache.org/jira/browse/IGNITE-25045";)
     @ParameterizedTest
     @MethodSource("timestampLtzWithPrecision")
     public void timestampLtzWithPrecisionUpdateFromLiteral(int precision, 
DateTimeArgs<Instant> args) {
@@ -781,9 +713,8 @@ public class ItDateTimeCastFormatTest extends 
BaseSqlIntegrationTest {
         }
     }
 
-    // CAST FORMAT confusing behaviour when translating milliseconds
-    // TODO https://issues.apache.org/jira/browse/IGNITE-25045
-    @Disabled("https://issues.apache.org/jira/browse/IGNITE-25313";)
+    // Cast to TIME/TIMESTAMP/TIMESTAMP_LTZ ignores target type's precision
+    @Disabled("https://issues.apache.org/jira/browse/IGNITE-25045";)
     @ParameterizedTest
     @MethodSource("timestampLtzWithPrecision")
     public void timestampLtzWithPrecisionUpdateFromDynamicParam(int precision, 
DateTimeArgs<Instant> args) {
diff --git 
a/modules/sql-engine/src/integrationTest/sql/group1/cast/test_cast_format.test 
b/modules/sql-engine/src/integrationTest/sql/group1/cast/test_cast_format.test
index 77810266afb..7553fee7c0e 100644
--- 
a/modules/sql-engine/src/integrationTest/sql/group1/cast/test_cast_format.test
+++ 
b/modules/sql-engine/src/integrationTest/sql/group1/cast/test_cast_format.test
@@ -162,15 +162,21 @@ SELECT cast('18-12-03' as date format 'YY-MM-DD')
 ----
 2018-12-03
 
-query T
+statement error: Unexpected element <MON>
 SELECT cast('JUN 30, 2018' as date format 'MON DD, YYYY')
+
+statement error: Invalid format. Expected both fields: 12-hour / am pm
+SELECT cast('17:30' as time format 'HH12:MI')
+
+query T
+SELECT cast('07:30 A.M.' as time format 'HH12:MI A.M.')
 ----
-2018-06-30
+07:30:00
 
 query T
-SELECT cast('17:30' as time format 'HH12:MI')
+SELECT cast('07:30 P.M.' as time format 'HH12:MI P.M.')
 ----
-17:30:00
+19:30:00
 
 query T
 SELECT cast('01:05:07.161' as time format 'HH24:MI:SS.FF4')
@@ -183,17 +189,14 @@ SELECT cast('2017-05-12' as timestamp format 'YYYY-MM-DD')
 2017-05-12 00:00:00
 
 query T
-SELECT cast('2020.06.03 12:42:53' as timestamp format 'YYYY.MM.DD HH:MI:SS')
+SELECT cast('2020.06.03 12:42:53' as timestamp format 'YYYY.MM.DD HH24:MI:SS')
 ----
 2020-06-03 12:42:53
 
-# Seems will be supported after resolve CALCITE_6367
-statement error: Invalid format: 'YYYY.MM.DD HH24:MI:SSTZH:TZM' for datetime 
string: '2020.06.03 00:00:53+06:30'
+query T
 SELECT cast('2020.06.03 00:00:53+06:30' as timestamp format 'YYYY.MM.DD 
HH24:MI:SSTZH:TZM')
-
-# Seems will be supported after resolve CALCITE_6367
-statement error: Invalid format: 'HH:MI P.M.' for datetime string: '03:30 P.M.'
-SELECT cast('03:30 P.M.' as time format 'HH:MI P.M.')
+----
+2020-06-02 17:30:53
 
 # Seems will be supported after resolve CALCITE_6270
 statement error: Cast function cannot convert value of type BINARY(5) to type 
VARCHAR
diff --git 
a/modules/sql-engine/src/integrationTest/sql/group1/types/date/test_incorrect_dates.test
 
b/modules/sql-engine/src/integrationTest/sql/group1/types/date/test_incorrect_dates.test
index e4190a390c3..df927b9a9c2 100644
--- 
a/modules/sql-engine/src/integrationTest/sql/group1/types/date/test_incorrect_dates.test
+++ 
b/modules/sql-engine/src/integrationTest/sql/group1/types/date/test_incorrect_dates.test
@@ -100,8 +100,7 @@ INSERT INTO dates VALUES (date '10000-01-01')
 statement error: Invalid DATE value, '10000-00-01'
 INSERT INTO dates VALUES ('10000-00-01'::DATE)
 
-# TODO https://issues.apache.org/jira/browse/IGNITE-25010 This should be 
parser error
-statement error: DATE out of range
+statement error: Invalid value for MonthOfYear
 INSERT INTO dates VALUES (CAST('9999-99-99' AS DATE FORMAT 'YYYY-MM-DD'))
 
 # The value is less than the minimum allowed
diff --git 
a/modules/sql-engine/src/integrationTest/sql/group1/types/timestamp/test_incorrect_timestamp.test
 
b/modules/sql-engine/src/integrationTest/sql/group1/types/timestamp/test_incorrect_timestamp.test
index f4ce68f0b4e..7d2f3c16f39 100644
--- 
a/modules/sql-engine/src/integrationTest/sql/group1/types/timestamp/test_incorrect_timestamp.test
+++ 
b/modules/sql-engine/src/integrationTest/sql/group1/types/timestamp/test_incorrect_timestamp.test
@@ -106,8 +106,7 @@ INSERT INTO timestamp_t VALUES (timestamp '10000-01-01 
01:01:01')
 statement error: Timestamp literal 'TIMESTAMP '10000-01-01'' out of range.
 INSERT INTO timestamp_t VALUES (timestamp '10000-01-01')
 
-# TODO https://issues.apache.org/jira/browse/IGNITE-25010 This should be 
parser error
-statement error: TIMESTAMP out of range
+statement error: Invalid value for MonthOfYear
 INSERT INTO timestamp_t VALUES (CAST('9999-99-99' AS TIMESTAMP FORMAT 
'YYYY-MM-DD'))
 
 statement error: Invalid DATE value, '10000-00-01 01:01:01'
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctions.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctions.java
index 7fbeeb7a0b8..9dae4b05b17 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctions.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctions.java
@@ -25,7 +25,11 @@ import static 
org.apache.ignite.lang.ErrorGroups.Sql.RUNTIME_ERR;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.math.RoundingMode;
+import java.sql.Date;
 import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.time.ZoneOffset;
 import java.time.temporal.ChronoUnit;
 import java.time.zone.ZoneRules;
@@ -35,12 +39,12 @@ import java.util.UUID;
 import org.apache.calcite.avatica.util.ByteString;
 import org.apache.calcite.linq4j.function.NonDeterministic;
 import org.apache.calcite.runtime.SqlFunctions;
-import org.apache.calcite.runtime.SqlFunctions.DateParseFunction;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.ignite.internal.schema.SchemaUtils;
 import org.apache.ignite.internal.sql.engine.util.Commons;
 import org.apache.ignite.internal.sql.engine.util.IgniteMath;
 import org.apache.ignite.internal.sql.engine.util.TypeUtils;
+import org.apache.ignite.internal.sql.engine.util.format.SqlDateTimeParser;
 import org.apache.ignite.sql.ColumnType;
 import org.apache.ignite.sql.SqlException;
 import org.jetbrains.annotations.Nullable;
@@ -57,6 +61,8 @@ public class IgniteSqlFunctions {
 
     private static final int DATE_MIN_INTERNAL = (int) 
TypeUtils.toInternal(SchemaUtils.DATE_MIN, ColumnType.DATE);
     private static final int DATE_MAX_INTERNAL = (int) 
TypeUtils.toInternal(SchemaUtils.DATE_MAX, ColumnType.DATE);
+    /** java.sql.Time is stored as the number of milliseconds since 1970/01/01 
*/
+    private static final LocalDate JAVA_SQL_TIME_DATE = LocalDate.of(1970, 1, 
1);
 
     /**
      * Default constructor.
@@ -560,9 +566,8 @@ public class IgniteSqlFunctions {
         Objects.requireNonNull(timeZone, "timeZone");
 
         // TODO https://issues.apache.org/jira/browse/IGNITE-25320 reuse to 
improve performance.
-        DateParseFunction function = new DateParseFunction();
-        long ts = function.parseTimestamp(format, v);
-        Instant instant = Instant.ofEpochMilli(ts);
+        LocalDateTime dateTime = 
SqlDateTimeParser.timestampFormatter(format).parseTimestamp(v);
+        Instant instant = dateTime.toInstant(ZoneOffset.UTC);
 
         // Adjust instant millis
         ZoneRules rules = timeZone.toZoneId().getRules();
@@ -571,6 +576,41 @@ public class IgniteSqlFunctions {
         return adjusted.toEpochMilli();
     }
 
+    /** Converts a date string into a date value. */
+    public static @Nullable Integer toDate(@Nullable String v, String format) {
+        if (v == null) {
+            return null;
+        }
+
+        // TODO https://issues.apache.org/jira/browse/IGNITE-25320 reuse to 
improve performance.
+        LocalDate date = SqlDateTimeParser.dateFormatter(format).parseDate(v);
+        return SqlFunctions.toInt(Date.valueOf(date));
+    }
+
+    /** Converts a time string into a time value. */
+    public static @Nullable Integer toTime(@Nullable String v, String format) {
+        if (v == null) {
+            return null;
+        }
+
+        // TODO https://issues.apache.org/jira/browse/IGNITE-25320 reuse to 
improve performance.
+        LocalTime time = SqlDateTimeParser.timeFormatter(format).parseTime(v);
+        Instant instant = 
time.atDate(JAVA_SQL_TIME_DATE).toInstant(ZoneOffset.UTC);
+        return (int) instant.toEpochMilli();
+    }
+
+    /** Converts a timestamp string into a timestamp value. */
+    public static @Nullable Long toTimestamp(@Nullable String v, String 
format) {
+        if (v == null) {
+            return null;
+        }
+
+        // TODO https://issues.apache.org/jira/browse/IGNITE-25320 reuse to 
improve performance.
+        LocalDateTime ts = 
SqlDateTimeParser.timestampFormatter(format).parseTimestamp(v);
+        Instant instant = ts.toInstant(ZoneOffset.UTC);
+        return instant.toEpochMilli();
+    }
+
     private static @Nullable Object leastOrGreatest(boolean least, Object 
arg0, Object arg1) {
         if (arg0 == null || arg1 == null) {
             return null;
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
index 395347a4bce..5e7faeba382 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java
@@ -117,6 +117,8 @@ import org.locationtech.jts.geom.Geometry;
  *      Removed original casts to numeric types and used own 
ConverterUtils.convert
  *      Added pad-truncate from CHARACTER to INTERVAL types
  *      Added time-zone dependency for cast from CHARACTER types to TIMESTAMP 
WITH LOCAL TIMEZONE (see point 3)
+ *      Cast VARCHAR to TIME is updated to use our implementation (see 
IgniteMethod.TIME_STRING_TO_TIME).
+ *      Cast VARCHAR to DATE is updated to use our implementation (see 
IgniteMethod.DATE_STRING_TO_DATE).
  *      Cast TIMESTAMP to TIMESTAMP WITH LOCAL TIMEZONE use our 
implementation, see IgniteMethod.UNIX_TIMESTAMP_TO_STRING_PRECISION_AWARE
  *      Cast TIMESTAMP LTZ accepts FORMAT. (See 
IgniteMethod.TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE).
  * 6. Translate literals changes:
@@ -612,16 +614,7 @@ public class RexToLixTranslator implements 
RexVisitor<RexToLixTranslator.Result>
       // If format string is supplied, parse formatted string into date
       return Expressions.isConstantNull(format)
               ? Expressions.call(BuiltInMethod.STRING_TO_DATE.method, operand)
-              : Expressions.call(
-                      // TODO 
https://issues.apache.org/jira/browse/IGNITE-25010 Remove redundant call to 
TO_DATE_EXACT
-                      IgniteMethod.TO_DATE_EXACT.method(),
-                      Expressions.call(
-                              
Expressions.new_(BuiltInMethod.PARSE_DATE.method.getDeclaringClass()),
-                              BuiltInMethod.PARSE_DATE.method,
-                              format,
-                              operand
-                      )
-              );
+              : Expressions.call(IgniteMethod.DATE_STRING_TO_DATE.method(), 
operand, format);
 
     case TIMESTAMP:
       return
@@ -652,8 +645,7 @@ public class RexToLixTranslator implements 
RexVisitor<RexToLixTranslator.Result>
       // If format string is supplied, parse formatted string into time
       return Expressions.isConstantNull(format)
           ? Expressions.call(IgniteMethod.STRING_TO_TIME.method(), operand)
-          : 
Expressions.call(Expressions.new_(BuiltInMethod.PARSE_TIME.method.getDeclaringClass()),
-              BuiltInMethod.PARSE_TIME.method, format, operand);
+          : Expressions.call(IgniteMethod.TIME_STRING_TO_TIME.method(), 
operand, format);
 
     case TIME_WITH_LOCAL_TIME_ZONE:
       return
@@ -733,13 +725,7 @@ public class RexToLixTranslator implements 
RexVisitor<RexToLixTranslator.Result>
       // If format string is supplied, parse formatted string into timestamp
       return Expressions.isConstantNull(format)
           ? Expressions.call(IgniteMethod.TO_TIMESTAMP_EXACT.method(), 
Expressions.call(IgniteMethod.STRING_TO_TIMESTAMP.method(), operand))
-          : Expressions.call(
-                  IgniteMethod.TO_TIMESTAMP_EXACT.method(),
-                  Expressions.call(
-                    
Expressions.new_(BuiltInMethod.PARSE_TIMESTAMP.method.getDeclaringClass()),
-                    BuiltInMethod.PARSE_TIMESTAMP.method, format, operand
-                  )
-          );
+          : 
Expressions.call(IgniteMethod.TIMESTAMP_STRING_TO_TIMESTAMP.method(), operand, 
format);
 
     case DATE:
       return
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMethod.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMethod.java
index 831882cd3b3..b2b92e1d458 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMethod.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/util/IgniteMethod.java
@@ -151,7 +151,22 @@ public enum IgniteMethod {
     CURRENT_DATE(IgniteSqlDateTimeUtils.class, "currentDate", 
DataContext.class),
 
     /**
-     * SQL CAST(? AS TIMESTAMP WITH LOCAL TIME ZONE FORMAT {@code format}). 
The same as
+     * SQL CAST({@code varchar} AS TIME FORMAT {@code format}).
+     */
+    TIME_STRING_TO_TIME(IgniteSqlFunctions.class, "toTime", String.class, 
String.class),
+
+    /**
+     * SQL CAST({@code varchar} AS DATE FORMAT {@code format}).
+     */
+    DATE_STRING_TO_DATE(IgniteSqlFunctions.class, "toDate", String.class, 
String.class),
+
+    /**
+     * SQL CAST({@code varchar} AS TIMESTAMP FORMAT {@code format}).
+     */
+    TIMESTAMP_STRING_TO_TIMESTAMP(IgniteSqlFunctions.class, "toTimestamp", 
String.class, String.class),
+
+    /**
+     * SQL CAST({@code varchar} AS TIMESTAMP WITH LOCAL TIME ZONE FORMAT 
{@code format}). The same as
      * {@link SqlFunctions#timeWithLocalTimeZoneToTimestampWithLocalTimeZone} 
but accepts date format literal.
      */
     
TIMESTAMP_STRING_TO_TIMESTAMP_WITH_LOCAL_TIME_ZONE(IgniteSqlFunctions.class,
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctionsTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctionsTest.java
index c74f8facbfc..0936c2c35f9 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctionsTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/exp/IgniteSqlFunctionsTest.java
@@ -33,6 +33,7 @@ import java.util.TimeZone;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 import org.apache.calcite.runtime.SqlFunctions;
+import org.apache.calcite.runtime.SqlFunctions.DateParseFunction;
 import org.apache.ignite.internal.sql.engine.util.IgniteMath;
 import org.apache.ignite.lang.ErrorGroups.Sql;
 import org.jetbrains.annotations.Nullable;
@@ -515,7 +516,7 @@ public class IgniteSqlFunctionsTest {
 
         TimeZone timeZone = TimeZone.getTimeZone(zoneId);
         long calciteTsLtz = SqlFunctions.toTimestampWithLocalTimeZone(v, 
timeZone);
-        long tsLtz = IgniteSqlFunctions.toTimestampWithLocalTimeZone(v, 
"yyyy-MM-dd hh:mi:ss.ff3", timeZone);
+        long tsLtz = IgniteSqlFunctions.toTimestampWithLocalTimeZone(v, 
"yyyy-MM-dd hh24:mi:ss.ff3", timeZone);
 
         assertEquals(Instant.ofEpochMilli(calciteTsLtz), 
Instant.ofEpochMilli(tsLtz));
     }
@@ -548,4 +549,64 @@ public class IgniteSqlFunctionsTest {
 
         return zones.stream().flatMap(z -> times.stream().map(t -> 
Arguments.of(z, t)));
     }
+
+    @ParameterizedTest
+    @MethodSource("timeValues")
+    public void testToTime(String timeStr, int expectedMillis) {
+
+        DateParseFunction f = new DateParseFunction();
+        int millis = f.parseTime("HH:mi:SS", timeStr);
+        int time2 = IgniteSqlFunctions.toTime(timeStr, "HH24:MI:SS");
+
+        assertEquals(expectedMillis, millis);
+        assertEquals(millis, time2);
+    }
+
+    private static Stream<Arguments> timeValues() {
+        return Stream.of(
+                Arguments.of("00:00:00", 0),
+                Arguments.of("01:01:43", 3703000),
+                Arguments.of("07:37:59", 27479000),
+                Arguments.of("19:01:32", 68492000),
+                Arguments.of("23:59:59", 86399000)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("dateValues")
+    public void testToDate(String timeStr, int expectedDays) {
+
+        DateParseFunction f = new DateParseFunction();
+        int days = f.parseDate("YYYY-MM-DD", timeStr);
+        int days2 = IgniteSqlFunctions.toDate(timeStr, "YYYY-MM-DD");
+
+        assertEquals(expectedDays, days);
+        assertEquals(days, days2);
+    }
+
+    private static Stream<Arguments> dateValues() {
+        return Stream.of(
+                Arguments.of("1970-01-01", 0),
+                Arguments.of("2025-01-01", 20089)
+        );
+    }
+
+    @ParameterizedTest
+    @MethodSource("timestampValues")
+    public void testToTimestamp(String timeStr, long expectedTs) {
+
+        DateParseFunction f = new DateParseFunction();
+        long ts = f.parseTimestamp("YYYY-MM-DD", timeStr);
+        Long ts2 = IgniteSqlFunctions.toTimestamp(timeStr, "YYYY-MM-DD");
+
+        assertEquals(expectedTs, ts);
+        assertEquals(ts, ts2);
+    }
+
+    private static Stream<Arguments> timestampValues() {
+        return Stream.of(
+                Arguments.of("1970-01-01", 0),
+                Arguments.of("2025-01-01", 1735689600000L)
+        );
+    }
 }


Reply via email to