-
Notifications
You must be signed in to change notification settings - Fork 79
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
feat: Added query library functions to overload Period and Duration arithmetic #5509
Changes from 8 commits
98bb980
655f4d0
7130dcc
066a724
8a29e47
e5fddc5
c0a0dc4
5a11c27
b489cf4
09d40d3
f9d369d
758d808
d805d5e
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 |
---|---|---|
|
@@ -24,8 +24,7 @@ | |
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
import static io.deephaven.util.QueryConstants.NULL_INT; | ||
import static io.deephaven.util.QueryConstants.NULL_LONG; | ||
import static io.deephaven.util.QueryConstants.*; | ||
import static java.time.format.DateTimeFormatter.*; | ||
|
||
/** | ||
|
@@ -1652,6 +1651,44 @@ public static ZonedDateTime plus(@Nullable final ZonedDateTime dateTime, @Nullab | |
} | ||
} | ||
|
||
/** | ||
* Adds two durations. | ||
* | ||
* @param duration1 first duration | ||
* @param duration2 second duration | ||
* @return {@code null} if either input is {@code null}; otherwise the sum of the two durations | ||
*/ | ||
public static Duration plus(@Nullable final Duration duration1, @Nullable final Duration duration2) { | ||
if (duration1 == null || duration2 == null) { | ||
return null; | ||
} | ||
|
||
try { | ||
return duration1.plus(duration2); | ||
} catch (Exception ex) { | ||
throw new DateTimeOverflowException(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Adds two periods. | ||
* | ||
* @param period1 first period | ||
* @param period2 second period | ||
* @return {@code null} if either input is {@code null}; otherwise the sum of the two periods | ||
*/ | ||
public static Period plus(@Nullable final Period period1, @Nullable final Period period2) { | ||
if (period1 == null || period2 == null) { | ||
return null; | ||
} | ||
|
||
try { | ||
return period1.plus(period2); | ||
} catch (Exception ex) { | ||
throw new DateTimeOverflowException(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Subtracts days from a {@link LocalDate}. | ||
* | ||
|
@@ -1871,6 +1908,153 @@ public static long minus(@Nullable final ZonedDateTime dateTime1, @Nullable fina | |
return checkUnderflowMinus(epochNanos(dateTime1), epochNanos(dateTime2), true); | ||
} | ||
|
||
/** | ||
* Subtracts two durations. | ||
* | ||
* @param duration1 first duration | ||
* @param duration2 second duration | ||
* @return {@code null} if either input is {@code null}; otherwise the difference of the two durations | ||
*/ | ||
public static Duration minus(@Nullable final Duration duration1, @Nullable final Duration duration2) { | ||
if (duration1 == null || duration2 == null) { | ||
return null; | ||
} | ||
|
||
try { | ||
return duration1.minus(duration2); | ||
} catch (Exception ex) { | ||
throw new DateTimeOverflowException(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Subtracts two periods. | ||
* | ||
* @param period1 first period | ||
* @param period2 second period | ||
* @return {@code null} if either input is {@code null}; otherwise the difference of the two periods | ||
*/ | ||
public static Period minus(@Nullable final Period period1, @Nullable final Period period2) { | ||
if (period1 == null || period2 == null) { | ||
return null; | ||
} | ||
|
||
try { | ||
return period1.minus(period2); | ||
} catch (Exception ex) { | ||
throw new DateTimeOverflowException(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Multiply a duration by a scalar. | ||
* | ||
* @param duration the duration to multiply | ||
* @param scalar the scalar to multiply by | ||
* @return {@code null} if either input is {@code null}; otherwise the duration multiplied by the scalar | ||
*/ | ||
public static Duration multiply(final Duration duration, final long scalar) { | ||
if (duration == null || scalar == NULL_LONG) { | ||
return null; | ||
} | ||
|
||
try { | ||
return duration.multipliedBy(scalar); | ||
} catch (ArithmeticException ex) { | ||
throw new DateTimeOverflowException(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Multiply a duration by a scalar. | ||
* | ||
* @param duration the duration to multiply | ||
* @param scalar the scalar to multiply by | ||
* @return {@code null} if either input is {@code null}; otherwise the duration multiplied by the scalar | ||
*/ | ||
public static Duration multiply(final long scalar, final Duration duration) { | ||
return multiply(duration, scalar); | ||
} | ||
|
||
/** | ||
* Multiply a period by a scalar. | ||
* | ||
* @param period the period to multiply | ||
* @param scalar the scalar to multiply by | ||
* @return {@code null} if either input is {@code null}; otherwise the period multiplied by the scalar | ||
*/ | ||
public static Period multiply(final Period period, final int scalar) { | ||
if (period == null || scalar == NULL_INT) { | ||
return null; | ||
} | ||
|
||
try { | ||
return period.multipliedBy(scalar); | ||
} catch (ArithmeticException ex) { | ||
throw new DateTimeOverflowException(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Multiply a period by a scalar. | ||
* | ||
* @param period the period to multiply | ||
* @param scalar the scalar to multiply by | ||
* @return {@code null} if either input is {@code null}; otherwise the period multiplied by the scalar | ||
*/ | ||
public static Period multiply(final int scalar, final Period period) { | ||
return multiply(period, scalar); | ||
} | ||
|
||
/** | ||
* Multiply a period by a scalar. | ||
* | ||
* @param period the period to multiply | ||
* @param scalar the scalar to multiply by | ||
* @return {@code null} if either input is {@code null}; otherwise the period multiplied by the scalar | ||
*/ | ||
public static Period multiply(final Period period, final long scalar) { | ||
if (period == null || scalar == NULL_LONG) { | ||
return null; | ||
} | ||
|
||
if (scalar > Integer.MAX_VALUE || scalar < Integer.MIN_VALUE) { | ||
throw new DateTimeOverflowException("Scalar value is too large to be cast to an int"); | ||
} | ||
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. Why provide a 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. The lack of a long version was the first complaint when @alexpeters1208 did user testing. 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. (makes sense to me to have this — it's easy to wind up with 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. I don't like this argument. The same could be said for any int-based method "why doesn't it accept a long?". Should we create a version of this that works with 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. I'm with Devin, here. If we don't accept 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. I agree with @rbasralian on this. Stuff like this happens frequently in real queries. 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. If this is happening frequently in real queries, we should address the root cause of it: "Why are logical int columns typed as longs?". 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. This isn't something we're doing elsewhere in our libraries. It isn't something users should expect from libraries generally. |
||
|
||
return period.multipliedBy((int) scalar); | ||
} | ||
|
||
/** | ||
* Multiply a period by a scalar. | ||
* | ||
* @param period the period to multiply | ||
* @param scalar the scalar to multiply by | ||
* @return {@code null} if either input is {@code null}; otherwise the period multiplied by the scalar | ||
*/ | ||
public static Period multiply(final long scalar, final Period period) { | ||
return multiply(period, scalar); | ||
} | ||
|
||
/** | ||
* Divide a duration by a scalar. | ||
* | ||
* @param duration the duration to divide | ||
* @param scalar the scalar to divide by | ||
* @return {@code null} if either input is {@code null}; otherwise the duration divide by the scalar | ||
*/ | ||
public static Duration divide(final Duration duration, final long scalar) { | ||
if (duration == null || scalar == NULL_LONG) { | ||
return null; | ||
} | ||
|
||
try { | ||
return duration.dividedBy(scalar); | ||
} catch (ArithmeticException ex) { | ||
throw new DateTimeOverflowException(ex); | ||
} | ||
} | ||
|
||
/** | ||
* Returns the difference in nanoseconds between two instant values. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is inconsistent (although probably more correct) than the versions that
catch (Exception ex)
. The date time operations typically document throwing:So, when we catch
Exception
and re-wrap inDateTimeOverflowException
, we might be "lying" b/c this could be caused by something other than overflow.I see this pattern is used widely in DateTimeUtils, I think imprecisely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have adjusted the handling to be:
Overflows can come through either exception.
java.time
does useDateTimeException
for other problems, but those problems should not be in the methods here.