-
Notifications
You must be signed in to change notification settings - Fork 29k
[SPARK-54442][SQL][FOLLOWUP] Add codegen for TIME numeric conversion functions #53370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
26c4e4f
64f386b
3b8ca13
2130498
50e6885
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -897,6 +897,102 @@ object DateTimeUtils extends SparkDateTimeUtils { | |
| } | ||
| } | ||
|
|
||
| private def withTimeConversionErrorHandling(f: => Long): Long = { | ||
| try { | ||
| val nanos = f | ||
| if (nanos < 0 || nanos >= NANOS_PER_DAY) { | ||
| throw new DateTimeException( | ||
| s"Invalid TIME value: must be between 00:00:00 and 23:59:59.999999999, " + | ||
| s"but got $nanos nanoseconds") | ||
| } | ||
| nanos | ||
| } catch { | ||
| case e: DateTimeException => | ||
| throw QueryExecutionErrors.ansiDateTimeArgumentOutOfRangeWithoutSuggestion(e) | ||
| case e: ArithmeticException => | ||
| throw QueryExecutionErrors.ansiDateTimeArgumentOutOfRangeWithoutSuggestion( | ||
| new DateTimeException("Overflow in TIME conversion", e)) | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Creates a TIME value from seconds since midnight (integral types). | ||
| * @param seconds Seconds (0 to 86399) | ||
| * @return Nanoseconds since midnight | ||
| */ | ||
| def timeFromSeconds(seconds: Long): Long = withTimeConversionErrorHandling { | ||
| Math.multiplyExact(seconds, NANOS_PER_SECOND) | ||
| } | ||
|
|
||
| /** | ||
| * Creates a TIME value from seconds since midnight (decimal type). | ||
| * @param seconds Seconds (0 to 86399.999999) | ||
| * @return Nanoseconds since midnight | ||
| */ | ||
| def timeFromSeconds(seconds: Decimal): Long = withTimeConversionErrorHandling { | ||
| val operand = new java.math.BigDecimal(NANOS_PER_SECOND) | ||
| seconds.toJavaBigDecimal.multiply(operand).longValueExact() | ||
| } | ||
|
|
||
| /** | ||
| * Creates a TIME value from seconds since midnight (floating point type). | ||
| * @param seconds Seconds (0 to 86399.999999) | ||
| * @return Nanoseconds since midnight | ||
| */ | ||
| def timeFromSeconds(seconds: Double): Long = withTimeConversionErrorHandling { | ||
| if (seconds.isNaN || seconds.isInfinite) { | ||
| throw new DateTimeException("Cannot convert NaN or Infinite value to TIME") | ||
| } | ||
| (seconds * NANOS_PER_SECOND).toLong | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need to consider overflow here when calling
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's the resolution?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. or overflow can never happen here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, overflow can happen, but it is already handled in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you sure?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Double.toLong can produce overflow results (when the Double is too large/small): I tested with -1e199 , 1e200 |
||
| } | ||
|
|
||
| /** | ||
| * Creates a TIME value from milliseconds since midnight. | ||
| * @param millis Milliseconds (0 to 86399999) | ||
| * @return Nanoseconds since midnight | ||
| */ | ||
| def timeFromMillis(millis: Long): Long = withTimeConversionErrorHandling { | ||
| Math.multiplyExact(millis, NANOS_PER_MILLIS) | ||
| } | ||
|
|
||
| /** | ||
| * Creates a TIME value from microseconds since midnight. | ||
| * @param micros Microseconds (0 to 86399999999) | ||
| * @return Nanoseconds since midnight | ||
| */ | ||
| def timeFromMicros(micros: Long): Long = withTimeConversionErrorHandling { | ||
| Math.multiplyExact(micros, NANOS_PER_MICROS) | ||
| } | ||
|
|
||
| /** | ||
| * Converts a TIME value to seconds. | ||
| * @param nanos Nanoseconds since midnight | ||
| * @return Seconds as Decimal(14, 6) | ||
| */ | ||
| def timeToSeconds(nanos: Long): Decimal = { | ||
vinodkc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| val result = Decimal(nanos) / Decimal(NANOS_PER_SECOND) | ||
| result.changePrecision(14, 6) | ||
| result | ||
| } | ||
|
|
||
| /** | ||
| * Converts a TIME value to milliseconds. | ||
| * @param nanos Nanoseconds since midnight | ||
| * @return Milliseconds since midnight | ||
| */ | ||
| def timeToMillis(nanos: Long): Long = { | ||
| Math.floorDiv(nanos, NANOS_PER_MILLIS) | ||
| } | ||
|
|
||
| /** | ||
| * Converts a TIME value to microseconds. | ||
| * @param nanos Nanoseconds since midnight | ||
| * @return Microseconds since midnight | ||
| */ | ||
| def timeToMicros(nanos: Long): Long = { | ||
| Math.floorDiv(nanos, NANOS_PER_MICROS) | ||
| } | ||
|
|
||
| /** | ||
| * Makes a timestamp without time zone from a date and a local time. | ||
| * | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.