Skip to content

Commit

Permalink
Add Hour_Of_Day Function As An Alias Of Hour (#1226) (#1269)
Browse files Browse the repository at this point in the history
* Add Hour_Of_Day Function As An Alias Of Hour

Added Tests And ImplementationFor Hour_Of_Day Function

Signed-off-by: GabeFernandez310 <[email protected]>

* Fixed Checkstyle

Signed-off-by: GabeFernandez310 <[email protected]>

Signed-off-by: GabeFernandez310 <[email protected]>
Signed-off-by: GabeFernandez310 <[email protected]>
(cherry picked from commit 9e67e5b)

Co-authored-by: GabeFernandez310 <[email protected]>
  • Loading branch information
1 parent b5336a1 commit 3e60ad3
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 12 deletions.
4 changes: 4 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 @@ -361,6 +361,10 @@ public static FunctionExpression hour(Expression... expressions) {
return compile(FunctionProperties.None, BuiltinFunctionName.HOUR, expressions);
}

public static FunctionExpression hour_of_day(Expression... expressions) {
return compile(FunctionProperties.None, BuiltinFunctionName.HOUR_OF_DAY, expressions);
}

public static FunctionExpression microsecond(Expression... expressions) {
return compile(FunctionProperties.None, BuiltinFunctionName.MICROSECOND, expressions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

package org.opensearch.sql.expression.datetime;


import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.SECONDS;
Expand Down Expand Up @@ -120,7 +122,8 @@ public void register(BuiltinFunctionRepository repository) {
repository.register(dayOfYear(BuiltinFunctionName.DAY_OF_YEAR));
repository.register(from_days());
repository.register(from_unixtime());
repository.register(hour());
repository.register(hour(BuiltinFunctionName.HOUR));
repository.register(hour(BuiltinFunctionName.HOUR_OF_DAY));
repository.register(localtime());
repository.register(localtimestamp());
repository.register(makedate());
Expand Down Expand Up @@ -504,12 +507,13 @@ private FunctionResolver from_unixtime() {
}

/**
* HOUR(STRING/TIME/DATETIME/TIMESTAMP). return the hour value for time.
* HOUR(STRING/TIME/DATETIME/DATE/TIMESTAMP). return the hour value for time.
*/
private DefaultFunctionResolver hour() {
return define(BuiltinFunctionName.HOUR.getName(),
private DefaultFunctionResolver hour(BuiltinFunctionName name) {
return define(name.getName(),
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, STRING),
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, TIME),
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, DATE),
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, DATETIME),
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, TIMESTAMP)
);
Expand Down Expand Up @@ -1139,7 +1143,8 @@ private ExprValue exprFromUnixTimeFormat(ExprValue time, ExprValue format) {
* @return ExprValue.
*/
private ExprValue exprHour(ExprValue time) {
return new ExprIntegerValue(time.timeValue().getHour());
return new ExprIntegerValue(
HOURS.between(LocalTime.MIN, time.timeValue()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public enum BuiltinFunctionName {
FROM_DAYS(FunctionName.of("from_days")),
FROM_UNIXTIME(FunctionName.of("from_unixtime")),
HOUR(FunctionName.of("hour")),
HOUR_OF_DAY(FunctionName.of("hour_of_day")),
MAKEDATE(FunctionName.of("makedate")),
MAKETIME(FunctionName.of("maketime")),
MICROSECOND(FunctionName.of("microsecond")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,69 @@ public void invalidMinuteOfDay() {

}

private void hourOfDayQuery(FunctionExpression dateExpression, int hour) {
assertEquals(INTEGER, dateExpression.type());
assertEquals(integerValue(hour), eval(dateExpression));
}

@Test
public void hourOfDay() {
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());

FunctionExpression expression1 = DSL.hour_of_day(DSL.literal(new ExprTimeValue("01:02:03")));
FunctionExpression expression2 = DSL.hour_of_day(DSL.literal("01:02:03"));
FunctionExpression expression3 = DSL.hour_of_day(
DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03")));
FunctionExpression expression4 = DSL.hour_of_day(
DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03")));
FunctionExpression expression5 = DSL.hour_of_day(DSL.literal("2020-08-17 01:02:03"));

assertAll(
() -> hourOfDayQuery(expression1, 1),
() -> assertEquals("hour_of_day(TIME '01:02:03')", expression1.toString()),

() -> hourOfDayQuery(expression2, 1),
() -> assertEquals("hour_of_day(\"01:02:03\")", expression2.toString()),

() -> hourOfDayQuery(expression3, 1),
() -> assertEquals("hour_of_day(TIMESTAMP '2020-08-17 01:02:03')", expression3.toString()),

() -> hourOfDayQuery(expression4, 1),
() -> assertEquals("hour_of_day(DATETIME '2020-08-17 01:02:03')", expression4.toString()),

() -> hourOfDayQuery(expression5, 1),
() -> assertEquals("hour_of_day(\"2020-08-17 01:02:03\")", expression5.toString())
);
}

private void invalidHourOfDayQuery(String time) {
FunctionExpression expression = DSL.hour_of_day(DSL.literal(new ExprTimeValue(time)));
eval(expression);
}

@Test
public void hourOfDayInvalidArguments() {
when(nullRef.type()).thenReturn(TIME);
when(missingRef.type()).thenReturn(TIME);

assertAll(
() -> assertEquals(nullValue(), eval(DSL.hour(nullRef))),
() -> assertEquals(missingValue(), eval(DSL.hour(missingRef))),
//Invalid Seconds
() -> assertThrows(SemanticCheckException.class, () -> invalidHourOfDayQuery("12:23:61")),
//Invalid Minutes
() -> assertThrows(SemanticCheckException.class, () -> invalidHourOfDayQuery("12:61:34")),

//Invalid Hours
() -> assertThrows(SemanticCheckException.class, () -> invalidHourOfDayQuery("25:23:34")),

//incorrect format
() -> assertThrows(SemanticCheckException.class, () -> invalidHourOfDayQuery("asdfasdf"))
);

}

@Test
public void microsecond() {
when(nullRef.type()).thenReturn(TIME);
Expand Down
14 changes: 7 additions & 7 deletions docs/user/dql/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1763,21 +1763,21 @@ Description
>>>>>>>>>>>

Usage: hour(time) extracts the hour value for time. Different from the time of day value, the time value has a large range and can be greater than 23, so the return value of hour(time) can be also greater than 23.
The function `hour_of_day` is also provided as an alias.

Argument type: STRING/TIME/DATETIME/TIMESTAMP

Return type: INTEGER

Example::

os> SELECT HOUR((TIME '01:02:03'))
os> SELECT HOUR('01:02:03'), HOUR_OF_DAY('01:02:03')
fetched rows / total rows = 1/1
+---------------------------+
| HOUR((TIME '01:02:03')) |
|---------------------------|
| 1 |
+---------------------------+

+--------------------+---------------------------+
| HOUR('01:02:03') | HOUR_OF_DAY('01:02:03') |
|--------------------+---------------------------|
| 1 | 1 |
+--------------------+---------------------------+

LOCALTIMESTAMP
--------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,57 @@ public void testHour() throws IOException {
verifyDataRows(result, rows(17));
}

@Test
public void testHourOfDayWithUnderscores() throws IOException {
JSONObject result = executeQuery("select hour_of_day(timestamp('2020-09-16 17:30:00'))");
verifySchema(result, schema(
"hour_of_day(timestamp('2020-09-16 17:30:00'))", null, "integer"));
verifyDataRows(result, rows(17));

result = executeQuery("select hour_of_day(datetime('2020-09-16 17:30:00'))");
verifySchema(result, schema(
"hour_of_day(datetime('2020-09-16 17:30:00'))", null, "integer"));
verifyDataRows(result, rows(17));

result = executeQuery("select hour_of_day(time('17:30:00'))");
verifySchema(result, schema("hour_of_day(time('17:30:00'))", null, "integer"));
verifyDataRows(result, rows(17));

result = executeQuery("select hour_of_day('2020-09-16 17:30:00')");
verifySchema(result, schema("hour_of_day('2020-09-16 17:30:00')", null, "integer"));
verifyDataRows(result, rows(17));

result = executeQuery("select hour_of_day('17:30:00')");
verifySchema(result, schema("hour_of_day('17:30:00')", null, "integer"));
verifyDataRows(result, rows(17));
}

@Test
public void testHourFunctionAliasesReturnTheSameResults() throws IOException {
JSONObject result1 = executeQuery("SELECT hour('11:30:00')");
JSONObject result2 = executeQuery("SELECT hour_of_day('11:30:00')");
verifyDataRows(result1, rows(11));
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));

result1 = executeQuery(String.format(
"SELECT hour(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
result2 = executeQuery(String.format(
"SELECT hour_of_day(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));

result1 = executeQuery(String.format(
"SELECT hour(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
result2 = executeQuery(String.format(
"SELECT hour_of_day(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));

result1 = executeQuery(String.format(
"SELECT hour(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
result2 = executeQuery(String.format(
"SELECT hour_of_day(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
}

@Test
public void testMicrosecond() throws IOException {
JSONObject result = executeQuery("select microsecond(timestamp('2020-09-16 17:30:00.123456'))");
Expand Down
1 change: 1 addition & 0 deletions sql/src/main/antlr/OpenSearchSQLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ dateTimeFunctionName
| FROM_DAYS
| FROM_UNIXTIME
| HOUR
| HOUR_OF_DAY
| MAKEDATE
| MAKETIME
| MICROSECOND
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ public void can_parse_now_like_functions(String name, Boolean hasFsp, Boolean ha
assertNotNull(parser.parse("SELECT id FROM test WHERE " + String.join(" AND ", calls)));
}

@Test
public void can_parse_hour_functions() {
assertNotNull(parser.parse("SELECT hour('2022-11-18 12:23:34')"));
assertNotNull(parser.parse("SELECT hour_of_day('12:23:34')"));
}

@Test
public void can_parse_week_of_year_functions() {
Expand Down

0 comments on commit 3e60ad3

Please sign in to comment.