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

MaxGekk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 405e9846ff9a [SPARK-57618][SQL] Support casting between TIME(p) and 
TIMESTAMP_NTZ(q)
405e9846ff9a is described below

commit 405e9846ff9a719a3151eb7824622834e6ea087d
Author: Maxim Gekk <[email protected]>
AuthorDate: Wed Jun 24 10:40:55 2026 +0200

    [SPARK-57618][SQL] Support casting between TIME(p) and TIMESTAMP_NTZ(q)
    
    ### What changes were proposed in this pull request?
    
    This PR adds bidirectional casts between the `TIME(p)` data type (`p` in 
`[0, 9]`) and `TIMESTAMP_NTZ(q)` (`q` in `[6, 9]`, where `q=6` is the 
microsecond `TimestampNTZType` and `q` in `[7, 9]` is the nanosecond 
`TimestampNTZNanosType`).
    
    Semantics follow the SQL standard (section 6.13 `<cast specification>`):
    - `CAST(TIMESTAMP_NTZ(q) AS TIME(p))` (rule 15.d): extracts the 
hour/minute/second and fractional fields and truncates to precision `p`. 
Deterministic and time-zone independent.
    - `CAST(TIME(p) AS TIMESTAMP_NTZ(q))` (rule 17.c): the date fields come 
from `CURRENT_DATE` and the time fields from the value. Since `CURRENT_DATE` is 
stable within a query, the cast is stabilized via the existing 
`ComputeCurrentTime` optimizer rule, so it shares the same date literal as 
`current_date()`.
    
    Fractional precision handling is pure truncation (floor toward the 
precision step; no rounding). Both directions always succeed, so no new 
nullability or error condition is introduced.
    
    Implementation notes:
    - New rule-table entries in `Cast.canCast` / `Cast.canAnsiCast` for the 
four pairs, restricted to the NTZ family (`TIMESTAMP_LTZ` is intentionally not 
a valid counterpart). `canTryCast` inherits these for atomic types.
    - Interpreted and codegen paths for both directions.
    - `TIME -> TIMESTAMP_NTZ` is marked `needsTimeZone` (its date fields come 
from `CURRENT_DATE`). `ComputeCurrentTime` scans `CAST` nodes directly and, 
applying the precise `Cast.isTimeToTimestampNTZ` predicate on the resolved 
plan, rewrites it into a date+time builder (`makeTimestampNTZ` / new internal 
`MakeTimestampNTZNanos`) anchored on the query current date. These casts are 
intentionally *not* tagged with the `CURRENT_LIKE` tree pattern: inline-table 
validation treats `CURRENT_LIKE [...]
    - New helpers: `SparkDateTimeUtils.timestampNTZToNanosOfDay` / 
`timestampNTZNanosToNanosOfDay` and `DateTimeUtils.makeTimestampNTZNanos`.
    
    Out of scope: Structured Streaming batch-timestamp parity for `TIME -> 
TIMESTAMP_NTZ` (the cast uses the optimizer-instant current date rather than 
the micro-batch timestamp).
    
    ### Why are the changes needed?
    
    Spark already supports `TIME` casts to/from `STRING`, integral, and 
`DECIMAL` types, but there was no way to convert between `TIME` and 
`TIMESTAMP_NTZ`. These conversions are required by the SQL standard and are a 
common user need (attaching a time-of-day to a timestamp, or extracting the 
time-of-day from a timestamp). This is a sub-task of SPARK-56822 (timestamps 
with nanosecond precision).
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes. Casting between `TIME(p)` and `TIMESTAMP_NTZ(q)` is now allowed 
(previously it failed analysis with a cast type-mismatch). Examples:
    
    ```sql
    -- extract the time-of-day
    SELECT CAST(TIMESTAMP_NTZ'2020-05-17 12:34:56.789012' AS TIME(6));
    -- 12:34:56.789012
    
    -- attach the current date
    SELECT CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9));
    -- <current_date> 12:34:56.789012345
    ```
    
    This is a new feature on an unreleased branch; there is no behavior change 
relative to a released version.
    
    ### How was this patch tested?
    
    - New unit tests in `CastSuiteBase` (run under ANSI on and off): 
allowed-pair / `needsTimeZone` matrix, `TIMESTAMP_NTZ(q) -> TIME(p)` values 
across all precisions (including pre-epoch and sub-microsecond truncation), 
interpreted-vs-codegen consistency, and date-independent round trips.
    - New test in `ComputeCurrentTimeSuite` asserting the forward cast is 
rewritten with a query-stable current-date literal consistent with 
`current_date()`.
    - New unit tests in `DateTimeUtilsSuite` for `makeTimestampNTZNanos` and 
the time-of-day extraction helpers.
    - New deterministic cases in `cast.sql` (and the imported 
`nonansi/cast.sql`) with regenerated golden files.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Cursor (Claude Opus 4.8)
    
    Closes #56677 from MaxGekk/time-cast-timestamp_ntz.
    
    Authored-by: Maxim Gekk <[email protected]>
    Signed-off-by: Max Gekk <[email protected]>
---
 .../sql/catalyst/util/SparkDateTimeUtils.scala     |  19 ++
 .../spark/sql/catalyst/expressions/Cast.scala      |  92 ++++++-
 .../catalyst/expressions/datetimeExpressions.scala |  31 +++
 .../sql/catalyst/optimizer/finishAnalysis.scala    |  31 ++-
 .../spark/sql/catalyst/util/DateTimeUtils.scala    |  17 ++
 .../analysis/ResolveInlineTablesSuite.scala        |   6 +-
 .../sql/catalyst/expressions/CastSuiteBase.scala   | 126 +++++++++
 .../expressions/DateExpressionsSuite.scala         |  32 +++
 .../optimizer/ComputeCurrentTimeSuite.scala        |  37 ++-
 .../sql/catalyst/util/DateTimeUtilsSuite.scala     |  37 +++
 .../connect/planner/SparkConnectProtoSuite.scala   |  17 ++
 .../sql-tests/analyzer-results/cast.sql.out        | 258 ++++++++++++++++++
 .../analyzer-results/nonansi/cast.sql.out          | 258 ++++++++++++++++++
 .../src/test/resources/sql-tests/inputs/cast.sql   |  50 ++++
 .../test/resources/sql-tests/results/cast.sql.out  | 291 +++++++++++++++++++++
 .../sql-tests/results/nonansi/cast.sql.out         | 291 +++++++++++++++++++++
 16 files changed, 1584 insertions(+), 9 deletions(-)

diff --git 
a/sql/api/src/main/scala/org/apache/spark/sql/catalyst/util/SparkDateTimeUtils.scala
 
b/sql/api/src/main/scala/org/apache/spark/sql/catalyst/util/SparkDateTimeUtils.scala
index 5abc80e7c6a1..ac93e3c1415a 100644
--- 
a/sql/api/src/main/scala/org/apache/spark/sql/catalyst/util/SparkDateTimeUtils.scala
+++ 
b/sql/api/src/main/scala/org/apache/spark/sql/catalyst/util/SparkDateTimeUtils.scala
@@ -389,6 +389,25 @@ trait SparkDateTimeUtils {
    */
   def nanosToLocalTime(nanos: Long): LocalTime = LocalTime.ofNanoOfDay(nanos)
 
+  /**
+   * Extracts the time-of-day component (nanoseconds since midnight) from a 
`TIMESTAMP_NTZ`
+   * microsecond value. `TIMESTAMP_NTZ` is a UTC wall-clock value, so its 
time-of-day is the value
+   * taken modulo one day. `floorMod` keeps the result in `[0, NANOS_PER_DAY)` 
even for pre-epoch
+   * (negative) timestamps.
+   */
+  def timestampNTZToNanosOfDay(micros: Long): Long = {
+    Math.floorMod(micros, MICROS_PER_DAY) * NANOS_PER_MICROS
+  }
+
+  /**
+   * Extracts the time-of-day component (nanoseconds since midnight) from a 
nanosecond-precision
+   * `TIMESTAMP_NTZ` value, preserving the sub-microsecond digits carried in 
`nanosWithinMicro`.
+   * Since `nanosWithinMicro` is in `[0, 999]`, the result stays in `[0, 
NANOS_PER_DAY)`.
+   */
+  def timestampNTZNanosToNanosOfDay(v: TimestampNanosVal): Long = {
+    Math.floorMod(v.epochMicros, MICROS_PER_DAY) * NANOS_PER_MICROS + 
v.nanosWithinMicro
+  }
+
   /**
    * Converts a local date at the default JVM time zone to the number of days 
since 1970-01-01 in
    * the hybrid calendar (Julian + Gregorian) by discarding the time part. The 
resulted days are
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala
index d12f46ecee9f..406e18ea1f7b 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/Cast.scala
@@ -158,6 +158,14 @@ object Cast extends QueryErrorsBase {
     case (_: TimeType, _: TimeType) => true
     case (_: TimeType, _: IntegralType) => true
 
+    // TIME(p) <-> TIMESTAMP_NTZ(q), q in [6, 9] (precision 6 is the micro 
TimestampNTZType,
+    // [7, 9] is TimestampNTZNanosType). Restricted to the NTZ family on 
purpose: TIMESTAMP_LTZ
+    // is not a valid counterpart for these casts.
+    case (_: TimeType, TimestampNTZType) => true
+    case (TimestampNTZType, _: TimeType) => true
+    case (_: TimeType, _: TimestampNTZNanosType) => true
+    case (_: TimestampNTZNanosType, _: TimeType) => true
+
     // non-null variants can generate nulls even in ANSI mode
     case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
       canAnsiCast(fromType, toType) && resolvableNullability(fn || (fromType 
== VariantType), tn)
@@ -311,6 +319,14 @@ object Cast extends QueryErrorsBase {
     case (_: TimeType, _: TimeType) => true
     case (_: TimeType, _: IntegralType) => true
 
+    // TIME(p) <-> TIMESTAMP_NTZ(q), q in [6, 9] (precision 6 is the micro 
TimestampNTZType,
+    // [7, 9] is TimestampNTZNanosType). Restricted to the NTZ family on 
purpose: TIMESTAMP_LTZ
+    // is not a valid counterpart for these casts.
+    case (_: TimeType, TimestampNTZType) => true
+    case (TimestampNTZType, _: TimeType) => true
+    case (_: TimeType, _: TimestampNTZNanosType) => true
+    case (_: TimestampNTZNanosType, _: TimeType) => true
+
     case (ArrayType(fromType, fn), ArrayType(toType, tn)) =>
       canCast(fromType, toType) &&
         resolvableNullability(fn || forceNullable(fromType, toType), tn)
@@ -351,11 +367,11 @@ object Cast extends QueryErrorsBase {
 
   /**
    * Return true if we need to use the `timeZone` information casting `from` 
type to `to` type.
-   * The patterns matched reflect the current implementation in the Cast node.
-   * c.f. usage of `timeZone` in:
-   * * Cast.castToString
-   * * Cast.castToDate
-   * * Cast.castToTimestamp
+   * The patterns matched reflect the current implementation in the Cast node 
and must stay in sync
+   * with it: a conversion needs the session time zone exactly when its 
`castTo*` / `castTo*Code`
+   * path reads `zoneId`. This is principally the string/date casts of the LTZ 
timestamp families
+   * (TIMESTAMP and TIMESTAMP_LTZ(p)), the cross-family TIMESTAMP_LTZ <-> 
TIMESTAMP_NTZ conversions
+   * (micro and nanosecond), and TIME -> TIMESTAMP_NTZ (whose date fields come 
from CURRENT_DATE).
    */
   def needsTimeZone(from: DataType, to: DataType): Boolean = (from, to) match {
     case (VariantType, _) => true
@@ -383,6 +399,11 @@ object Cast extends QueryErrorsBase {
     // mirroring micro TIMESTAMP_NTZ<->DATE which is intentionally absent here.
     case (DateType, _: TimestampLTZNanosType) => true
     case (_: TimestampLTZNanosType, DateType) => true
+    // TIME -> TIMESTAMP_NTZ fills the date fields from CURRENT_DATE, which is 
resolved in the
+    // session time zone. The reverse (TIMESTAMP_NTZ -> TIME) extracts the UTC 
wall-clock
+    // time-of-day and is intentionally zone-independent, so it is absent here.
+    case (_: TimeType, TimestampNTZType) => true
+    case (_: TimeType, _: TimestampNTZNanosType) => true
     case (ArrayType(fromType, _), ArrayType(toType, _)) => 
needsTimeZone(fromType, toType)
     case (MapType(fromKey, fromValue, _), MapType(toKey, toValue, _)) =>
       needsTimeZone(fromKey, toKey) || needsTimeZone(fromValue, toValue)
@@ -395,6 +416,18 @@ object Cast extends QueryErrorsBase {
     case _ => false
   }
 
+  /**
+   * Returns true for a cast from `TIME(p)` to `TIMESTAMP_NTZ(q)` (q in [6, 
9]). Such casts derive
+   * their date fields from `CURRENT_DATE`, so they are stabilized within a 
query by
+   * [[org.apache.spark.sql.catalyst.optimizer.ComputeCurrentTime]], which 
scans `CAST` nodes and
+   * uses this predicate on the resolved plan.
+   */
+  def isTimeToTimestampNTZ(from: DataType, to: DataType): Boolean = (from, to) 
match {
+    case (_: TimeType, _: TimestampNTZType) => true
+    case (_: TimeType, _: TimestampNTZNanosType) => true
+    case _ => false
+  }
+
   /**
    * Returns true iff we can safely up-cast the `from` type to `to` type 
without any truncating or
    * precision lose or possible runtime failures. For example, long -> int, 
string -> int are not
@@ -868,6 +901,12 @@ case class Cast(
       buildCast[TimestampNanosVal](_, v => v.epochMicros)
     case _: TimestampLTZNanosType =>
       buildCast[TimestampNanosVal](_, v => convertTz(v.epochMicros, 
ZoneOffset.UTC, zoneId))
+    case _: TimeType =>
+      // Per ANSI, the date fields come from CURRENT_DATE (resolved in the 
session time zone).
+      // In a real query plan ComputeCurrentTime rewrites this cast with a 
query-stable date
+      // literal; this eval path is the fallback for direct expression 
evaluation and reads the
+      // current date in the session time zone.
+      buildCast[Long](_, nanos => 
DateTimeUtils.makeTimestampNTZ(currentDate(zoneId), nanos))
   }
 
   private[this] def castToTimestampLTZNanos(
@@ -919,6 +958,12 @@ case class Cast(
     case DateType =>
       buildCast[Int](_, d =>
         TimestampNanosVal.fromParts(daysToMicros(d, ZoneOffset.UTC), 
0.toShort))
+    case _: TimeType =>
+      // See castToTimestampNTZ: the date fields come from CURRENT_DATE in the 
session time zone,
+      // with the query-stable rewrite handled by ComputeCurrentTime. The 
sub-microsecond digits
+      // of the TIME value are preserved up to the target precision.
+      buildCast[Long](_, nanos =>
+        DateTimeUtils.makeTimestampNTZNanos(currentDate(zoneId), nanos, 
precision))
   }
 
   private[this] def decimalToTimestamp(d: Decimal): Long = {
@@ -973,6 +1018,18 @@ case class Cast(
       }
     case _: TimeType =>
       buildCast[Long](_, nanos => DateTimeUtils.truncateTimeToPrecision(nanos, 
to.precision))
+    case TimestampNTZType =>
+      buildCast[Long](_, micros => DateTimeUtils.truncateTimeToPrecision(
+        DateTimeUtils.timestampNTZToNanosOfDay(micros), to.precision))
+    case _: TimestampNTZNanosType =>
+      buildCast[TimestampNanosVal](_, v => 
DateTimeUtils.truncateTimeToPrecision(
+        DateTimeUtils.timestampNTZNanosToNanosOfDay(v), to.precision))
+    // Unreachable for valid casts: `canCast(_, TimeType)` only allows the 
source types handled
+    // above (and NullType is short-circuited in castInternal). Fail fast to 
keep the interpreted
+    // and codegen (castToTimeCode) paths consistent if a future canCast arm 
is added without a
+    // matching converter here.
+    case _ =>
+      throw SparkException.internalError(s"Cannot cast $from to 
${to.typeName}.")
   }
 
   // IntervalConverter
@@ -1692,8 +1749,22 @@ case class Cast(
           code"""
             $evPrim = $dateTimeUtilsCls.truncateTimeToPrecision($nanos, 
${to.precision});
           """
+      case TimestampNTZType =>
+        (c, evPrim, _) =>
+          code"""
+            $evPrim = $dateTimeUtilsCls.truncateTimeToPrecision(
+              $dateTimeUtilsCls.timestampNTZToNanosOfDay($c), ${to.precision});
+          """
+      case _: TimestampNTZNanosType =>
+        (c, evPrim, _) =>
+          code"""
+            $evPrim = $dateTimeUtilsCls.truncateTimeToPrecision(
+              $dateTimeUtilsCls.timestampNTZNanosToNanosOfDay($c), 
${to.precision});
+          """
+      // Unreachable for valid casts (see castToTime). Fail fast at codegen 
time instead of
+      // silently emitting a null, matching the interpreted path.
       case _ =>
-        (_, _, evNull) => code"$evNull = true;"
+        throw SparkException.internalError(s"Cannot cast $from to 
${to.typeName}.")
     }
   }
 
@@ -1932,6 +2003,10 @@ case class Cast(
       val zid = zoneIdValue(ctx)
       (c, evPrim, evNull) =>
         code"$evPrim = $dateTimeUtilsCls.convertTz($c.epochMicros, 
java.time.ZoneOffset.UTC, $zid);"
+    case _: TimeType =>
+      val zid = zoneIdValue(ctx)
+      (c, evPrim, evNull) =>
+        code"$evPrim = 
$dateTimeUtilsCls.makeTimestampNTZ($dateTimeUtilsCls.currentDate($zid), $c);"
   }
 
   private[this] def castToTimestampLTZNanosCode(
@@ -2024,6 +2099,11 @@ case class Cast(
       (c, evPrim, evNull) =>
         code"$evPrim = TimestampNanosVal.fromParts(" +
           code"$dateTimeUtilsCls.daysToMicros($c, java.time.ZoneOffset.UTC), 
(short) 0);"
+    case _: TimeType =>
+      val zid = zoneIdValue(ctx)
+      (c, evPrim, evNull) =>
+        code"$evPrim = $dateTimeUtilsCls.makeTimestampNTZNanos(" +
+          code"$dateTimeUtilsCls.currentDate($zid), $c, $precision);"
   }
 
   private[this] def castToIntervalCode(from: DataType): CastFunction = from 
match {
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
index 268d86852c3c..3dfe12cc6108 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala
@@ -3035,6 +3035,37 @@ case class MakeTimestampNTZ(left: Expression, right: 
Expression)
   }
 }
 
+/**
+ * Creates a nanosecond-precision `TIMESTAMP_NTZ(precision)` (precision in [7, 
9]) from a date and
+ * a local time, preserving the time's sub-microsecond digits up to 
`precision`. This is the
+ * nanosecond counterpart of [[MakeTimestampNTZ]]. It is an internal 
expression used by
+ * [[org.apache.spark.sql.catalyst.optimizer.ComputeCurrentTime]] to rewrite
+ * `CAST(time AS TIMESTAMP_NTZ(precision))` with a query-stable current date; 
it is not registered
+ * as a SQL function.
+ */
+case class MakeTimestampNTZNanos(left: Expression, right: Expression, 
precision: Int)
+  extends BinaryExpression
+  with RuntimeReplaceable
+  with ExpectsInputTypes {
+
+  override def replacement: Expression = StaticInvoke(
+    classOf[DateTimeUtils.type],
+    TimestampNTZNanosType(precision),
+    "makeTimestampNTZNanos",
+    Seq(left, right, Literal(precision)),
+    Seq(left.dataType, right.dataType, IntegerType)
+  )
+
+  override def inputTypes: Seq[AbstractDataType] = Seq(DateType, AnyTimeType)
+
+  override def prettyName: String = "make_timestamp_ntz_nanos"
+
+  override protected def withNewChildrenInternal(
+    newLeft: Expression, newRight: Expression): Expression = {
+    copy(left = newLeft, right = newRight)
+  }
+}
+
 // scalastyle:off line.size.limit
 @ExpressionDescription(
   usage = """
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/optimizer/finishAnalysis.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/optimizer/finishAnalysis.scala
index 160c4147dae6..74182f781890 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/optimizer/finishAnalysis.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/optimizer/finishAnalysis.scala
@@ -21,6 +21,7 @@ import java.time.{Instant, LocalDateTime, ZoneId}
 
 import scala.util.control.NonFatal
 
+import org.apache.spark.SparkException
 import org.apache.spark.sql.catalyst.{CurrentUserContext, InternalRow}
 import org.apache.spark.sql.catalyst.analysis.{CastSupport, 
ResolvedInlineTable}
 import 
org.apache.spark.sql.catalyst.analysis.ResolveInlineTables.prepareForEval
@@ -119,8 +120,15 @@ object ComputeCurrentTime extends Rule[LogicalPlan] {
     val currentDates = collection.mutable.HashMap.empty[ZoneId, Literal]
     val localTimestamps = collection.mutable.HashMap.empty[ZoneId, Literal]
 
+    // The CAST bit is included so this rule can find TIME -> TIMESTAMP_NTZ 
casts (which depend on
+    // CURRENT_DATE) and stabilize them below. CAST is a broad pattern, so 
this widens the rule's
+    // traversal to most plans; the precise `Cast.isTimeToTimestampNTZ` guard 
keeps the rewrite
+    // scoped. We intentionally do not tag these casts with CURRENT_LIKE 
instead: inline-table
+    // validation treats CURRENT_LIKE as safe to defer, so tagging would let 
unrelated non-foldable
+    // NTZ-target casts (e.g. CAST(rand() AS TIMESTAMP_NTZ)) bypass that 
validation (see SPARK-57618
+    // and ResolveInlineTablesSuite).
     def transformCondition(treePatternbits: TreePatternBits): Boolean = {
-      treePatternbits.containsPattern(CURRENT_LIKE)
+      treePatternbits.containsPattern(CURRENT_LIKE) || 
treePatternbits.containsPattern(CAST)
     }
 
     plan.transformDownWithSubqueriesAndPruning(transformCondition) {
@@ -131,6 +139,27 @@ object ComputeCurrentTime extends Rule[LogicalPlan] {
               Literal.create(
                 DateTimeUtils.microsToDays(currentTimestampMicros, cd.zoneId), 
DateType)
             })
+          // CAST(time AS TIMESTAMP_NTZ(q)) fills the date fields from 
CURRENT_DATE. Rewrite it to
+          // a date+time builder anchored on the same query-stable current 
date literal that
+          // current_date() resolves to, so all references agree within the 
query. The builder's
+          // `replacement` (a StaticInvoke) is emitted directly because 
ReplaceExpressions has
+          // already run earlier in this batch and will not expand a fresh 
RuntimeReplaceable.
+          case c: Cast if Cast.isTimeToTimestampNTZ(c.child.dataType, 
c.dataType) =>
+            val dateLit = currentDates.getOrElseUpdate(c.zoneId, {
+              Literal.create(
+                DateTimeUtils.microsToDays(currentTimestampMicros, c.zoneId), 
DateType)
+            })
+            c.dataType match {
+              case n: TimestampNTZNanosType =>
+                MakeTimestampNTZNanos(dateLit, c.child, 
n.precision).replacement
+              case _: TimestampNTZType =>
+                MakeTimestampNTZ(dateLit, c.child).replacement
+              case other =>
+                // Unreachable: the outer guard `Cast.isTimeToTimestampNTZ` 
only matches the micro
+                // TimestampNTZType and the nanosecond TimestampNTZNanosType 
targets.
+                throw SparkException.internalError(
+                  s"Unexpected target type in TIME -> TIMESTAMP_NTZ rewrite: 
$other")
+            }
           case currentTimeType : CurrentTime =>
             val truncatedTime = truncateTimeToPrecision(currentTimeOfDayNanos,
               currentTimeType.precision)
diff --git 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala
 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala
index b37fbf224963..48ca74c29f25 100644
--- 
a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala
+++ 
b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala
@@ -1098,6 +1098,23 @@ object DateTimeUtils extends SparkDateTimeUtils {
     localDateTimeToMicros(LocalDateTime.of(daysToLocalDate(days), 
nanosToLocalTime(nanos)))
   }
 
+  /**
+   * Makes a nanosecond-precision timestamp without time zone from a date and 
a local time,
+   * flooring the combined value to the target `precision` in [7, 9] (see
+   * [[localDateTimeToTimestampNanos]]).
+   *
+   * @param days The number of days since the epoch 1970-01-01.
+   *             Negative numbers represent earlier days.
+   * @param nanos The number of nanoseconds within the day since midnight.
+   * @param precision The fractional-second precision of the target 
`TIMESTAMP_NTZ(precision)`.
+   * @return The composite `(epochMicros, nanosWithinMicro)` pair since the 
epoch
+   *         1970-01-01 00:00:00Z.
+   */
+  def makeTimestampNTZNanos(days: Int, nanos: Long, precision: Int): 
TimestampNanosVal = {
+    localDateTimeToTimestampNanos(
+      LocalDateTime.of(daysToLocalDate(days), nanosToLocalTime(nanos)), 
precision)
+  }
+
   /**
    * Makes a timestamp from a date and a local time.
    *
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ResolveInlineTablesSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ResolveInlineTablesSuite.scala
index db22c9e48a39..50d88e90987c 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ResolveInlineTablesSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/analysis/ResolveInlineTablesSuite.scala
@@ -25,7 +25,7 @@ import 
org.apache.spark.sql.catalyst.expressions.aggregate.Count
 import org.apache.spark.sql.catalyst.optimizer.{ComputeCurrentTime, 
EvalInlineTables}
 import org.apache.spark.sql.catalyst.plans.logical.LocalRelation
 import org.apache.spark.sql.catalyst.util.EvaluateUnresolvedInlineTable
-import org.apache.spark.sql.types.{LongType, NullType, TimestampType, TimeType}
+import org.apache.spark.sql.types.{LongType, NullType, TimestampNTZType, 
TimestampType, TimeType}
 
 /**
  * Unit tests for [[ResolveInlineTables]]. Note that there are also test cases 
defined in
@@ -49,6 +49,10 @@ class ResolveInlineTablesSuite extends AnalysisTest with 
BeforeAndAfter {
       EvaluateUnresolvedInlineTable.validateInputEvaluable(
         UnresolvedInlineTable(Seq("c1"), Seq(Seq(Rand(1)))))
     }
+    intercept[AnalysisException] {
+      EvaluateUnresolvedInlineTable.validateInputEvaluable(
+        UnresolvedInlineTable(Seq("c1"), Seq(Seq(Cast(Rand(1), 
TimestampNTZType)))))
+    }
 
     // aggregate should not work
     intercept[AnalysisException] {
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuiteBase.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuiteBase.scala
index 122554a18886..73b7c872fc13 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuiteBase.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/CastSuiteBase.scala
@@ -30,6 +30,7 @@ import org.apache.spark.sql.catalyst.expressions.Cast._
 import org.apache.spark.sql.catalyst.expressions.codegen.CodegenContext
 import org.apache.spark.sql.catalyst.util.DateTimeConstants._
 import org.apache.spark.sql.catalyst.util.DateTimeTestUtils._
+import org.apache.spark.sql.catalyst.util.DateTimeUtils
 import org.apache.spark.sql.catalyst.util.DateTimeUtils._
 import org.apache.spark.sql.catalyst.util.IntervalUtils
 import org.apache.spark.sql.catalyst.util.IntervalUtils.microsToDuration
@@ -2503,6 +2504,131 @@ abstract class CastSuiteBase extends SparkFunSuite with 
ExpressionEvalHelper {
     }
   }
 
+  test("cast between TIME and TIMESTAMP_NTZ is allowed only for the NTZ 
family") {
+    for (p <- TimeType.MIN_PRECISION to TimeType.MAX_PRECISION) {
+      assert(Cast.canCast(TimeType(p), TimestampNTZType))
+      assert(Cast.canCast(TimestampNTZType, TimeType(p)))
+      assert(Cast.canAnsiCast(TimeType(p), TimestampNTZType))
+      assert(Cast.canAnsiCast(TimestampNTZType, TimeType(p)))
+      // try_cast inherits the allowed pairs (canTryCast delegates to 
canAnsiCast for atomic types).
+      // These casts never fail, so try_cast behaves exactly like cast.
+      assert(Cast.canTryCast(TimeType(p), TimestampNTZType))
+      assert(Cast.canTryCast(TimestampNTZType, TimeType(p)))
+      // TIMESTAMP_LTZ (the micro TimestampType) is not a valid counterpart.
+      assert(!Cast.canCast(TimeType(p), TimestampType))
+      assert(!Cast.canCast(TimestampType, TimeType(p)))
+      assert(!Cast.canAnsiCast(TimeType(p), TimestampType))
+      assert(!Cast.canAnsiCast(TimestampType, TimeType(p)))
+      assert(!Cast.canTryCast(TimeType(p), TimestampType))
+      assert(!Cast.canTryCast(TimestampType, TimeType(p)))
+      // The disallowed pairs are rejected at analysis, not merely by the 
canCast predicate. The
+      // suite `cast` helper applies the active evalMode, so canAnsiCast / 
canCast is exercised
+      // under ANSI on / off respectively.
+      assert(cast(Literal.create(0L, TimeType(p)), 
TimestampType).checkInputDataTypes().isFailure)
+      assert(cast(Literal.create(0L, TimestampType), 
TimeType(p)).checkInputDataTypes().isFailure)
+      foreachNanosPrecision { q =>
+        assert(Cast.canCast(TimeType(p), TimestampNTZNanosType(q)))
+        assert(Cast.canCast(TimestampNTZNanosType(q), TimeType(p)))
+        assert(Cast.canAnsiCast(TimeType(p), TimestampNTZNanosType(q)))
+        assert(Cast.canAnsiCast(TimestampNTZNanosType(q), TimeType(p)))
+        assert(Cast.canTryCast(TimeType(p), TimestampNTZNanosType(q)))
+        assert(Cast.canTryCast(TimestampNTZNanosType(q), TimeType(p)))
+        // TIMESTAMP_LTZ nanos is not a valid counterpart either.
+        assert(!Cast.canCast(TimeType(p), TimestampLTZNanosType(q)))
+        assert(!Cast.canCast(TimestampLTZNanosType(q), TimeType(p)))
+        assert(!Cast.canAnsiCast(TimeType(p), TimestampLTZNanosType(q)))
+        assert(!Cast.canAnsiCast(TimestampLTZNanosType(q), TimeType(p)))
+        assert(!Cast.canTryCast(TimeType(p), TimestampLTZNanosType(q)))
+        assert(!Cast.canTryCast(TimestampLTZNanosType(q), TimeType(p)))
+      }
+    }
+    // Only TIME -> TIMESTAMP_NTZ depends on the session time zone 
(CURRENT_DATE); the reverse
+    // direction extracts the UTC wall-clock time-of-day and is 
zone-independent.
+    assert(Cast.needsTimeZone(TimeType(0), TimestampNTZType))
+    assert(Cast.needsTimeZone(TimeType(9), TimestampNTZNanosType(9)))
+    assert(!Cast.needsTimeZone(TimestampNTZType, TimeType(0)))
+    assert(!Cast.needsTimeZone(TimestampNTZNanosType(9), TimeType(9)))
+  }
+
+  test("isTimeToTimestampNTZ identifies only TIME -> TIMESTAMP_NTZ") {
+    for (p <- TimeType.MIN_PRECISION to TimeType.MAX_PRECISION) {
+      // True only for TIME -> TIMESTAMP_NTZ (the current-date-dependent 
direction).
+      assert(Cast.isTimeToTimestampNTZ(TimeType(p), TimestampNTZType))
+      // The reverse direction is zone-independent, and TIMESTAMP_LTZ is not a 
counterpart.
+      assert(!Cast.isTimeToTimestampNTZ(TimestampNTZType, TimeType(p)))
+      assert(!Cast.isTimeToTimestampNTZ(TimeType(p), TimestampType))
+      assert(!Cast.isTimeToTimestampNTZ(TimestampType, TimeType(p)))
+      foreachNanosPrecision { q =>
+        assert(Cast.isTimeToTimestampNTZ(TimeType(p), 
TimestampNTZNanosType(q)))
+        assert(!Cast.isTimeToTimestampNTZ(TimestampNTZNanosType(q), 
TimeType(p)))
+        assert(!Cast.isTimeToTimestampNTZ(TimeType(p), 
TimestampLTZNanosType(q)))
+        assert(!Cast.isTimeToTimestampNTZ(TimestampLTZNanosType(q), 
TimeType(p)))
+      }
+    }
+    // Pairs that involve neither a TIME source nor a TIMESTAMP_NTZ target are 
false.
+    assert(!Cast.isTimeToTimestampNTZ(DateType, TimestampNTZType))
+    assert(!Cast.isTimeToTimestampNTZ(TimestampNTZType, TimestampNTZType))
+  }
+
+  test("cast timestamp_ntz to time") {
+    // Per ANSI rule 15.d the time-of-day fields are extracted and truncated 
to the target
+    // precision; the operation is deterministic and time-zone independent.
+    val ldts = Seq(
+      LocalDateTime.of(2020, 5, 17, 12, 34, 56, 789012345),
+      LocalDateTime.of(1969, 12, 31, 23, 59, 59, 123456789),
+      LocalDateTime.of(1, 1, 1, 0, 0, 0, 1))
+    ldts.foreach { ldt =>
+      for (p <- TimeType.MIN_PRECISION to TimeType.MAX_PRECISION) {
+        // q = 6: the micro TimestampNTZType. Its time-of-day has microsecond 
resolution.
+        val micros = DateTimeUtils.localDateTimeToMicros(ldt)
+        val expectedFromMicros =
+          
truncateTimeToPrecision(localTimeToNanos(microsToLocalDateTime(micros).toLocalTime),
 p)
+        checkEvaluation(
+          cast(Literal.create(micros, TimestampNTZType), TimeType(p)), 
expectedFromMicros)
+
+        // q in [7, 9]: the nanosecond TimestampNTZNanosType.
+        foreachNanosPrecision { q =>
+          val truncatedLdt = ldt.withNano(nanoOfSecTruncator(q)(ldt.getNano))
+          val v = localDateTimeToNanosVal(truncatedLdt)
+          val expected = 
truncateTimeToPrecision(localTimeToNanos(truncatedLdt.toLocalTime), p)
+          checkEvaluation(cast(Literal.create(v, TimestampNTZNanosType(q)), 
TimeType(p)), expected)
+        }
+      }
+    }
+
+    // Interpreted vs codegen consistency (zone-independent reverse direction).
+    for (p <- TimeType.MIN_PRECISION to TimeType.MAX_PRECISION) {
+      checkConsistencyBetweenInterpretedAndCodegen(
+        (child: Expression) => Cast(child, TimeType(p)), TimestampNTZType)
+      foreachNanosPrecision { q =>
+        checkConsistencyBetweenInterpretedAndCodegen(
+          (child: Expression) => Cast(child, TimeType(p)), 
TimestampNTZNanosType(q))
+      }
+    }
+  }
+
+  test("cast time to timestamp_ntz and back") {
+    // TIME -> TIMESTAMP_NTZ takes the date from CURRENT_DATE, which cancels 
out on the round trip
+    // back to TIME, so these assertions are deterministic regardless of the 
current date.
+    val times = Seq(
+      localTime(0, 0, 0),
+      localTime(12, 34, 56, 789012),
+      localTime(12, 34, 56, 789012, 345),
+      localTime(23, 59, 59, 999999, 999))
+    times.foreach { nanos =>
+      // q = 6 keeps microsecond resolution.
+      checkEvaluation(
+        cast(cast(Literal(nanos, TimeType(9)), TimestampNTZType, UTC_OPT), 
TimeType(9)),
+        truncateTimeToPrecision(nanos, 6))
+      // q in [7, 9] keeps the corresponding sub-microsecond digits.
+      foreachNanosPrecision { q =>
+        checkEvaluation(
+          cast(cast(Literal(nanos, TimeType(9)), TimestampNTZNanosType(q), 
UTC_OPT), TimeType(9)),
+          truncateTimeToPrecision(nanos, q))
+      }
+    }
+  }
+
   test("SPARK-52620: cast time to decimal with sufficient precision and 
scale") {
     // Test various TIME values converted to DecimalType(14, 9), which always 
has sufficient
     // precision and scale to represent the number of (nano)seconds since 
midnight. Note that
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/DateExpressionsSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/DateExpressionsSuite.scala
index 4a016ee186bd..474a8a04aa71 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/DateExpressionsSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/DateExpressionsSuite.scala
@@ -2593,6 +2593,38 @@ class DateExpressionsSuite extends SparkFunSuite with 
ExpressionEvalHelper {
       null)
   }
 
+  test("SPARK-57618: make nanosecond timestamp_ntz from date and time") {
+    val date = "2025-06-20"
+    val micros = timestampToMicros("2025-06-20T15:20:30.123456", UTC)
+    val timeNanos = Literal.create(localTime(15, 20, 30, 123456, 789), 
TimeType(9))
+    // Precision 9 preserves all sub-microsecond digits; lower precisions 
floor them.
+    checkEvaluation(MakeTimestampNTZNanos(dateLit(date), timeNanos, 9),
+      TimestampNanosVal.fromParts(micros, 789.toShort))
+    checkEvaluation(MakeTimestampNTZNanos(dateLit(date), timeNanos, 8),
+      TimestampNanosVal.fromParts(micros, 780.toShort))
+    checkEvaluation(MakeTimestampNTZNanos(dateLit(date), timeNanos, 7),
+      TimestampNanosVal.fromParts(micros, 700.toShort))
+    // Pre-epoch date.
+    val preEpochMicros = timestampToMicros("1969-12-31T23:59:59.123456", UTC)
+    checkEvaluation(
+      MakeTimestampNTZNanos(dateLit("1969-12-31"),
+        Literal.create(localTime(23, 59, 59, 123456, 789), TimeType(9)), 9),
+      TimestampNanosVal.fromParts(preEpochMicros, 789.toShort))
+    // Null inputs propagate to a null result.
+    checkEvaluation(MakeTimestampNTZNanos(Literal(null, DateType), timeNanos, 
9), null)
+    checkEvaluation(MakeTimestampNTZNanos(dateLit(date), Literal(null, 
TimeType(9)), 9), null)
+    // The result type carries the requested nanosecond precision.
+    assert(MakeTimestampNTZNanos(dateLit(date), timeNanos, 7).dataType === 
TimestampNTZNanosType(7))
+    // The precision participates in equality and canonicalization: builders 
that differ only in
+    // precision are distinct, so two casts to different TIMESTAMP_NTZ(q) are 
never conflated.
+    assert(MakeTimestampNTZNanos(dateLit(date), timeNanos, 9) !=
+      MakeTimestampNTZNanos(dateLit(date), timeNanos, 7))
+    assert(MakeTimestampNTZNanos(dateLit(date), timeNanos, 9).canonicalized ==
+      MakeTimestampNTZNanos(dateLit(date), timeNanos, 9).canonicalized)
+    assert(MakeTimestampNTZNanos(dateLit(date), timeNanos, 9).canonicalized !=
+      MakeTimestampNTZNanos(dateLit(date), timeNanos, 7).canonicalized)
+  }
+
   test("SPARK-53113: try to make timestamp from date, time, and timezone") {
     Seq(
       ("2023-10-01", "12:34:56.123456", "America/Los_Angeles", LA),
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ComputeCurrentTimeSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ComputeCurrentTimeSuite.scala
index c4f71ec62957..34b38cbaed8f 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ComputeCurrentTimeSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/optimizer/ComputeCurrentTimeSuite.scala
@@ -30,7 +30,7 @@ import org.apache.spark.sql.catalyst.plans.logical.{Filter, 
LocalRelation, Logic
 import org.apache.spark.sql.catalyst.rules.RuleExecutor
 import org.apache.spark.sql.catalyst.util.DateTimeUtils
 import org.apache.spark.sql.internal.SQLConf
-import org.apache.spark.sql.types.IntegerType
+import org.apache.spark.sql.types.{DateType, IntegerType, 
TimestampNTZNanosType, TimestampNTZType, TimeType}
 import org.apache.spark.unsafe.types.UTF8String
 
 class ComputeCurrentTimeSuite extends PlanTest {
@@ -273,6 +273,41 @@ class ComputeCurrentTimeSuite extends PlanTest {
     checkLiterals({ zoneId: String => CurrentDate(Some(zoneId)) }, 
numUniqueZoneIds)
   }
 
+  test("CAST(time AS TIMESTAMP_NTZ) is stabilized with the query current 
date") {
+    val timeLit = Literal(0L, TimeType(6))
+    val in = Project(Seq(
+      Alias(Cast(timeLit, TimestampNTZType), "a")(),
+      Alias(Cast(timeLit, TimestampNTZNanosType(9)), "b")(),
+      Alias(CurrentDate(), "c")()), LocalRelation())
+
+    val min = DateTimeUtils.currentDate(ZoneId.systemDefault())
+    val plan = Optimize.execute(in.analyze).asInstanceOf[Project]
+    val max = DateTimeUtils.currentDate(ZoneId.systemDefault())
+
+    // The two casts and current_date() must all be anchored to the same 
current-date literal.
+    val dateLits = dateLiterals(plan)
+    assert(dateLits.size == 3)
+    assert(dateLits.toSet.size == 1)
+    assert(dateLits.forall(d => d >= min && d <= max))
+
+    // The TIME -> TIMESTAMP_NTZ casts must be rewritten away (replaced by a 
date+time builder).
+    val remainingCasts = plan.flatMap(_.expressions.flatMap(_.collect {
+      case c: Cast if Cast.isTimeToTimestampNTZ(c.child.dataType, c.dataType) 
=> c
+    }))
+    assert(remainingCasts.isEmpty)
+  }
+
+  private def dateLiterals(plan: LogicalPlan): 
scala.collection.mutable.ArrayBuffer[Int] = {
+    val buf = new scala.collection.mutable.ArrayBuffer[Int]
+    plan.transformWithSubqueries { case subQuery =>
+      subQuery.transformAllExpressions { case lit: Literal if lit.dataType == 
DateType =>
+        buf += lit.value.asInstanceOf[Int]
+        lit
+      }
+    }
+    buf
+  }
+
   private def literals[T](plan: LogicalPlan): 
scala.collection.mutable.ArrayBuffer[T] = {
     val literals = new scala.collection.mutable.ArrayBuffer[T]
     plan.transformWithSubqueries { case subQuery =>
diff --git 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala
 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala
index 82617b6b4cf6..e60ebf118207 100644
--- 
a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala
+++ 
b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/util/DateTimeUtilsSuite.scala
@@ -1636,6 +1636,43 @@ class DateTimeUtilsSuite extends SparkFunSuite with 
Matchers with SQLHelper {
     assert(msg.contains("Invalid value"))
   }
 
+  test("makeTimestampNTZNanos") {
+    // The combined date + time is floored to the target nanosecond precision 
in [7, 9].
+    val nanos = localTime(23, 59, 59, 999999, 999)
+    val microsOfDay = localTime(23, 59, 59, 999999) / NANOS_PER_MICROS
+    assert(makeTimestampNTZNanos(0, nanos, 9) ===
+      TimestampNanosVal.fromParts(microsOfDay, 999.toShort))
+    assert(makeTimestampNTZNanos(0, nanos, 8) ===
+      TimestampNanosVal.fromParts(microsOfDay, 990.toShort))
+    assert(makeTimestampNTZNanos(0, nanos, 7) ===
+      TimestampNanosVal.fromParts(microsOfDay, 900.toShort))
+    // A non-zero date shifts the microsecond component while preserving the 
sub-micro digits.
+    assert(makeTimestampNTZNanos(days(2020, 5, 17), localTime(12, 34, 56, 
789012, 345), 9) ===
+      TimestampNanosVal.fromParts(date(2020, 5, 17, 12, 34, 56, 789012), 
345.toShort))
+    // Pre-epoch date.
+    assert(makeTimestampNTZNanos(days(1969, 12, 31), localTime(23, 59, 59, 
123456, 789), 9) ===
+      TimestampNanosVal.fromParts(date(1969, 12, 31, 23, 59, 59, 123456), 
789.toShort))
+  }
+
+  test("timestampNTZ time-of-day extraction") {
+    // Micro TimestampNTZ: time-of-day is the value modulo one day.
+    assert(timestampNTZToNanosOfDay(0) === 0)
+    assert(timestampNTZToNanosOfDay(date(2020, 5, 17, 12, 34, 56, 789012)) ===
+      localTime(12, 34, 56, 789012))
+    // Pre-epoch timestamps wrap correctly via floorMod.
+    assert(timestampNTZToNanosOfDay(date(1969, 12, 31, 23, 59, 59, 123456)) ===
+      localTime(23, 59, 59, 123456))
+    assert(timestampNTZToNanosOfDay(-1) === localTime(23, 59, 59, 999999))
+
+    // Nanosecond TimestampNTZ preserves the sub-microsecond digits.
+    assert(timestampNTZNanosToNanosOfDay(
+      TimestampNanosVal.fromParts(date(2020, 5, 17, 12, 34, 56, 789012), 
345.toShort)) ===
+      localTime(12, 34, 56, 789012, 345))
+    assert(timestampNTZNanosToNanosOfDay(
+      TimestampNanosVal.fromParts(date(1969, 12, 31, 23, 59, 59, 123456), 
789.toShort)) ===
+      localTime(23, 59, 59, 123456, 789))
+  }
+
   test("instant to nanos of day") {
     
assert(instantToNanosOfDay(Instant.parse("1970-01-01T00:00:01.001002003Z"), 
"UTC") ==
       1001002003)
diff --git 
a/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectProtoSuite.scala
 
b/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectProtoSuite.scala
index aa0345f089fc..1a5189e24304 100644
--- 
a/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectProtoSuite.scala
+++ 
b/sql/connect/server/src/test/scala/org/apache/spark/sql/connect/planner/SparkConnectProtoSuite.scala
@@ -986,6 +986,23 @@ class SparkConnectProtoSuite extends PlanTest with 
SparkConnectPlanTest {
       sparkTestRelation.select(col("id").cast("string")))
   }
 
+  test("SPARK-57618: cast TIMESTAMP_NTZ to TIME") {
+    // The cast logic itself lives in Catalyst (covered by CastSuite*); this 
confirms the
+    // TIMESTAMP_NTZ -> TIME pair round-trips through the Connect planner. The 
target TIME type is
+    // carried as a type string and parsed server-side, so this does not 
depend on TIME being
+    // serializable in the Connect schema proto (only the NTZ column is). The 
reverse direction
+    // (TIME -> TIMESTAMP_NTZ) is not exercisable here until the TIME type is 
supported by the
+    // Connect DataType proto converter; it is covered by the Catalyst suites.
+    val connectRel =
+      createLocalRelationProto(Seq(AttributeReference("ts", 
TimestampNTZType)()), Seq.empty)
+    val sparkRel = spark.createDataFrame(
+      new java.util.ArrayList[Row](),
+      StructType(Seq(StructField("ts", TimestampNTZType))))
+    comparePlans(
+      connectRel.select("ts".protoAttr.cast("time")),
+      sparkRel.select(col("ts").cast("time")))
+  }
+
   test("Test colRegex") {
     comparePlans(
       connectTestRelation.select("id".colRegex),
diff --git 
a/sql/core/src/test/resources/sql-tests/analyzer-results/cast.sql.out 
b/sql/core/src/test/resources/sql-tests/analyzer-results/cast.sql.out
index 2ad6e040585b..91788c515310 100644
--- a/sql/core/src/test/resources/sql-tests/analyzer-results/cast.sql.out
+++ b/sql/core/src/test/resources/sql-tests/analyzer-results/cast.sql.out
@@ -1734,3 +1734,261 @@ SELECT CAST(time '23:59:59.999999999' AS decimal(14, 8))
 -- !query analysis
 Project [cast(23:59:59.999999999 as decimal(14,8)) AS CAST(TIME 
'23:59:59.999999999' AS DECIMAL(14,8))#x]
 +- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(6))
+-- !query analysis
+Project [cast(2020-05-17 12:34:56.789012 as time(6)) AS CAST(TIMESTAMP_NTZ 
'2020-05-17 12:34:56.789012' AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(3))
+-- !query analysis
+Project [cast(2020-05-17 12:34:56.789012 as time(3)) AS CAST(TIMESTAMP_NTZ 
'2020-05-17 12:34:56.789012' AS TIME(3))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(0))
+-- !query analysis
+Project [cast(2020-05-17 12:34:56.789012 as time(0)) AS CAST(TIMESTAMP_NTZ 
'2020-05-17 12:34:56.789012' AS TIME(0))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'1969-12-31 23:59:59.123456' AS TIME(6))
+-- !query analysis
+Project [cast(1969-12-31 23:59:59.123456 as time(6)) AS CAST(TIMESTAMP_NTZ 
'1969-12-31 23:59:59.123456' AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(9))
+-- !query analysis
+Project [cast(cast(2020-05-17 12:34:56.789012345 as timestamp_ntz(9)) as 
time(9)) AS CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(7))
+-- !query analysis
+Project [cast(cast(2020-05-17 12:34:56.789012345 as timestamp_ntz(9)) as 
time(7)) AS CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(7))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(6))
+-- !query analysis
+Project [cast(cast(2020-05-17 12:34:56.789012345 as timestamp_ntz(9)) as 
time(6)) AS CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(7) AS 
TIME(9))
+-- !query analysis
+Project [cast(cast(2020-05-17 12:34:56.789012345 as timestamp_ntz(7)) as 
time(9)) AS CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(7)) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT timestamp_ntz'2020-05-17 12:34:56.789012' :: TIME(6)
+-- !query analysis
+Project [cast(2020-05-17 12:34:56.789012 as time(6)) AS CAST(TIMESTAMP_NTZ 
'2020-05-17 12:34:56.789012' AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ))
+-- !query analysis
+Project [typeof(cast(12:34:56 as timestamp_ntz)) AS typeof(CAST(TIME 
'12:34:56' AS TIMESTAMP_NTZ))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ(9)))
+-- !query analysis
+Project [typeof(cast(12:34:56 as timestamp_ntz(9))) AS typeof(CAST(TIME 
'12:34:56' AS TIMESTAMP_NTZ(9)))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ) AS DATE) = current_date()
+-- !query analysis
+[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS DATE) = 
current_date()
+-- !query analysis
+[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6))
+-- !query analysis
+Project [cast(cast(12:34:56.789012 as timestamp_ntz) as time(6)) AS 
CAST(CAST(TIME '12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS TIME(9))
+-- !query analysis
+Project [cast(cast(12:34:56.789012345 as timestamp_ntz(9)) as time(9)) AS 
CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS TIME(9))
+-- !query analysis
+Project [cast(cast(12:34:56.789012345 as timestamp_ntz(7)) as time(9)) AS 
CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345'::time(9) AS TIMESTAMP_NTZ(6)) AS 
TIME(9))
+-- !query analysis
+Project [cast(cast(cast(12:34:56.789012345 as time(9)) as timestamp_ntz) as 
time(9)) AS CAST(CAST(CAST(TIME '12:34:56.789012345' AS TIME(9)) AS 
TIMESTAMP_NTZ) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ)
+-- !query analysis
+Project [cast(cast(null as time(6)) as timestamp_ntz) AS CAST(CAST(NULL AS 
TIME(6)) AS TIMESTAMP_NTZ)#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ(9))
+-- !query analysis
+Project [cast(cast(null as time(6)) as timestamp_ntz(9)) AS CAST(CAST(NULL AS 
TIME(6)) AS TIMESTAMP_NTZ(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ) AS TIME(6))
+-- !query analysis
+Project [cast(cast(null as timestamp_ntz) as time(6)) AS CAST(CAST(NULL AS 
TIMESTAMP_NTZ) AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS TIME(6))
+-- !query analysis
+Project [cast(cast(null as timestamp_ntz(9)) as time(6)) AS CAST(CAST(NULL AS 
TIMESTAMP_NTZ(9)) AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(x AS DATE) = current_date() FROM VALUES (CAST(TIME'12:34:56' AS 
TIMESTAMP_NTZ)) t(x)
+-- !query analysis
+[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT CAST(x AS TIME(6)) FROM VALUES (CAST(TIME'12:34:56.789012' AS 
TIMESTAMP_NTZ)) t(x)
+-- !query analysis
+Project [cast(x#x as time(6)) AS x#x]
++- SubqueryAlias t
+   +- LocalRelation [x#x]
+
+
+-- !query
+SELECT CAST(x AS TIME(9)) FROM VALUES (CAST(TIME'12:34:56.789012345' AS 
TIMESTAMP_NTZ(9))) t(x)
+-- !query analysis
+Project [cast(x#x as time(9)) AS x#x]
++- SubqueryAlias t
+   +- LocalRelation [x#x]
+
+
+-- !query
+SELECT time'12:34:56' UNION ALL SELECT timestamp_ntz'2020-05-17 12:34:56'
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "INCOMPATIBLE_COLUMN_TYPE",
+  "sqlState" : "42825",
+  "messageParameters" : {
+    "columnOrdinalNumber" : "first",
+    "dataType1" : "\"TIMESTAMP_NTZ\"",
+    "dataType2" : "\"TIME(6)\"",
+    "hint" : "",
+    "operator" : "UNION",
+    "tableOrdinalNumber" : "second"
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 1,
+    "stopIndex" : 73,
+    "fragment" : "SELECT time'12:34:56' UNION ALL SELECT 
timestamp_ntz'2020-05-17 12:34:56'"
+  } ]
+}
+
+
+-- !query
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56')
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "(\"TIME(6)\" or \"TIMESTAMP_NTZ\")",
+    "functionName" : "`coalesce`",
+    "sqlExpr" : "\"coalesce(TIME '12:34:56', TIMESTAMP_NTZ '2020-05-17 
12:34:56')\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 67,
+    "fragment" : "coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56')"
+  } ]
+}
+
+
+-- !query
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9))
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "(\"TIME(6)\" or \"TIMESTAMP_NTZ(9)\")",
+    "functionName" : "`coalesce`",
+    "sqlExpr" : "\"coalesce(TIME '12:34:56', CAST(TIMESTAMP_NTZ '2020-05-17 
12:34:56.789012345' AS TIMESTAMP_NTZ(9)))\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 95,
+    "fragment" : "coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9))"
+  } ]
+}
+
+
+-- !query
+SELECT CASE WHEN true THEN time'12:34:56' ELSE timestamp_ntz'2020-05-17 
12:34:56' END
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "[\"TIME(6)\", \"TIMESTAMP_NTZ\"]",
+    "functionName" : "`casewhen`",
+    "sqlExpr" : "\"CASE WHEN true THEN TIME '12:34:56' ELSE TIMESTAMP_NTZ 
'2020-05-17 12:34:56' END\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 85,
+    "fragment" : "CASE WHEN true THEN time'12:34:56' ELSE 
timestamp_ntz'2020-05-17 12:34:56' END"
+  } ]
+}
diff --git 
a/sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/cast.sql.out 
b/sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/cast.sql.out
index c48776a1de31..eba639340d26 100644
--- 
a/sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/cast.sql.out
+++ 
b/sql/core/src/test/resources/sql-tests/analyzer-results/nonansi/cast.sql.out
@@ -1581,3 +1581,261 @@ SELECT CAST(time '23:59:59.999999999' AS decimal(14, 8))
 -- !query analysis
 Project [cast(23:59:59.999999999 as decimal(14,8)) AS CAST(TIME 
'23:59:59.999999999' AS DECIMAL(14,8))#x]
 +- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(6))
+-- !query analysis
+Project [cast(2020-05-17 12:34:56.789012 as time(6)) AS CAST(TIMESTAMP_NTZ 
'2020-05-17 12:34:56.789012' AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(3))
+-- !query analysis
+Project [cast(2020-05-17 12:34:56.789012 as time(3)) AS CAST(TIMESTAMP_NTZ 
'2020-05-17 12:34:56.789012' AS TIME(3))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(0))
+-- !query analysis
+Project [cast(2020-05-17 12:34:56.789012 as time(0)) AS CAST(TIMESTAMP_NTZ 
'2020-05-17 12:34:56.789012' AS TIME(0))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'1969-12-31 23:59:59.123456' AS TIME(6))
+-- !query analysis
+Project [cast(1969-12-31 23:59:59.123456 as time(6)) AS CAST(TIMESTAMP_NTZ 
'1969-12-31 23:59:59.123456' AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(9))
+-- !query analysis
+Project [cast(cast(2020-05-17 12:34:56.789012345 as timestamp_ntz(9)) as 
time(9)) AS CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(7))
+-- !query analysis
+Project [cast(cast(2020-05-17 12:34:56.789012345 as timestamp_ntz(9)) as 
time(7)) AS CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(7))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(6))
+-- !query analysis
+Project [cast(cast(2020-05-17 12:34:56.789012345 as timestamp_ntz(9)) as 
time(6)) AS CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(7) AS 
TIME(9))
+-- !query analysis
+Project [cast(cast(2020-05-17 12:34:56.789012345 as timestamp_ntz(7)) as 
time(9)) AS CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(7)) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT timestamp_ntz'2020-05-17 12:34:56.789012' :: TIME(6)
+-- !query analysis
+Project [cast(2020-05-17 12:34:56.789012 as time(6)) AS CAST(TIMESTAMP_NTZ 
'2020-05-17 12:34:56.789012' AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ))
+-- !query analysis
+Project [typeof(cast(12:34:56 as timestamp_ntz)) AS typeof(CAST(TIME 
'12:34:56' AS TIMESTAMP_NTZ))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ(9)))
+-- !query analysis
+Project [typeof(cast(12:34:56 as timestamp_ntz(9))) AS typeof(CAST(TIME 
'12:34:56' AS TIMESTAMP_NTZ(9)))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ) AS DATE) = current_date()
+-- !query analysis
+[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS DATE) = 
current_date()
+-- !query analysis
+[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6))
+-- !query analysis
+Project [cast(cast(12:34:56.789012 as timestamp_ntz) as time(6)) AS 
CAST(CAST(TIME '12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS TIME(9))
+-- !query analysis
+Project [cast(cast(12:34:56.789012345 as timestamp_ntz(9)) as time(9)) AS 
CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS TIME(9))
+-- !query analysis
+Project [cast(cast(12:34:56.789012345 as timestamp_ntz(7)) as time(9)) AS 
CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345'::time(9) AS TIMESTAMP_NTZ(6)) AS 
TIME(9))
+-- !query analysis
+Project [cast(cast(cast(12:34:56.789012345 as time(9)) as timestamp_ntz) as 
time(9)) AS CAST(CAST(CAST(TIME '12:34:56.789012345' AS TIME(9)) AS 
TIMESTAMP_NTZ) AS TIME(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ)
+-- !query analysis
+Project [cast(cast(null as time(6)) as timestamp_ntz) AS CAST(CAST(NULL AS 
TIME(6)) AS TIMESTAMP_NTZ)#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ(9))
+-- !query analysis
+Project [cast(cast(null as time(6)) as timestamp_ntz(9)) AS CAST(CAST(NULL AS 
TIME(6)) AS TIMESTAMP_NTZ(9))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ) AS TIME(6))
+-- !query analysis
+Project [cast(cast(null as timestamp_ntz) as time(6)) AS CAST(CAST(NULL AS 
TIMESTAMP_NTZ) AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS TIME(6))
+-- !query analysis
+Project [cast(cast(null as timestamp_ntz(9)) as time(6)) AS CAST(CAST(NULL AS 
TIMESTAMP_NTZ(9)) AS TIME(6))#x]
++- OneRowRelation
+
+
+-- !query
+SELECT CAST(x AS DATE) = current_date() FROM VALUES (CAST(TIME'12:34:56' AS 
TIMESTAMP_NTZ)) t(x)
+-- !query analysis
+[Analyzer test output redacted due to nondeterminism]
+
+
+-- !query
+SELECT CAST(x AS TIME(6)) FROM VALUES (CAST(TIME'12:34:56.789012' AS 
TIMESTAMP_NTZ)) t(x)
+-- !query analysis
+Project [cast(x#x as time(6)) AS x#x]
++- SubqueryAlias t
+   +- LocalRelation [x#x]
+
+
+-- !query
+SELECT CAST(x AS TIME(9)) FROM VALUES (CAST(TIME'12:34:56.789012345' AS 
TIMESTAMP_NTZ(9))) t(x)
+-- !query analysis
+Project [cast(x#x as time(9)) AS x#x]
++- SubqueryAlias t
+   +- LocalRelation [x#x]
+
+
+-- !query
+SELECT time'12:34:56' UNION ALL SELECT timestamp_ntz'2020-05-17 12:34:56'
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "INCOMPATIBLE_COLUMN_TYPE",
+  "sqlState" : "42825",
+  "messageParameters" : {
+    "columnOrdinalNumber" : "first",
+    "dataType1" : "\"TIMESTAMP_NTZ\"",
+    "dataType2" : "\"TIME(6)\"",
+    "hint" : "",
+    "operator" : "UNION",
+    "tableOrdinalNumber" : "second"
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 1,
+    "stopIndex" : 73,
+    "fragment" : "SELECT time'12:34:56' UNION ALL SELECT 
timestamp_ntz'2020-05-17 12:34:56'"
+  } ]
+}
+
+
+-- !query
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56')
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "(\"TIME(6)\" or \"TIMESTAMP_NTZ\")",
+    "functionName" : "`coalesce`",
+    "sqlExpr" : "\"coalesce(TIME '12:34:56', TIMESTAMP_NTZ '2020-05-17 
12:34:56')\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 67,
+    "fragment" : "coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56')"
+  } ]
+}
+
+
+-- !query
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9))
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "(\"TIME(6)\" or \"TIMESTAMP_NTZ(9)\")",
+    "functionName" : "`coalesce`",
+    "sqlExpr" : "\"coalesce(TIME '12:34:56', CAST(TIMESTAMP_NTZ '2020-05-17 
12:34:56.789012345' AS TIMESTAMP_NTZ(9)))\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 95,
+    "fragment" : "coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9))"
+  } ]
+}
+
+
+-- !query
+SELECT CASE WHEN true THEN time'12:34:56' ELSE timestamp_ntz'2020-05-17 
12:34:56' END
+-- !query analysis
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "[\"TIME(6)\", \"TIMESTAMP_NTZ\"]",
+    "functionName" : "`casewhen`",
+    "sqlExpr" : "\"CASE WHEN true THEN TIME '12:34:56' ELSE TIMESTAMP_NTZ 
'2020-05-17 12:34:56' END\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 85,
+    "fragment" : "CASE WHEN true THEN time'12:34:56' ELSE 
timestamp_ntz'2020-05-17 12:34:56' END"
+  } ]
+}
diff --git a/sql/core/src/test/resources/sql-tests/inputs/cast.sql 
b/sql/core/src/test/resources/sql-tests/inputs/cast.sql
index 87621d4413d3..e32dc528d1fd 100644
--- a/sql/core/src/test/resources/sql-tests/inputs/cast.sql
+++ b/sql/core/src/test/resources/sql-tests/inputs/cast.sql
@@ -324,3 +324,53 @@ SELECT CAST(time '23:59:59.9' AS decimal(6, 0));
 SELECT CAST(time '23:59:59.999' AS decimal(8, 2));
 SELECT CAST(time '23:59:59.999999' AS decimal(11, 5));
 SELECT CAST(time '23:59:59.999999999' AS decimal(14, 8));
+
+-- SPARK-57618: cast TIMESTAMP_NTZ(q) to TIME(p) extracts the time-of-day and 
truncates to p.
+-- This direction is deterministic and time-zone independent.
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(6));
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(3));
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(0));
+-- Pre-epoch wall-clock time-of-day is preserved.
+SELECT CAST(timestamp_ntz'1969-12-31 23:59:59.123456' AS TIME(6));
+-- Nanosecond TIMESTAMP_NTZ(q) preserves the sub-microsecond digits up to p.
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(9));
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(7));
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(6));
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(7) AS 
TIME(9));
+-- Double colon syntax.
+SELECT timestamp_ntz'2020-05-17 12:34:56.789012' :: TIME(6);
+
+-- SPARK-57618: cast TIME(p) to TIMESTAMP_NTZ(q) takes the date from 
CURRENT_DATE. SQL-layer
+-- coverage stays deterministic: type resolution, the date anchor equals 
current_date(), and the
+-- value round-trips back to TIME. The current-date stabilization is covered 
by ComputeCurrentTimeSuite
+-- and the value semantics by CastSuite* unit tests.
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ));
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ(9)));
+-- The date fields come from the query current date.
+SELECT CAST(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ) AS DATE) = current_date();
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS DATE) = 
current_date();
+-- Round-trips re-extract the original time-of-day (truncated to the 
intermediate precision).
+SELECT CAST(CAST(TIME'12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6));
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS TIME(9));
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS TIME(9));
+SELECT CAST(CAST(TIME'12:34:56.789012345'::time(9) AS TIMESTAMP_NTZ(6)) AS 
TIME(9));
+-- Null propagation in both directions.
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ);
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ(9));
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ) AS TIME(6));
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS TIME(6));
+
+-- SPARK-57618: inside an inline table the TIME -> TIMESTAMP_NTZ cast is 
foldable and carries no
+-- CURRENT_LIKE pattern, so it is early-evaluated before ComputeCurrentTime. 
Coverage stays
+-- deterministic: the date anchor still equals current_date() and the value 
round-trips back to TIME.
+SELECT CAST(x AS DATE) = current_date() FROM VALUES (CAST(TIME'12:34:56' AS 
TIMESTAMP_NTZ)) t(x);
+SELECT CAST(x AS TIME(6)) FROM VALUES (CAST(TIME'12:34:56.789012' AS 
TIMESTAMP_NTZ)) t(x);
+SELECT CAST(x AS TIME(9)) FROM VALUES (CAST(TIME'12:34:56.789012345' AS 
TIMESTAMP_NTZ(9))) t(x);
+
+-- SPARK-57618: TIME and TIMESTAMP_NTZ have no common type, so implicit 
coercion is rejected; an
+-- explicit CAST (as above) is required. This guards `findWiderDateTimeType` 
against ever widening
+-- TIME, which would silently inject CURRENT_DATE into UNION / coalesce / CASE.
+SELECT time'12:34:56' UNION ALL SELECT timestamp_ntz'2020-05-17 12:34:56';
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56');
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9));
+SELECT CASE WHEN true THEN time'12:34:56' ELSE timestamp_ntz'2020-05-17 
12:34:56' END;
diff --git a/sql/core/src/test/resources/sql-tests/results/cast.sql.out 
b/sql/core/src/test/resources/sql-tests/results/cast.sql.out
index a6d3cee116aa..223504de7397 100644
--- a/sql/core/src/test/resources/sql-tests/results/cast.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/cast.sql.out
@@ -2871,3 +2871,294 @@ SELECT CAST(time '23:59:59.999999999' AS decimal(14, 8))
 struct<CAST(TIME '23:59:59.999999999' AS DECIMAL(14,8)):decimal(14,8)>
 -- !query output
 86400.00000000
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(6))
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012' AS TIME(6)):time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(3))
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012' AS TIME(3)):time(3)>
+-- !query output
+12:34:56.789
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(0))
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012' AS TIME(0)):time(0)>
+-- !query output
+12:34:56
+
+
+-- !query
+SELECT CAST(timestamp_ntz'1969-12-31 23:59:59.123456' AS TIME(6))
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '1969-12-31 23:59:59.123456' AS TIME(6)):time(6)>
+-- !query output
+23:59:59.123456
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(9))
+-- !query schema
+struct<CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(9)):time(9)>
+-- !query output
+12:34:56.789012345
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(7))
+-- !query schema
+struct<CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(7)):time(7)>
+-- !query output
+12:34:56.7890123
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(6))
+-- !query schema
+struct<CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(6)):time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(7) AS 
TIME(9))
+-- !query schema
+struct<CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(7)) AS TIME(9)):time(9)>
+-- !query output
+12:34:56.7890123
+
+
+-- !query
+SELECT timestamp_ntz'2020-05-17 12:34:56.789012' :: TIME(6)
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012' AS TIME(6)):time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ))
+-- !query schema
+struct<typeof(CAST(TIME '12:34:56' AS TIMESTAMP_NTZ)):string>
+-- !query output
+timestamp_ntz
+
+
+-- !query
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ(9)))
+-- !query schema
+struct<typeof(CAST(TIME '12:34:56' AS TIMESTAMP_NTZ(9))):string>
+-- !query output
+timestamp_ntz(9)
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ) AS DATE) = current_date()
+-- !query schema
+struct<(CAST(CAST(TIME '12:34:56' AS TIMESTAMP_NTZ) AS DATE) = 
current_date()):boolean>
+-- !query output
+true
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS DATE) = 
current_date()
+-- !query schema
+struct<(CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS DATE) = 
current_date()):boolean>
+-- !query output
+true
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6))
+-- !query schema
+struct<CAST(CAST(TIME '12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6)):time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS TIME(9))
+-- !query schema
+struct<CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS 
TIME(9)):time(9)>
+-- !query output
+12:34:56.789012345
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS TIME(9))
+-- !query schema
+struct<CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS 
TIME(9)):time(9)>
+-- !query output
+12:34:56.7890123
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345'::time(9) AS TIMESTAMP_NTZ(6)) AS 
TIME(9))
+-- !query schema
+struct<CAST(CAST(CAST(TIME '12:34:56.789012345' AS TIME(9)) AS TIMESTAMP_NTZ) 
AS TIME(9)):time(9)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ)
+-- !query schema
+struct<CAST(CAST(NULL AS TIME(6)) AS TIMESTAMP_NTZ):timestamp_ntz>
+-- !query output
+NULL
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ(9))
+-- !query schema
+struct<CAST(CAST(NULL AS TIME(6)) AS TIMESTAMP_NTZ(9)):timestamp_ntz(9)>
+-- !query output
+NULL
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ) AS TIME(6))
+-- !query schema
+struct<CAST(CAST(NULL AS TIMESTAMP_NTZ) AS TIME(6)):time(6)>
+-- !query output
+NULL
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS TIME(6))
+-- !query schema
+struct<CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS TIME(6)):time(6)>
+-- !query output
+NULL
+
+
+-- !query
+SELECT CAST(x AS DATE) = current_date() FROM VALUES (CAST(TIME'12:34:56' AS 
TIMESTAMP_NTZ)) t(x)
+-- !query schema
+struct<(CAST(x AS DATE) = current_date()):boolean>
+-- !query output
+true
+
+
+-- !query
+SELECT CAST(x AS TIME(6)) FROM VALUES (CAST(TIME'12:34:56.789012' AS 
TIMESTAMP_NTZ)) t(x)
+-- !query schema
+struct<x:time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(x AS TIME(9)) FROM VALUES (CAST(TIME'12:34:56.789012345' AS 
TIMESTAMP_NTZ(9))) t(x)
+-- !query schema
+struct<x:time(9)>
+-- !query output
+12:34:56.789012345
+
+
+-- !query
+SELECT time'12:34:56' UNION ALL SELECT timestamp_ntz'2020-05-17 12:34:56'
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "INCOMPATIBLE_COLUMN_TYPE",
+  "sqlState" : "42825",
+  "messageParameters" : {
+    "columnOrdinalNumber" : "first",
+    "dataType1" : "\"TIMESTAMP_NTZ\"",
+    "dataType2" : "\"TIME(6)\"",
+    "hint" : "",
+    "operator" : "UNION",
+    "tableOrdinalNumber" : "second"
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 1,
+    "stopIndex" : 73,
+    "fragment" : "SELECT time'12:34:56' UNION ALL SELECT 
timestamp_ntz'2020-05-17 12:34:56'"
+  } ]
+}
+
+
+-- !query
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56')
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "(\"TIME(6)\" or \"TIMESTAMP_NTZ\")",
+    "functionName" : "`coalesce`",
+    "sqlExpr" : "\"coalesce(TIME '12:34:56', TIMESTAMP_NTZ '2020-05-17 
12:34:56')\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 67,
+    "fragment" : "coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56')"
+  } ]
+}
+
+
+-- !query
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9))
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "(\"TIME(6)\" or \"TIMESTAMP_NTZ(9)\")",
+    "functionName" : "`coalesce`",
+    "sqlExpr" : "\"coalesce(TIME '12:34:56', CAST(TIMESTAMP_NTZ '2020-05-17 
12:34:56.789012345' AS TIMESTAMP_NTZ(9)))\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 95,
+    "fragment" : "coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9))"
+  } ]
+}
+
+
+-- !query
+SELECT CASE WHEN true THEN time'12:34:56' ELSE timestamp_ntz'2020-05-17 
12:34:56' END
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "[\"TIME(6)\", \"TIMESTAMP_NTZ\"]",
+    "functionName" : "`casewhen`",
+    "sqlExpr" : "\"CASE WHEN true THEN TIME '12:34:56' ELSE TIMESTAMP_NTZ 
'2020-05-17 12:34:56' END\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 85,
+    "fragment" : "CASE WHEN true THEN time'12:34:56' ELSE 
timestamp_ntz'2020-05-17 12:34:56' END"
+  } ]
+}
diff --git a/sql/core/src/test/resources/sql-tests/results/nonansi/cast.sql.out 
b/sql/core/src/test/resources/sql-tests/results/nonansi/cast.sql.out
index 1bc9c12b0421..18ce49c59bbf 100644
--- a/sql/core/src/test/resources/sql-tests/results/nonansi/cast.sql.out
+++ b/sql/core/src/test/resources/sql-tests/results/nonansi/cast.sql.out
@@ -1871,3 +1871,294 @@ SELECT CAST(time '23:59:59.999999999' AS decimal(14, 8))
 struct<CAST(TIME '23:59:59.999999999' AS DECIMAL(14,8)):decimal(14,8)>
 -- !query output
 86400.00000000
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(6))
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012' AS TIME(6)):time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(3))
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012' AS TIME(3)):time(3)>
+-- !query output
+12:34:56.789
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012' AS TIME(0))
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012' AS TIME(0)):time(0)>
+-- !query output
+12:34:56
+
+
+-- !query
+SELECT CAST(timestamp_ntz'1969-12-31 23:59:59.123456' AS TIME(6))
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '1969-12-31 23:59:59.123456' AS TIME(6)):time(6)>
+-- !query output
+23:59:59.123456
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(9))
+-- !query schema
+struct<CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(9)):time(9)>
+-- !query output
+12:34:56.789012345
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(7))
+-- !query schema
+struct<CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(7)):time(7)>
+-- !query output
+12:34:56.7890123
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(9) AS 
TIME(6))
+-- !query schema
+struct<CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(9)) AS TIME(6)):time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(timestamp_ntz'2020-05-17 12:34:56.789012345'::timestamp_ntz(7) AS 
TIME(9))
+-- !query schema
+struct<CAST(CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012345' AS 
TIMESTAMP_NTZ(7)) AS TIME(9)):time(9)>
+-- !query output
+12:34:56.7890123
+
+
+-- !query
+SELECT timestamp_ntz'2020-05-17 12:34:56.789012' :: TIME(6)
+-- !query schema
+struct<CAST(TIMESTAMP_NTZ '2020-05-17 12:34:56.789012' AS TIME(6)):time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ))
+-- !query schema
+struct<typeof(CAST(TIME '12:34:56' AS TIMESTAMP_NTZ)):string>
+-- !query output
+timestamp_ntz
+
+
+-- !query
+SELECT typeof(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ(9)))
+-- !query schema
+struct<typeof(CAST(TIME '12:34:56' AS TIMESTAMP_NTZ(9))):string>
+-- !query output
+timestamp_ntz(9)
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56' AS TIMESTAMP_NTZ) AS DATE) = current_date()
+-- !query schema
+struct<(CAST(CAST(TIME '12:34:56' AS TIMESTAMP_NTZ) AS DATE) = 
current_date()):boolean>
+-- !query output
+true
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS DATE) = 
current_date()
+-- !query schema
+struct<(CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS DATE) = 
current_date()):boolean>
+-- !query output
+true
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6))
+-- !query schema
+struct<CAST(CAST(TIME '12:34:56.789012' AS TIMESTAMP_NTZ) AS TIME(6)):time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS TIME(9))
+-- !query schema
+struct<CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(9)) AS 
TIME(9)):time(9)>
+-- !query output
+12:34:56.789012345
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS TIME(9))
+-- !query schema
+struct<CAST(CAST(TIME '12:34:56.789012345' AS TIMESTAMP_NTZ(7)) AS 
TIME(9)):time(9)>
+-- !query output
+12:34:56.7890123
+
+
+-- !query
+SELECT CAST(CAST(TIME'12:34:56.789012345'::time(9) AS TIMESTAMP_NTZ(6)) AS 
TIME(9))
+-- !query schema
+struct<CAST(CAST(CAST(TIME '12:34:56.789012345' AS TIME(9)) AS TIMESTAMP_NTZ) 
AS TIME(9)):time(9)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ)
+-- !query schema
+struct<CAST(CAST(NULL AS TIME(6)) AS TIMESTAMP_NTZ):timestamp_ntz>
+-- !query output
+NULL
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIME) AS TIMESTAMP_NTZ(9))
+-- !query schema
+struct<CAST(CAST(NULL AS TIME(6)) AS TIMESTAMP_NTZ(9)):timestamp_ntz(9)>
+-- !query output
+NULL
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ) AS TIME(6))
+-- !query schema
+struct<CAST(CAST(NULL AS TIMESTAMP_NTZ) AS TIME(6)):time(6)>
+-- !query output
+NULL
+
+
+-- !query
+SELECT CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS TIME(6))
+-- !query schema
+struct<CAST(CAST(NULL AS TIMESTAMP_NTZ(9)) AS TIME(6)):time(6)>
+-- !query output
+NULL
+
+
+-- !query
+SELECT CAST(x AS DATE) = current_date() FROM VALUES (CAST(TIME'12:34:56' AS 
TIMESTAMP_NTZ)) t(x)
+-- !query schema
+struct<(CAST(x AS DATE) = current_date()):boolean>
+-- !query output
+true
+
+
+-- !query
+SELECT CAST(x AS TIME(6)) FROM VALUES (CAST(TIME'12:34:56.789012' AS 
TIMESTAMP_NTZ)) t(x)
+-- !query schema
+struct<x:time(6)>
+-- !query output
+12:34:56.789012
+
+
+-- !query
+SELECT CAST(x AS TIME(9)) FROM VALUES (CAST(TIME'12:34:56.789012345' AS 
TIMESTAMP_NTZ(9))) t(x)
+-- !query schema
+struct<x:time(9)>
+-- !query output
+12:34:56.789012345
+
+
+-- !query
+SELECT time'12:34:56' UNION ALL SELECT timestamp_ntz'2020-05-17 12:34:56'
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "INCOMPATIBLE_COLUMN_TYPE",
+  "sqlState" : "42825",
+  "messageParameters" : {
+    "columnOrdinalNumber" : "first",
+    "dataType1" : "\"TIMESTAMP_NTZ\"",
+    "dataType2" : "\"TIME(6)\"",
+    "hint" : "",
+    "operator" : "UNION",
+    "tableOrdinalNumber" : "second"
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 1,
+    "stopIndex" : 73,
+    "fragment" : "SELECT time'12:34:56' UNION ALL SELECT 
timestamp_ntz'2020-05-17 12:34:56'"
+  } ]
+}
+
+
+-- !query
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56')
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "(\"TIME(6)\" or \"TIMESTAMP_NTZ\")",
+    "functionName" : "`coalesce`",
+    "sqlExpr" : "\"coalesce(TIME '12:34:56', TIMESTAMP_NTZ '2020-05-17 
12:34:56')\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 67,
+    "fragment" : "coalesce(time'12:34:56', timestamp_ntz'2020-05-17 12:34:56')"
+  } ]
+}
+
+
+-- !query
+SELECT coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9))
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "(\"TIME(6)\" or \"TIMESTAMP_NTZ(9)\")",
+    "functionName" : "`coalesce`",
+    "sqlExpr" : "\"coalesce(TIME '12:34:56', CAST(TIMESTAMP_NTZ '2020-05-17 
12:34:56.789012345' AS TIMESTAMP_NTZ(9)))\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 95,
+    "fragment" : "coalesce(time'12:34:56', timestamp_ntz'2020-05-17 
12:34:56.789012345'::timestamp_ntz(9))"
+  } ]
+}
+
+
+-- !query
+SELECT CASE WHEN true THEN time'12:34:56' ELSE timestamp_ntz'2020-05-17 
12:34:56' END
+-- !query schema
+struct<>
+-- !query output
+org.apache.spark.sql.catalyst.ExtendedAnalysisException
+{
+  "errorClass" : "DATATYPE_MISMATCH.DATA_DIFF_TYPES",
+  "sqlState" : "42K09",
+  "messageParameters" : {
+    "dataType" : "[\"TIME(6)\", \"TIMESTAMP_NTZ\"]",
+    "functionName" : "`casewhen`",
+    "sqlExpr" : "\"CASE WHEN true THEN TIME '12:34:56' ELSE TIMESTAMP_NTZ 
'2020-05-17 12:34:56' END\""
+  },
+  "queryContext" : [ {
+    "objectType" : "",
+    "objectName" : "",
+    "startIndex" : 8,
+    "stopIndex" : 85,
+    "fragment" : "CASE WHEN true THEN time'12:34:56' ELSE 
timestamp_ntz'2020-05-17 12:34:56' END"
+  } ]
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to