|
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; |
|
27 | 28 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_LONG_YEAR; |
28 | 29 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_SHORT_YEAR; |
29 | 30 | import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_STRICT_WITH_TZ; |
| 31 | +import static org.opensearch.sql.utils.DateTimeUtils.extractDate; |
30 | 32 | import static org.opensearch.sql.utils.DateTimeUtils.extractDateTime; |
31 | 33 |
|
32 | 34 | import java.math.BigDecimal; |
33 | 35 | import java.math.RoundingMode; |
34 | 36 | import java.text.DecimalFormat; |
35 | 37 | import java.time.Clock; |
36 | 38 | import java.time.DateTimeException; |
| 39 | +import java.time.Duration; |
37 | 40 | import java.time.Instant; |
38 | 41 | import java.time.LocalDate; |
39 | 42 | import java.time.LocalDateTime; |
@@ -107,6 +110,7 @@ public void register(BuiltinFunctionRepository repository) { |
107 | 110 | repository.register(current_time()); |
108 | 111 | repository.register(current_timestamp()); |
109 | 112 | repository.register(date()); |
| 113 | + repository.register(datediff()); |
110 | 114 | repository.register(datetime()); |
111 | 115 | repository.register(date_add()); |
112 | 116 | repository.register(date_sub()); |
@@ -138,6 +142,7 @@ public void register(BuiltinFunctionRepository repository) { |
138 | 142 | repository.register(sysdate()); |
139 | 143 | repository.register(time()); |
140 | 144 | repository.register(time_to_sec()); |
| 145 | + repository.register(timediff()); |
141 | 146 | repository.register(timestamp()); |
142 | 147 | repository.register(utc_date()); |
143 | 148 | repository.register(utc_time()); |
@@ -298,6 +303,46 @@ private DefaultFunctionResolver date() { |
298 | 303 | impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP)); |
299 | 304 | } |
300 | 305 |
|
| 306 | + /* |
| 307 | + * Calculates the difference of date part of given values. |
| 308 | + * (DATE/DATETIME/TIMESTAMP/TIME, DATE/DATETIME/TIMESTAMP/TIME) -> LONG |
| 309 | + */ |
| 310 | + private DefaultFunctionResolver datediff() { |
| 311 | + return define(BuiltinFunctionName.DATEDIFF.getName(), |
| 312 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 313 | + LONG, DATE, DATE), |
| 314 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 315 | + LONG, DATETIME, DATE), |
| 316 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 317 | + LONG, DATE, DATETIME), |
| 318 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 319 | + LONG, DATETIME, DATETIME), |
| 320 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 321 | + LONG, DATE, TIME), |
| 322 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 323 | + LONG, TIME, DATE), |
| 324 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 325 | + LONG, TIME, TIME), |
| 326 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 327 | + LONG, TIMESTAMP, DATE), |
| 328 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 329 | + LONG, DATE, TIMESTAMP), |
| 330 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 331 | + LONG, TIMESTAMP, TIMESTAMP), |
| 332 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 333 | + LONG, TIMESTAMP, TIME), |
| 334 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 335 | + LONG, TIME, TIMESTAMP), |
| 336 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 337 | + LONG, TIMESTAMP, DATETIME), |
| 338 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 339 | + LONG, DATETIME, TIMESTAMP), |
| 340 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 341 | + LONG, TIME, DATETIME), |
| 342 | + implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff), |
| 343 | + LONG, DATETIME, TIME)); |
| 344 | + } |
| 345 | + |
301 | 346 | /** |
302 | 347 | * Specify a datetime with time zone field and a time zone to convert to. |
303 | 348 | * Returns a local date time. |
@@ -557,6 +602,22 @@ private DefaultFunctionResolver time() { |
557 | 602 | impl(nullMissingHandling(DateTimeFunction::exprTime), TIME, TIMESTAMP)); |
558 | 603 | } |
559 | 604 |
|
| 605 | + /** |
| 606 | + * Returns different between two times as a time. |
| 607 | + * (TIME, TIME) -> TIME |
| 608 | + * MySQL has these signatures too |
| 609 | + * (DATE, DATE) -> TIME // result is > 24 hours |
| 610 | + * (DATETIME, DATETIME) -> TIME // result is > 24 hours |
| 611 | + * (TIMESTAMP, TIMESTAMP) -> TIME // result is > 24 hours |
| 612 | + * (x, x) -> NULL // when args have different types |
| 613 | + * (STRING, STRING) -> TIME // argument strings contain same types only |
| 614 | + * (STRING, STRING) -> NULL // argument strings are different types |
| 615 | + */ |
| 616 | + private DefaultFunctionResolver timediff() { |
| 617 | + return define(BuiltinFunctionName.TIMEDIFF.getName(), |
| 618 | + impl(nullMissingHandling(DateTimeFunction::exprTimeDiff), TIME, TIME, TIME)); |
| 619 | + } |
| 620 | + |
560 | 621 | /** |
561 | 622 | * TIME_TO_SEC(STRING/TIME/DATETIME/TIMESTAMP). return the time argument, converted to seconds. |
562 | 623 | */ |
@@ -792,6 +853,22 @@ private ExprValue exprDate(ExprValue exprValue) { |
792 | 853 | } |
793 | 854 | } |
794 | 855 |
|
| 856 | + /** |
| 857 | + * Calculate the value in days from one date to the other. |
| 858 | + * Only the date parts of the values are used in the calculation. |
| 859 | + * |
| 860 | + * @param first The first value. |
| 861 | + * @param second The second value. |
| 862 | + * @return The diff. |
| 863 | + */ |
| 864 | + private ExprValue exprDateDiff(FunctionProperties functionProperties, |
| 865 | + ExprValue first, ExprValue second) { |
| 866 | + // java inverses the value, so we have to swap 1 and 2 |
| 867 | + return new ExprLongValue(DAYS.between( |
| 868 | + extractDate(second, functionProperties), |
| 869 | + extractDate(first, functionProperties))); |
| 870 | + } |
| 871 | + |
795 | 872 | /** |
796 | 873 | * DateTime implementation for ExprValue. |
797 | 874 | * |
@@ -1151,6 +1228,19 @@ private ExprValue exprTime(ExprValue exprValue) { |
1151 | 1228 | } |
1152 | 1229 | } |
1153 | 1230 |
|
| 1231 | + /** |
| 1232 | + * Calculate the time difference between two times. |
| 1233 | + * |
| 1234 | + * @param first The first value. |
| 1235 | + * @param second The second value. |
| 1236 | + * @return The diff. |
| 1237 | + */ |
| 1238 | + private ExprValue exprTimeDiff(ExprValue first, ExprValue second) { |
| 1239 | + // java inverses the value, so we have to swap 1 and 2 |
| 1240 | + return new ExprTimeValue(LocalTime.MIN.plus( |
| 1241 | + Duration.between(second.timeValue(), first.timeValue()))); |
| 1242 | + } |
| 1243 | + |
1154 | 1244 | /** |
1155 | 1245 | * Timestamp implementation for ExprValue. |
1156 | 1246 | * |
|
0 commit comments