spark-test commented on code in PR #59955:
URL: https://github.com/apache/spark/pull/59955#discussion_r4423408150


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala:
##########
@@ -1105,6 +1105,34 @@ object DateTimeUtils extends SparkDateTimeUtils {
     }
   }
 
+  /** The whole seconds and the nanos of the second of a seconds value with a 
fraction. */
+  case class SecondsAndNanos(seconds: Int, nanos: Int)
+
+  /**
+   * Splits the seconds of a minute with a fraction of 6 digits (microseconds) 
into the whole
+   * seconds and the nanos of the second, as `LocalTime.of` and 
`LocalDateTime.of` take them.
+   *
+   * The whole seconds are checked to be in the int range and not negative 
before they are
+   * narrowed. A value outside of the int range would overflow when converted 
from long to int,
+   * and could produce an int in the valid seconds range and return a wrong 
value, or a misleading
+   * error message. A negative value is rejected here for a better error 
message: `Math.floorDiv`
+   * gets the next lower integer for it, so the full seconds would not match 
the value given.
+   * The message is the one that `LocalTime.of` and `LocalDateTime.of` throw 
for invalid seconds,
+   * with the seconds given, truncated towards zero. Any other value, such as 
61 seconds, is
+   * left to them, which check their fields in order, so an invalid date or 
hour is reported
+   * before such seconds, while a negative value or one above `Int.MaxValue` 
is reported first.
+   */
+  def splitSecsAndMicros(secsAndMicros: Decimal): SecondsAndNanos = {
+    val unscaledSecFrac = secsAndMicros.toUnscaledLong
+    val fullSecs = Math.floorDiv(unscaledSecFrac, MICROS_PER_SECOND)
+    if (fullSecs > Int.MaxValue || fullSecs < 0) {
+      throw new DateTimeException(
+        s"Invalid value for SecondOfMinute (valid values 0 - 59): 
${secsAndMicros.toLong}")

Review Comment:
   **Nit (P3):** This split rejects on the floored whole seconds but prints 
`secsAndMicros.toLong`, which truncates towards zero. For a seconds value 
strictly between -1 and 0, such as `make_timestamp(2020, 1, 1, 0, 0, -0.5)`, 
`Math.floorDiv` gives -1, so the value is rejected, but the message reads 
`Invalid value for SecondOfMinute (valid values 0 - 59): 0`. That names a valid 
second as the invalid one and hides the input. Before this change, 
make_timestamp reported -1 here (through `LocalDateTime.of`). make_time already 
printed 0, and routing `makeTimestampMicros` through this helper now carries 
that to make_timestamp, make_timestamp_ltz and make_timestamp_ntz with ANSI 
mode on. Only the message is affected: the error class and SQLSTATE are right, 
and ANSI-off and `try_make_timestamp*` calls still return NULL. The new cases 
stop at -4264.967296, so no test covers this range.
   
   One way to fix it: when the given value lies strictly between -1 and 0, 
report it as given (for example -0.5), and keep the truncated whole seconds for 
every other rejected value. Then update this Scaladoc and the comment in the 
new `DateExpressionsSuite` test, which both state the truncation rule. Because 
make_time shares the helper, this also corrects its message for the same range.
   
   **Verification:**
   - **Regression:** Evaluate make_timestamp with seconds -0.5 and -0.000001 
for both TIMESTAMP and TIMESTAMP_NTZ results through interpreted and 
code-generated evaluation. With ANSI mode on, assert 
DATETIME_FIELD_OUT_OF_BOUNDS.WITHOUT_SUGGESTION with a rangeMessage naming the 
given negative value; with ANSI mode off, assert NULL.
   - **Regression:** Convert hour, minute and seconds -0.5 with the make_time 
conversion and assert the same DATETIME_FIELD_OUT_OF_BOUNDS rangeMessage naming 
-0.5.
   - **Compatibility:** Confirm that the existing out-of-range seconds 
expectations for make_timestamp and make_time (2147.483647 through 
9999999999.999999, -4264.967296, -9999999999.999999, -999999999.999999, 
4294967297.999999, 61, 60.0 and 100.5), the timestamp SQL golden outputs and 
the time SQL golden output for make_time(1, 18, -999999999.999999) keep their 
messages and NULL results unchanged.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to