|
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.MINUTES;
|
10 | 11 | import static java.time.temporal.ChronoUnit.MONTHS;
|
11 | 12 | import static org.opensearch.sql.data.type.ExprCoreType.DATE;
|
|
21 | 22 | import static org.opensearch.sql.expression.function.FunctionDSL.impl;
|
22 | 23 | import static org.opensearch.sql.expression.function.FunctionDSL.implWithProperties;
|
23 | 24 | import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandling;
|
| 25 | +import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandlingWithProperties; |
24 | 26 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_FORMATTER_LONG_YEAR;
|
25 | 27 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_FORMATTER_SHORT_YEAR;
|
26 | 28 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_LONG_YEAR;
|
27 | 29 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_SHORT_YEAR;
|
28 | 30 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_STRICT_WITH_TZ;
|
| 31 | +import static org.opensearch.sql.utils.DateTimeUtils.extractDate; |
29 | 32 |
|
30 | 33 | import java.math.BigDecimal;
|
31 | 34 | import java.math.RoundingMode;
|
32 | 35 | import java.text.DecimalFormat;
|
33 | 36 | import java.time.Clock;
|
34 | 37 | import java.time.DateTimeException;
|
| 38 | +import java.time.Duration; |
35 | 39 | import java.time.Instant;
|
36 | 40 | import java.time.LocalDate;
|
37 | 41 | import java.time.LocalDateTime;
|
@@ -97,6 +101,7 @@ public void register(BuiltinFunctionRepository repository) {
|
97 | 101 | repository.register(current_time());
|
98 | 102 | repository.register(current_timestamp());
|
99 | 103 | repository.register(date());
|
| 104 | + repository.register(datediff()); |
100 | 105 | repository.register(datetime());
|
101 | 106 | repository.register(date_add());
|
102 | 107 | repository.register(date_sub());
|
@@ -128,6 +133,7 @@ public void register(BuiltinFunctionRepository repository) {
|
128 | 133 | repository.register(sysdate());
|
129 | 134 | repository.register(time());
|
130 | 135 | repository.register(time_to_sec());
|
| 136 | + repository.register(timediff()); |
131 | 137 | repository.register(timestamp());
|
132 | 138 | repository.register(utc_date());
|
133 | 139 | repository.register(utc_time());
|
@@ -267,6 +273,46 @@ private DefaultFunctionResolver date() {
|
267 | 273 | impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP));
|
268 | 274 | }
|
269 | 275 |
|
| 276 | + /* |
| 277 | + * Calculates the difference of date part of given values. |
| 278 | + * (DATE/DATETIME/TIMESTAMP/TIME, DATE/DATETIME/TIMESTAMP/TIME) -> LONG |
| 279 | + */ |
| 280 | + private DefaultFunctionResolver datediff() { |
| 281 | + return define(BuiltinFunctionName.DATEDIFF.getName(), |
| 282 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 283 | + LONG, DATE, DATE), |
| 284 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 285 | + LONG, DATETIME, DATE), |
| 286 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 287 | + LONG, DATE, DATETIME), |
| 288 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 289 | + LONG, DATETIME, DATETIME), |
| 290 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 291 | + LONG, DATE, TIME), |
| 292 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 293 | + LONG, TIME, DATE), |
| 294 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 295 | + LONG, TIME, TIME), |
| 296 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 297 | + LONG, TIMESTAMP, DATE), |
| 298 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 299 | + LONG, DATE, TIMESTAMP), |
| 300 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 301 | + LONG, TIMESTAMP, TIMESTAMP), |
| 302 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 303 | + LONG, TIMESTAMP, TIME), |
| 304 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 305 | + LONG, TIME, TIMESTAMP), |
| 306 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 307 | + LONG, TIMESTAMP, DATETIME), |
| 308 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 309 | + LONG, DATETIME, TIMESTAMP), |
| 310 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 311 | + LONG, TIME, DATETIME), |
| 312 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 313 | + LONG, DATETIME, TIME)); |
| 314 | + } |
| 315 | + |
270 | 316 | /**
|
271 | 317 | * Specify a datetime with time zone field and a time zone to convert to.
|
272 | 318 | * Returns a local date time.
|
@@ -538,6 +584,22 @@ private DefaultFunctionResolver time() {
|
538 | 584 | impl(nullMissingHandling(DateTimeFunction::exprTime), TIME, TIMESTAMP));
|
539 | 585 | }
|
540 | 586 |
|
| 587 | + /** |
| 588 | + * Returns different between two times as a time. |
| 589 | + * (TIME, TIME) -> TIME |
| 590 | + * MySQL has these signatures too |
| 591 | + * (DATE, DATE) -> TIME // result is > 24 hours |
| 592 | + * (DATETIME, DATETIME) -> TIME // result is > 24 hours |
| 593 | + * (TIMESTAMP, TIMESTAMP) -> TIME // result is > 24 hours |
| 594 | + * (x, x) -> NULL // when args have different types |
| 595 | + * (STRING, STRING) -> TIME // argument strings contain same types only |
| 596 | + * (STRING, STRING) -> NULL // argument strings are different types |
| 597 | + */ |
| 598 | + private DefaultFunctionResolver timediff() { |
| 599 | + return define(BuiltinFunctionName.TIMEDIFF.getName(), |
| 600 | + impl(nullMissingHandling(DateTimeFunction::exprTimeDiff), TIME, TIME, TIME)); |
| 601 | + } |
| 602 | + |
541 | 603 | /**
|
542 | 604 | * TIME_TO_SEC(STRING/TIME/DATETIME/TIMESTAMP). return the time argument, converted to seconds.
|
543 | 605 | */
|
@@ -737,6 +799,22 @@ private ExprValue exprDate(ExprValue exprValue) {
|
737 | 799 | }
|
738 | 800 | }
|
739 | 801 |
|
| 802 | + /** |
| 803 | + * Calculate the value in days from one date to the other. |
| 804 | + * Only the date parts of the values are used in the calculation. |
| 805 | + * |
| 806 | + * @param first The first value. |
| 807 | + * @param second The second value. |
| 808 | + * @return The diff. |
| 809 | + */ |
| 810 | + private ExprValue exprDateDiff(FunctionProperties functionProperties, |
| 811 | + ExprValue first, ExprValue second) { |
| 812 | + // java inverses the value, so we have to swap 1 and 2 |
| 813 | + return new ExprLongValue(DAYS.between( |
| 814 | + extractDate(second, functionProperties), |
| 815 | + extractDate(first, functionProperties))); |
| 816 | + } |
| 817 | + |
740 | 818 | /**
|
741 | 819 | * DateTime implementation for ExprValue.
|
742 | 820 | *
|
@@ -1096,6 +1174,19 @@ private ExprValue exprTime(ExprValue exprValue) {
|
1096 | 1174 | }
|
1097 | 1175 | }
|
1098 | 1176 |
|
| 1177 | + /** |
| 1178 | + * Calculate the time difference between two times. |
| 1179 | + * |
| 1180 | + * @param first The first value. |
| 1181 | + * @param second The second value. |
| 1182 | + * @return The diff. |
| 1183 | + */ |
| 1184 | + private ExprValue exprTimeDiff(ExprValue first, ExprValue second) { |
| 1185 | + // java inverses the value, so we have to swap 1 and 2 |
| 1186 | + return new ExprTimeValue(LocalTime.MIN.plus( |
| 1187 | + Duration.between(second.timeValue(), first.timeValue()))); |
| 1188 | + } |
| 1189 | + |
1099 | 1190 | /**
|
1100 | 1191 | * Timestamp implementation for ExprValue.
|
1101 | 1192 | *
|
|
0 commit comments