|
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