Skip to content

Commit 9e67e5b

Browse files
Add Hour_Of_Day Function As An Alias Of Hour (opensearch-project#1226)
* 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]>
1 parent 1108379 commit 9e67e5b

File tree

8 files changed

+142
-12
lines changed

8 files changed

+142
-12
lines changed

core/src/main/java/org/opensearch/sql/expression/DSL.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,10 @@ public static FunctionExpression hour(Expression... expressions) {
361361
return compile(FunctionProperties.None, BuiltinFunctionName.HOUR, expressions);
362362
}
363363

364+
public static FunctionExpression hour_of_day(Expression... expressions) {
365+
return compile(FunctionProperties.None, BuiltinFunctionName.HOUR_OF_DAY, expressions);
366+
}
367+
364368
public static FunctionExpression microsecond(Expression... expressions) {
365369
return compile(FunctionProperties.None, BuiltinFunctionName.MICROSECOND, expressions);
366370
}

core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
package org.opensearch.sql.expression.datetime;
88

9+
910
import static java.time.temporal.ChronoUnit.DAYS;
11+
import static java.time.temporal.ChronoUnit.HOURS;
1012
import static java.time.temporal.ChronoUnit.MINUTES;
1113
import static java.time.temporal.ChronoUnit.MONTHS;
1214
import static java.time.temporal.ChronoUnit.SECONDS;
@@ -120,7 +122,8 @@ public void register(BuiltinFunctionRepository repository) {
120122
repository.register(dayOfYear(BuiltinFunctionName.DAY_OF_YEAR));
121123
repository.register(from_days());
122124
repository.register(from_unixtime());
123-
repository.register(hour());
125+
repository.register(hour(BuiltinFunctionName.HOUR));
126+
repository.register(hour(BuiltinFunctionName.HOUR_OF_DAY));
124127
repository.register(localtime());
125128
repository.register(localtimestamp());
126129
repository.register(makedate());
@@ -504,12 +507,13 @@ private FunctionResolver from_unixtime() {
504507
}
505508

506509
/**
507-
* HOUR(STRING/TIME/DATETIME/TIMESTAMP). return the hour value for time.
510+
* HOUR(STRING/TIME/DATETIME/DATE/TIMESTAMP). return the hour value for time.
508511
*/
509-
private DefaultFunctionResolver hour() {
510-
return define(BuiltinFunctionName.HOUR.getName(),
512+
private DefaultFunctionResolver hour(BuiltinFunctionName name) {
513+
return define(name.getName(),
511514
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, STRING),
512515
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, TIME),
516+
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, DATE),
513517
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, DATETIME),
514518
impl(nullMissingHandling(DateTimeFunction::exprHour), INTEGER, TIMESTAMP)
515519
);
@@ -1139,7 +1143,8 @@ private ExprValue exprFromUnixTimeFormat(ExprValue time, ExprValue format) {
11391143
* @return ExprValue.
11401144
*/
11411145
private ExprValue exprHour(ExprValue time) {
1142-
return new ExprIntegerValue(time.timeValue().getHour());
1146+
return new ExprIntegerValue(
1147+
HOURS.between(LocalTime.MIN, time.timeValue()));
11431148
}
11441149

11451150
/**

core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public enum BuiltinFunctionName {
7777
FROM_DAYS(FunctionName.of("from_days")),
7878
FROM_UNIXTIME(FunctionName.of("from_unixtime")),
7979
HOUR(FunctionName.of("hour")),
80+
HOUR_OF_DAY(FunctionName.of("hour_of_day")),
8081
MAKEDATE(FunctionName.of("makedate")),
8182
MAKETIME(FunctionName.of("maketime")),
8283
MICROSECOND(FunctionName.of("microsecond")),

core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,69 @@ public void invalidMinuteOfDay() {
925925

926926
}
927927

928+
private void hourOfDayQuery(FunctionExpression dateExpression, int hour) {
929+
assertEquals(INTEGER, dateExpression.type());
930+
assertEquals(integerValue(hour), eval(dateExpression));
931+
}
932+
933+
@Test
934+
public void hourOfDay() {
935+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
936+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
937+
938+
FunctionExpression expression1 = DSL.hour_of_day(DSL.literal(new ExprTimeValue("01:02:03")));
939+
FunctionExpression expression2 = DSL.hour_of_day(DSL.literal("01:02:03"));
940+
FunctionExpression expression3 = DSL.hour_of_day(
941+
DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03")));
942+
FunctionExpression expression4 = DSL.hour_of_day(
943+
DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03")));
944+
FunctionExpression expression5 = DSL.hour_of_day(DSL.literal("2020-08-17 01:02:03"));
945+
946+
assertAll(
947+
() -> hourOfDayQuery(expression1, 1),
948+
() -> assertEquals("hour_of_day(TIME '01:02:03')", expression1.toString()),
949+
950+
() -> hourOfDayQuery(expression2, 1),
951+
() -> assertEquals("hour_of_day(\"01:02:03\")", expression2.toString()),
952+
953+
() -> hourOfDayQuery(expression3, 1),
954+
() -> assertEquals("hour_of_day(TIMESTAMP '2020-08-17 01:02:03')", expression3.toString()),
955+
956+
() -> hourOfDayQuery(expression4, 1),
957+
() -> assertEquals("hour_of_day(DATETIME '2020-08-17 01:02:03')", expression4.toString()),
958+
959+
() -> hourOfDayQuery(expression5, 1),
960+
() -> assertEquals("hour_of_day(\"2020-08-17 01:02:03\")", expression5.toString())
961+
);
962+
}
963+
964+
private void invalidHourOfDayQuery(String time) {
965+
FunctionExpression expression = DSL.hour_of_day(DSL.literal(new ExprTimeValue(time)));
966+
eval(expression);
967+
}
968+
969+
@Test
970+
public void hourOfDayInvalidArguments() {
971+
when(nullRef.type()).thenReturn(TIME);
972+
when(missingRef.type()).thenReturn(TIME);
973+
974+
assertAll(
975+
() -> assertEquals(nullValue(), eval(DSL.hour(nullRef))),
976+
() -> assertEquals(missingValue(), eval(DSL.hour(missingRef))),
977+
//Invalid Seconds
978+
() -> assertThrows(SemanticCheckException.class, () -> invalidHourOfDayQuery("12:23:61")),
979+
//Invalid Minutes
980+
() -> assertThrows(SemanticCheckException.class, () -> invalidHourOfDayQuery("12:61:34")),
981+
982+
//Invalid Hours
983+
() -> assertThrows(SemanticCheckException.class, () -> invalidHourOfDayQuery("25:23:34")),
984+
985+
//incorrect format
986+
() -> assertThrows(SemanticCheckException.class, () -> invalidHourOfDayQuery("asdfasdf"))
987+
);
988+
989+
}
990+
928991
@Test
929992
public void microsecond() {
930993
when(nullRef.type()).thenReturn(TIME);

docs/user/dql/functions.rst

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,21 +1763,21 @@ Description
17631763
>>>>>>>>>>>
17641764

17651765
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.
1766+
The function `hour_of_day` is also provided as an alias.
17661767

17671768
Argument type: STRING/TIME/DATETIME/TIMESTAMP
17681769

17691770
Return type: INTEGER
17701771

17711772
Example::
17721773

1773-
os> SELECT HOUR((TIME '01:02:03'))
1774+
os> SELECT HOUR('01:02:03'), HOUR_OF_DAY('01:02:03')
17741775
fetched rows / total rows = 1/1
1775-
+---------------------------+
1776-
| HOUR((TIME '01:02:03')) |
1777-
|---------------------------|
1778-
| 1 |
1779-
+---------------------------+
1780-
1776+
+--------------------+---------------------------+
1777+
| HOUR('01:02:03') | HOUR_OF_DAY('01:02:03') |
1778+
|--------------------+---------------------------|
1779+
| 1 | 1 |
1780+
+--------------------+---------------------------+
17811781

17821782
LOCALTIMESTAMP
17831783
--------------

integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,57 @@ public void testHour() throws IOException {
391391
verifyDataRows(result, rows(17));
392392
}
393393

394+
@Test
395+
public void testHourOfDayWithUnderscores() throws IOException {
396+
JSONObject result = executeQuery("select hour_of_day(timestamp('2020-09-16 17:30:00'))");
397+
verifySchema(result, schema(
398+
"hour_of_day(timestamp('2020-09-16 17:30:00'))", null, "integer"));
399+
verifyDataRows(result, rows(17));
400+
401+
result = executeQuery("select hour_of_day(datetime('2020-09-16 17:30:00'))");
402+
verifySchema(result, schema(
403+
"hour_of_day(datetime('2020-09-16 17:30:00'))", null, "integer"));
404+
verifyDataRows(result, rows(17));
405+
406+
result = executeQuery("select hour_of_day(time('17:30:00'))");
407+
verifySchema(result, schema("hour_of_day(time('17:30:00'))", null, "integer"));
408+
verifyDataRows(result, rows(17));
409+
410+
result = executeQuery("select hour_of_day('2020-09-16 17:30:00')");
411+
verifySchema(result, schema("hour_of_day('2020-09-16 17:30:00')", null, "integer"));
412+
verifyDataRows(result, rows(17));
413+
414+
result = executeQuery("select hour_of_day('17:30:00')");
415+
verifySchema(result, schema("hour_of_day('17:30:00')", null, "integer"));
416+
verifyDataRows(result, rows(17));
417+
}
418+
419+
@Test
420+
public void testHourFunctionAliasesReturnTheSameResults() throws IOException {
421+
JSONObject result1 = executeQuery("SELECT hour('11:30:00')");
422+
JSONObject result2 = executeQuery("SELECT hour_of_day('11:30:00')");
423+
verifyDataRows(result1, rows(11));
424+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
425+
426+
result1 = executeQuery(String.format(
427+
"SELECT hour(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
428+
result2 = executeQuery(String.format(
429+
"SELECT hour_of_day(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
430+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
431+
432+
result1 = executeQuery(String.format(
433+
"SELECT hour(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
434+
result2 = executeQuery(String.format(
435+
"SELECT hour_of_day(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
436+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
437+
438+
result1 = executeQuery(String.format(
439+
"SELECT hour(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
440+
result2 = executeQuery(String.format(
441+
"SELECT hour_of_day(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
442+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
443+
}
444+
394445
@Test
395446
public void testMicrosecond() throws IOException {
396447
JSONObject result = executeQuery("select microsecond(timestamp('2020-09-16 17:30:00.123456'))");

sql/src/main/antlr/OpenSearchSQLParser.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ dateTimeFunctionName
439439
| FROM_DAYS
440440
| FROM_UNIXTIME
441441
| HOUR
442+
| HOUR_OF_DAY
442443
| MAKEDATE
443444
| MAKETIME
444445
| MICROSECOND

sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ public void can_parse_now_like_functions(String name, Boolean hasFsp, Boolean ha
194194
assertNotNull(parser.parse("SELECT id FROM test WHERE " + String.join(" AND ", calls)));
195195
}
196196

197+
@Test
198+
public void can_parse_hour_functions() {
199+
assertNotNull(parser.parse("SELECT hour('2022-11-18 12:23:34')"));
200+
assertNotNull(parser.parse("SELECT hour_of_day('12:23:34')"));
201+
}
197202

198203
@Test
199204
public void can_parse_week_of_year_functions() {

0 commit comments

Comments
 (0)