|
6 | 6 |
|
7 | 7 | package org.opensearch.sql.expression.datetime;
|
8 | 8 |
|
| 9 | +import static java.time.temporal.ChronoUnit.DAYS; |
9 | 10 | import static java.time.temporal.ChronoUnit.MONTHS;
|
10 | 11 | import static org.opensearch.sql.data.type.ExprCoreType.DATE;
|
11 | 12 | import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;
|
|
20 | 21 | import static org.opensearch.sql.expression.function.FunctionDSL.impl;
|
21 | 22 | import static org.opensearch.sql.expression.function.FunctionDSL.implWithProperties;
|
22 | 23 | import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandling;
|
| 24 | +import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandlingWithProperties; |
23 | 25 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_FORMATTER_LONG_YEAR;
|
24 | 26 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_FORMATTER_SHORT_YEAR;
|
25 | 27 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_LONG_YEAR;
|
26 | 28 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_SHORT_YEAR;
|
27 | 29 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_STRICT_WITH_TZ;
|
| 30 | +import static org.opensearch.sql.utils.DateTimeUtils.extractDate; |
28 | 31 |
|
29 | 32 | import java.math.BigDecimal;
|
30 | 33 | import java.math.RoundingMode;
|
31 | 34 | import java.text.DecimalFormat;
|
32 | 35 | import java.time.Clock;
|
33 | 36 | import java.time.DateTimeException;
|
| 37 | +import java.time.Duration; |
34 | 38 | import java.time.Instant;
|
35 | 39 | import java.time.LocalDate;
|
36 | 40 | import java.time.LocalDateTime;
|
|
63 | 67 | import org.opensearch.sql.expression.function.DefaultFunctionResolver;
|
64 | 68 | import org.opensearch.sql.expression.function.FunctionDSL;
|
65 | 69 | import org.opensearch.sql.expression.function.FunctionName;
|
| 70 | +import org.opensearch.sql.expression.function.FunctionProperties; |
66 | 71 | import org.opensearch.sql.expression.function.FunctionResolver;
|
67 | 72 | import org.opensearch.sql.utils.DateTimeUtils;
|
68 | 73 |
|
@@ -95,6 +100,7 @@ public void register(BuiltinFunctionRepository repository) {
|
95 | 100 | repository.register(current_time());
|
96 | 101 | repository.register(current_timestamp());
|
97 | 102 | repository.register(date());
|
| 103 | + repository.register(datediff()); |
98 | 104 | repository.register(datetime());
|
99 | 105 | repository.register(date_add());
|
100 | 106 | repository.register(date_sub());
|
@@ -125,6 +131,7 @@ public void register(BuiltinFunctionRepository repository) {
|
125 | 131 | repository.register(sysdate());
|
126 | 132 | repository.register(time());
|
127 | 133 | repository.register(time_to_sec());
|
| 134 | + repository.register(timediff()); |
128 | 135 | repository.register(timestamp());
|
129 | 136 | repository.register(date_format());
|
130 | 137 | repository.register(to_days());
|
@@ -261,6 +268,46 @@ private DefaultFunctionResolver date() {
|
261 | 268 | impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP));
|
262 | 269 | }
|
263 | 270 |
|
| 271 | + /* |
| 272 | + * Calculates the difference of date part of given values. |
| 273 | + * (DATE/DATETIME/TIMESTAMP/TIME, DATE/DATETIME/TIMESTAMP/TIME) -> LONG |
| 274 | + */ |
| 275 | + private DefaultFunctionResolver datediff() { |
| 276 | + return define(BuiltinFunctionName.DATEDIFF.getName(), |
| 277 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 278 | + LONG, DATE, DATE), |
| 279 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 280 | + LONG, DATETIME, DATE), |
| 281 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 282 | + LONG, DATE, DATETIME), |
| 283 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 284 | + LONG, DATETIME, DATETIME), |
| 285 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 286 | + LONG, DATE, TIME), |
| 287 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 288 | + LONG, TIME, DATE), |
| 289 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 290 | + LONG, TIME, TIME), |
| 291 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 292 | + LONG, TIMESTAMP, DATE), |
| 293 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 294 | + LONG, DATE, TIMESTAMP), |
| 295 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 296 | + LONG, TIMESTAMP, TIMESTAMP), |
| 297 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 298 | + LONG, TIMESTAMP, TIME), |
| 299 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 300 | + LONG, TIME, TIMESTAMP), |
| 301 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 302 | + LONG, TIMESTAMP, DATETIME), |
| 303 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 304 | + LONG, DATETIME, TIMESTAMP), |
| 305 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 306 | + LONG, TIME, DATETIME), |
| 307 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 308 | + LONG, DATETIME, TIME)); |
| 309 | + } |
| 310 | + |
264 | 311 | /**
|
265 | 312 | * Specify a datetime with time zone field and a time zone to convert to.
|
266 | 313 | * Returns a local date time.
|
@@ -519,6 +566,22 @@ private DefaultFunctionResolver time() {
|
519 | 566 | impl(nullMissingHandling(DateTimeFunction::exprTime), TIME, TIMESTAMP));
|
520 | 567 | }
|
521 | 568 |
|
| 569 | + /** |
| 570 | + * Returns different between two times as a time. |
| 571 | + * (TIME, TIME) -> TIME |
| 572 | + * MySQL has these signatures too |
| 573 | + * (DATE, DATE) -> TIME // result is > 24 hours |
| 574 | + * (DATETIME, DATETIME) -> TIME // result is > 24 hours |
| 575 | + * (TIMESTAMP, TIMESTAMP) -> TIME // result is > 24 hours |
| 576 | + * (x, x) -> NULL // when args have different types |
| 577 | + * (STRING, STRING) -> TIME // argument strings contain same types only |
| 578 | + * (STRING, STRING) -> NULL // argument strings are different types |
| 579 | + */ |
| 580 | + private DefaultFunctionResolver timediff() { |
| 581 | + return define(BuiltinFunctionName.TIMEDIFF.getName(), |
| 582 | + impl(nullMissingHandling(DateTimeFunction::exprTimeDiff), TIME, TIME, TIME)); |
| 583 | + } |
| 584 | + |
522 | 585 | /**
|
523 | 586 | * TIME_TO_SEC(STRING/TIME/DATETIME/TIMESTAMP). return the time argument, converted to seconds.
|
524 | 587 | */
|
@@ -691,6 +754,22 @@ private ExprValue exprDate(ExprValue exprValue) {
|
691 | 754 | }
|
692 | 755 | }
|
693 | 756 |
|
| 757 | + /** |
| 758 | + * Calculate the value in days from one date to the other. |
| 759 | + * Only the date parts of the values are used in the calculation. |
| 760 | + * |
| 761 | + * @param first The first value. |
| 762 | + * @param second The second value. |
| 763 | + * @return The diff. |
| 764 | + */ |
| 765 | + private ExprValue exprDateDiff(FunctionProperties functionProperties, |
| 766 | + ExprValue first, ExprValue second) { |
| 767 | + // java inverses the value, so we have to swap 1 and 2 |
| 768 | + return new ExprLongValue(DAYS.between( |
| 769 | + extractDate(second, functionProperties), |
| 770 | + extractDate(first, functionProperties))); |
| 771 | + } |
| 772 | + |
694 | 773 | /**
|
695 | 774 | * DateTime implementation for ExprValue.
|
696 | 775 | *
|
@@ -1039,6 +1118,19 @@ private ExprValue exprTime(ExprValue exprValue) {
|
1039 | 1118 | }
|
1040 | 1119 | }
|
1041 | 1120 |
|
| 1121 | + /** |
| 1122 | + * Calculate the time difference between two times. |
| 1123 | + * |
| 1124 | + * @param first The first value. |
| 1125 | + * @param second The second value. |
| 1126 | + * @return The diff. |
| 1127 | + */ |
| 1128 | + private ExprValue exprTimeDiff(ExprValue first, ExprValue second) { |
| 1129 | + // java inverses the value, so we have to swap 1 and 2 |
| 1130 | + return new ExprTimeValue(LocalTime.MIN.plus( |
| 1131 | + Duration.between(second.timeValue(), first.timeValue()))); |
| 1132 | + } |
| 1133 | + |
1042 | 1134 | /**
|
1043 | 1135 | * Timestamp implementation for ExprValue.
|
1044 | 1136 | *
|
|
0 commit comments