Skip to content

Commit

Permalink
Merge pull request #109 from Bit-Quill/dev-Add-convert_tz-function
Browse files Browse the repository at this point in the history
Adding convert_tz and datetime functions to SQL and PPL
  • Loading branch information
MitchellGale authored Sep 19, 2022
2 parents 929ebfe + 45a6d2e commit f19780b
Show file tree
Hide file tree
Showing 18 changed files with 1,768 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class ExprDatetimeValue extends AbstractExprValue {

static {
FORMATTER_VARIABLE_NANOS = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss")
.appendPattern("uuuu-MM-dd HH:mm:ss[xxx]")
.appendFraction(
ChronoField.NANO_OF_SECOND,
MIN_FRACTION_SECONDS,
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,18 @@ public FunctionExpression adddate(Expression... expressions) {
return function(BuiltinFunctionName.ADDDATE, expressions);
}

public FunctionExpression convert_tz(Expression... expressions) {
return function(BuiltinFunctionName.CONVERT_TZ, expressions);
}

public FunctionExpression date(Expression... expressions) {
return function(BuiltinFunctionName.DATE, expressions);
}

public FunctionExpression datetime(Expression... expressions) {
return function(BuiltinFunctionName.DATETIME, expressions);
}

public FunctionExpression date_add(Expression... expressions) {
return function(BuiltinFunctionName.DATE_ADD, expressions);
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ public enum BuiltinFunctionName {
* Date and Time Functions.
*/
ADDDATE(FunctionName.of("adddate")),
CONVERT_TZ(FunctionName.of("convert_tz")),
DATE(FunctionName.of("date")),
DATETIME(FunctionName.of("datetime")),
DATE_ADD(FunctionName.of("date_add")),
DATE_SUB(FunctionName.of("date_sub")),
DAY(FunctionName.of("day")),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/


package org.opensearch.sql.expression.datetime;


import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.opensearch.sql.data.model.ExprValueUtils.nullValue;
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opensearch.sql.data.model.ExprDatetimeValue;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.expression.DSL;
import org.opensearch.sql.expression.Expression;
import org.opensearch.sql.expression.ExpressionTestBase;
import org.opensearch.sql.expression.FunctionExpression;
import org.opensearch.sql.expression.env.Environment;



@ExtendWith(MockitoExtension.class)
class ConvertTZTest extends ExpressionTestBase {

@Mock
Environment<Expression, ExprValue> env;

@Test
public void invalidDate() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2021-04-31 10:00:00")),
DSL.literal("+00:00"),
DSL.literal("+00:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void conversionFromNoOffset() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("+00:00"),
DSL.literal("+10:00"));
assertEquals(DATETIME, expr.type());
assertEquals(new ExprDatetimeValue("2008-05-16 08:00:00"), expr.valueOf(env));
}

@Test
public void conversionToInvalidInput3Over() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("+00:00"),
DSL.literal("+16:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void conversionToInvalidInput3Under() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("+00:00"),
DSL.literal("-16:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void conversionFromPositiveToPositive() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("+15:00"),
DSL.literal("+01:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void invalidInput2Under() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("-15:00"),
DSL.literal("+01:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void invalidInput3Over() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("-12:00"),
DSL.literal("+15:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void conversionToPositiveEdge() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("+00:00"),
DSL.literal("+14:00"));
assertEquals(DATETIME, expr.type());
assertEquals(new ExprDatetimeValue("2008-05-16 12:00:00"), expr.valueOf(env));
}

@Test
public void conversionToNegativeEdge() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("+00:01"),
DSL.literal("-13:59"));
assertEquals(DATETIME, expr.type());
assertEquals(new ExprDatetimeValue("2008-05-15 08:00:00"), expr.valueOf(env));
}

@Test
public void invalidInput2() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("+)()"),
DSL.literal("+12:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void invalidInput3() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2008-05-15 22:00:00")),
DSL.literal("+00:00"),
DSL.literal("test"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void invalidInput1() {
FunctionExpression expr = dsl.convert_tz(
DSL.literal("test"),
DSL.literal("+00:00"),
DSL.literal("+00:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void invalidDateFeb30() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2021-02-30 10:00:00")),
DSL.literal("+00:00"),
DSL.literal("+00:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void invalidDateApril31() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2021-04-31 10:00:00")),
DSL.literal("+00:00"),
DSL.literal("+00:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void invalidMonth13() {
FunctionExpression expr = dsl.convert_tz(dsl.datetime(
DSL.literal("2021-13-03 10:00:00")),
DSL.literal("+00:00"),
DSL.literal("+00:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import static org.opensearch.sql.data.model.ExprValueUtils.stringValue;
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;
import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
import static org.opensearch.sql.data.type.ExprCoreType.INTERVAL;
import static org.opensearch.sql.data.type.ExprCoreType.LONG;
Expand All @@ -25,15 +24,7 @@
import static org.opensearch.sql.data.type.ExprCoreType.TIMESTAMP;

import com.google.common.collect.ImmutableList;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Year;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.IntStream;
import lombok.AllArgsConstructor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -52,10 +43,7 @@
import org.opensearch.sql.expression.Expression;
import org.opensearch.sql.expression.ExpressionTestBase;
import org.opensearch.sql.expression.FunctionExpression;
import org.opensearch.sql.expression.config.ExpressionConfig;
import org.opensearch.sql.expression.env.Environment;
import org.opensearch.sql.expression.function.FunctionName;
import org.opensearch.sql.expression.function.FunctionSignature;

@ExtendWith(MockitoExtension.class)
class DateTimeFunctionTest extends ExpressionTestBase {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/


package org.opensearch.sql.expression.datetime;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.opensearch.sql.data.model.ExprValueUtils.nullValue;
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.opensearch.sql.data.model.ExprDatetimeValue;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.expression.DSL;
import org.opensearch.sql.expression.Expression;
import org.opensearch.sql.expression.ExpressionTestBase;
import org.opensearch.sql.expression.FunctionExpression;
import org.opensearch.sql.expression.env.Environment;



@ExtendWith(MockitoExtension.class)
class DateTimeTest extends ExpressionTestBase {

@Mock
Environment<Expression, ExprValue> env;

@Test
public void noTimeZoneNoField2() {
FunctionExpression expr = dsl.datetime(DSL.literal("2008-05-15 22:00:00"));
assertEquals(DATETIME, expr.type());
assertEquals(new ExprDatetimeValue("2008-05-15 22:00:00"), expr.valueOf(env));
}

@Test
public void positiveTimeZoneNoField2() {
FunctionExpression expr = dsl.datetime(DSL.literal("2008-05-15 22:00:00+01:00"));
assertEquals(DATETIME, expr.type());
assertEquals(new ExprDatetimeValue("2008-05-15 22:00:00"), expr.valueOf(env));
}

@Test
public void positiveField1WrittenField2() {
FunctionExpression expr = dsl.datetime(DSL.literal("2008-05-15 22:00:00+01:00"),
DSL.literal("America/Los_Angeles"));
assertEquals(DATETIME, expr.type());
assertEquals(new ExprDatetimeValue("2008-05-15 14:00:00"), expr.valueOf(env));
}

// When no timezone argument is passed inside the datetime field, it assumes local time.
@Test
public void localDateTimeConversion() {
// needs to work for all time zones because it defaults to local timezone.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String dt = "2008-05-15 22:00:00";
String timeZone = "America/Los_Angeles";
LocalDateTime timeConverted = LocalDateTime.parse(dt, formatter);
ZonedDateTime timeZoneLocal = timeConverted.atZone(ZoneId.of(TimeZone.getDefault().getID()))
.withZoneSameInstant(ZoneId.of(timeZone));
FunctionExpression expr = dsl.datetime(DSL.literal(dt),
DSL.literal(timeZone));
assertEquals(DATETIME, expr.type());
assertEquals(new ExprDatetimeValue(timeZoneLocal.toLocalDateTime()), expr.valueOf(env));
}

@Test
public void negativeField1WrittenField2() {
FunctionExpression expr = dsl.datetime(DSL.literal("2008-05-15 22:00:00-11:00"),
DSL.literal("America/Los_Angeles"));
assertEquals(DATETIME, expr.type());
assertEquals(new ExprDatetimeValue("2008-05-16 02:00:00"), expr.valueOf(env));
}

@Test
public void negativeField1PositiveField2() {
FunctionExpression expr = dsl.datetime(DSL.literal("2008-05-15 22:00:00-12:00"),
DSL.literal("+15:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void twentyFourHourDifference() {
FunctionExpression expr = dsl.datetime(DSL.literal("2008-05-15 22:00:00-14:00"),
DSL.literal("+10:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void negativeToNull() {
FunctionExpression expr = dsl.datetime(DSL.literal("2008-05-15 22:00:00-11:00"),
DSL.literal(nullValue()));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}

@Test
public void invalidDate() {
FunctionExpression expr = dsl.datetime(DSL.literal("2008-04-31 22:00:00-11:00"));
assertEquals(DATETIME, expr.type());
assertEquals(nullValue(), expr.valueOf(env));
}
}
Loading

0 comments on commit f19780b

Please sign in to comment.