Skip to content

Commit

Permalink
Add TIMEDIFF and DATEDIFF functions. (#131) (#1195)
Browse files Browse the repository at this point in the history
* Add `TIMEDIFF` and `DATEDIFF` functions.

Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
Co-authored-by: Max Ksyunz <maxk@bitquilltech.com>

Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
Co-authored-by: Max Ksyunz <maxk@bitquilltech.com>
(cherry picked from commit 438c44d)
  • Loading branch information
Yury-Fridlyand authored and github-actions[bot] committed Jan 6, 2023
1 parent de79815 commit f0ae82c
Show file tree
Hide file tree
Showing 24 changed files with 599 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
Expand Down Expand Up @@ -69,7 +68,7 @@ public LocalDateTime datetimeValue() {

@Override
public Instant timestampValue() {
return ZonedDateTime.of(date, timeValue(), ZoneId.systemDefault()).toInstant();
return ZonedDateTime.of(date, timeValue(), ExprTimestampValue.ZONE).toInstant();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
Expand Down Expand Up @@ -71,7 +70,7 @@ public LocalTime timeValue() {

@Override
public Instant timestampValue() {
return ZonedDateTime.of(datetime, ZoneId.of("UTC")).toInstant();
return ZonedDateTime.of(datetime, ExprTimestampValue.ZONE).toInstant();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.opensearch.sql.data.type.ExprCoreType;
import org.opensearch.sql.data.type.ExprType;
import org.opensearch.sql.exception.SemanticCheckException;
import org.opensearch.sql.expression.function.FunctionProperties;

/**
* Expression Time Value.
Expand Down Expand Up @@ -57,6 +57,19 @@ public LocalTime timeValue() {
return time;
}

public LocalDate dateValue(FunctionProperties functionProperties) {
return LocalDate.now(functionProperties.getQueryStartClock());
}

public LocalDateTime datetimeValue(FunctionProperties functionProperties) {
return LocalDateTime.of(dateValue(functionProperties), timeValue());
}

public Instant timestampValue(FunctionProperties functionProperties) {
return ZonedDateTime.of(dateValue(functionProperties), timeValue(), ExprTimestampValue.ZONE)
.toInstant();
}

@Override
public String toString() {
return String.format("TIME '%s'", value());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ExprTimestampValue extends AbstractExprValue {
/**
* todo. only support UTC now.
*/
private static final ZoneId ZONE = ZoneId.of("UTC");
public static final ZoneId ZONE = ZoneId.of("UTC");

private final Instant timestamp;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

package org.opensearch.sql.data.model;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAmount;
import java.util.ArrayList;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -61,6 +65,22 @@ public static ExprValue intervalValue(TemporalAmount value) {
return new ExprIntervalValue(value);
}

public static ExprValue dateValue(LocalDate value) {
return new ExprDateValue(value);
}

public static ExprValue datetimeValue(LocalDateTime value) {
return new ExprDatetimeValue(value);
}

public static ExprValue timeValue(LocalTime value) {
return new ExprTimeValue(value);
}

public static ExprValue timestampValue(Instant value) {
return new ExprTimestampValue(value);
}

/**
* {@link ExprTupleValue} constructor.
*/
Expand Down Expand Up @@ -115,6 +135,14 @@ public static ExprValue fromObjectValue(Object o) {
return stringValue((String) o);
} else if (o instanceof Float) {
return floatValue((Float) o);
} else if (o instanceof LocalDate) {
return dateValue((LocalDate) o);
} else if (o instanceof LocalDateTime) {
return datetimeValue((LocalDateTime) o);
} else if (o instanceof LocalTime) {
return timeValue((LocalTime) o);
} else if (o instanceof Instant) {
return timestampValue((Instant) o);
} else {
throw new ExpressionEvaluationException("unsupported object " + o.getClass());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package org.opensearch.sql.expression.datetime;

import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.MONTHS;
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
Expand All @@ -21,17 +22,20 @@
import static org.opensearch.sql.expression.function.FunctionDSL.impl;
import static org.opensearch.sql.expression.function.FunctionDSL.implWithProperties;
import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandling;
import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandlingWithProperties;
import static org.opensearch.sql.utils.DateTimeFormatters.DATE_FORMATTER_LONG_YEAR;
import static org.opensearch.sql.utils.DateTimeFormatters.DATE_FORMATTER_SHORT_YEAR;
import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_LONG_YEAR;
import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_SHORT_YEAR;
import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_STRICT_WITH_TZ;
import static org.opensearch.sql.utils.DateTimeUtils.extractDate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
Expand Down Expand Up @@ -97,6 +101,7 @@ public void register(BuiltinFunctionRepository repository) {
repository.register(current_time());
repository.register(current_timestamp());
repository.register(date());
repository.register(datediff());
repository.register(datetime());
repository.register(date_add());
repository.register(date_sub());
Expand Down Expand Up @@ -128,6 +133,7 @@ public void register(BuiltinFunctionRepository repository) {
repository.register(sysdate());
repository.register(time());
repository.register(time_to_sec());
repository.register(timediff());
repository.register(timestamp());
repository.register(utc_date());
repository.register(utc_time());
Expand Down Expand Up @@ -267,6 +273,46 @@ private DefaultFunctionResolver date() {
impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP));
}

/*
* Calculates the difference of date part of given values.
* (DATE/DATETIME/TIMESTAMP/TIME, DATE/DATETIME/TIMESTAMP/TIME) -> LONG
*/
private DefaultFunctionResolver datediff() {
return define(BuiltinFunctionName.DATEDIFF.getName(),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, DATE, DATE),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, DATETIME, DATE),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, DATE, DATETIME),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, DATETIME, DATETIME),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, DATE, TIME),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, TIME, DATE),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, TIME, TIME),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, TIMESTAMP, DATE),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, DATE, TIMESTAMP),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, TIMESTAMP, TIMESTAMP),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, TIMESTAMP, TIME),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, TIME, TIMESTAMP),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, TIMESTAMP, DATETIME),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, DATETIME, TIMESTAMP),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, TIME, DATETIME),
implWithProperties(nullMissingHandlingWithProperties(DateTimeFunction::exprDateDiff),
LONG, DATETIME, TIME));
}

/**
* Specify a datetime with time zone field and a time zone to convert to.
* Returns a local date time.
Expand Down Expand Up @@ -538,6 +584,22 @@ private DefaultFunctionResolver time() {
impl(nullMissingHandling(DateTimeFunction::exprTime), TIME, TIMESTAMP));
}

/**
* Returns different between two times as a time.
* (TIME, TIME) -> TIME
* MySQL has these signatures too
* (DATE, DATE) -> TIME // result is > 24 hours
* (DATETIME, DATETIME) -> TIME // result is > 24 hours
* (TIMESTAMP, TIMESTAMP) -> TIME // result is > 24 hours
* (x, x) -> NULL // when args have different types
* (STRING, STRING) -> TIME // argument strings contain same types only
* (STRING, STRING) -> NULL // argument strings are different types
*/
private DefaultFunctionResolver timediff() {
return define(BuiltinFunctionName.TIMEDIFF.getName(),
impl(nullMissingHandling(DateTimeFunction::exprTimeDiff), TIME, TIME, TIME));
}

/**
* TIME_TO_SEC(STRING/TIME/DATETIME/TIMESTAMP). return the time argument, converted to seconds.
*/
Expand Down Expand Up @@ -737,6 +799,22 @@ private ExprValue exprDate(ExprValue exprValue) {
}
}

/**
* Calculate the value in days from one date to the other.
* Only the date parts of the values are used in the calculation.
*
* @param first The first value.
* @param second The second value.
* @return The diff.
*/
private ExprValue exprDateDiff(FunctionProperties functionProperties,
ExprValue first, ExprValue second) {
// java inverses the value, so we have to swap 1 and 2
return new ExprLongValue(DAYS.between(
extractDate(second, functionProperties),
extractDate(first, functionProperties)));
}

/**
* DateTime implementation for ExprValue.
*
Expand Down Expand Up @@ -1096,6 +1174,19 @@ private ExprValue exprTime(ExprValue exprValue) {
}
}

/**
* Calculate the time difference between two times.
*
* @param first The first value.
* @param second The second value.
* @return The diff.
*/
private ExprValue exprTimeDiff(ExprValue first, ExprValue second) {
// java inverses the value, so we have to swap 1 and 2
return new ExprTimeValue(LocalTime.MIN.plus(
Duration.between(second.timeValue(), first.timeValue())));
}

/**
* Timestamp implementation for ExprValue.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public enum BuiltinFunctionName {
ADDDATE(FunctionName.of("adddate")),
CONVERT_TZ(FunctionName.of("convert_tz")),
DATE(FunctionName.of("date")),
DATEDIFF(FunctionName.of("datediff")),
DATETIME(FunctionName.of("datetime")),
DATE_ADD(FunctionName.of("date_add")),
DATE_SUB(FunctionName.of("date_sub")),
Expand All @@ -87,6 +88,7 @@ public enum BuiltinFunctionName {
SECOND(FunctionName.of("second")),
SUBDATE(FunctionName.of("subdate")),
TIME(FunctionName.of("time")),
TIMEDIFF(FunctionName.of("timediff")),
TIME_TO_SEC(FunctionName.of("time_to_sec")),
TIMESTAMP(FunctionName.of("timestamp")),
DATE_FORMAT(FunctionName.of("date_format")),
Expand Down
Loading

0 comments on commit f0ae82c

Please sign in to comment.