SQL: non ISO 8601 versions of DAY_OF_WEEK and WEEK_OF_YEAR functions (#36358)
* Renamed DAY_OF_WEEK and WEEK_OF_YEAR functions to their ISO version and added the same functions with different functionality. * Rewritten the datetime functions documentation to follow the format of the other functions documentation pages.
This commit is contained in:
parent
51800de2a8
commit
de373060fb
|
@ -5,92 +5,397 @@
|
|||
|
||||
beta[]
|
||||
|
||||
* Extract the year from a date (`YEAR`)
|
||||
[[sql-functions-datetime-day]]
|
||||
==== `DAY_OF_MONTH`/`DOM`/`DAY`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
DAY_OF_MONTH(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the day of the month from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[year]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[dayOfMonth]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the month of the year from a date (`MONTH_OF_YEAR` or `MONTH`)
|
||||
[[sql-functions-datetime-dow]]
|
||||
==== `DAY_OF_WEEK`/`DAYOFWEEK`/`DOW`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
DAY_OF_WEEK(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the day of the week from a date. Sunday is `1`, Monday is `2`, etc.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[monthOfYear]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[dayOfWeek]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the week of the year from a date (`WEEK_OF_YEAR` or `WEEK`)
|
||||
[[sql-functions-datetime-doy]]
|
||||
==== `DAY_OF_YEAR`/`DOY`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
DAY_OF_YEAR(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the day of the year from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[weekOfYear]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[dayOfYear]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the day of the year from a date (`DAY_OF_YEAR` or `DOY`)
|
||||
[[sql-functions-datetime-dayname]]
|
||||
==== `DAY_NAME`/`DAYNAME`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
DAY_NAME(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: string
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the day of the week from a datetime in text format (`Monday`, `Tuesday`...).
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[dayOfYear]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[dayName]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the day of the month from a date (`DAY_OF_MONTH`, `DOM`, or `DAY`)
|
||||
[[sql-functions-datetime-hour]]
|
||||
==== `HOUR_OF_DAY`/`HOUR`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
HOUR_OF_DAY(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the hour of the day from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[dayOfMonth]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[hourOfDay]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the day of the week from a date (`DAY_OF_WEEK` or `DOW`).
|
||||
[[sql-functions-datetime-isodow]]
|
||||
==== `ISO_DAY_OF_WEEK`/`ISODAYOFWEEK`/`ISODOW`/`IDOW`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
ISO_DAY_OF_WEEK(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the day of the week from a date, following the https://en.wikipedia.org/wiki/ISO_week_date[ISO 8601 standard].
|
||||
Monday is `1`, Tuesday is `2`, etc.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[dayOfWeek]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[isoDayOfWeek]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the hour of the day from a date (`HOUR_OF_DAY` or `HOUR`).
|
||||
Monday is `1`, Tuesday is `2`, etc.
|
||||
[[sql-functions-datetime-isoweek]]
|
||||
==== `ISO_WEEK_OF_YEAR`/`ISOWEEKOFYEAR`/`ISOWEEK`/`IWOY`/`IW`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
ISO_WEEK_OF_YEAR(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the week of the year from a date, following https://en.wikipedia.org/wiki/ISO_week_date[ISO 8601 standard]. The first week
|
||||
of a year is the first week with a majority (4 or more) of its days in January.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[hourOfDay]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[isoWeekOfYear]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the minute of the day from a date (`MINUTE_OF_DAY`).
|
||||
[[sql-functions-datetime-minuteofday]]
|
||||
==== `MINUTE_OF_DAY`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
MINUTE_OF_DAY(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the minute of the day from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[minuteOfDay]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[minuteOfDay]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the minute of the hour from a date (`MINUTE_OF_HOUR`, `MINUTE`).
|
||||
[[sql-functions-datetime-minute]]
|
||||
==== `MINUTE_OF_HOUR`/`MINUTE`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
MINUTE_OF_HOUR(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the minute of the hour from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[minuteOfHour]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[minuteOfHour]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract the second of the minute from a date (`SECOND_OF_MINUTE`, `SECOND`).
|
||||
[[sql-functions-datetime-month]]
|
||||
==== `MONTH_OF_YEAR`/`MONTH`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
MONTH(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the month of the year from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[secondOfMinute]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[monthOfYear]
|
||||
--------------------------------------------------
|
||||
|
||||
* Extract
|
||||
[[sql-functions-datetime-monthname]]
|
||||
==== `MONTH_NAME`/`MONTHNAME`
|
||||
|
||||
As an alternative, one can support `EXTRACT` to extract fields from datetimes.
|
||||
You can run any <<sql-functions-datetime,datetime function>>
|
||||
with `EXTRACT(<datetime_function> FROM <expression>)`. So
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
MONTH_NAME(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: string
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the month from a datetime in text format (`January`, `February`...).
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[extractDayOfYear]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[monthName]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-datetime-second]]
|
||||
==== `SECOND_OF_MINUTE`/`SECOND`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
SECOND_OF_MINUTE(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the second of the minute from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/docs.csv-spec[secondOfMinute]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-datetime-quarter]]
|
||||
==== `QUARTER`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
QUARTER(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the year quarter the date falls in.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/docs.csv-spec[quarter]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-datetime-week]]
|
||||
==== `WEEK_OF_YEAR`/`WEEK`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
WEEK_OF_YEAR(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the week of the year from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/docs.csv-spec[weekOfYear]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-datetime-year]]
|
||||
==== `YEAR`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
YEAR(date_exp<1>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract the year from a date.
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/docs.csv-spec[year]
|
||||
--------------------------------------------------
|
||||
|
||||
[[sql-functions-datetime-extract]]
|
||||
==== `EXTRACT`
|
||||
|
||||
.Synopsis:
|
||||
[source, sql]
|
||||
--------------------------------------------------
|
||||
EXTRACT(datetime_function<1> FROM date_exp<2>)
|
||||
--------------------------------------------------
|
||||
|
||||
*Input*:
|
||||
|
||||
<1> datetime function name
|
||||
<2> date expression
|
||||
|
||||
*Output*: integer
|
||||
|
||||
.Description:
|
||||
|
||||
Extract fields from a datetime by specifying the name of a <<sql-functions-datetime,datetime function>>.
|
||||
The following
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/docs.csv-spec[extractDayOfYear]
|
||||
--------------------------------------------------
|
||||
|
||||
is the equivalent to
|
||||
|
||||
["source","sql",subs="attributes,callouts,macros"]
|
||||
--------------------------------------------------
|
||||
include-tagged::{sql-specs}/datetime.csv-spec[dayOfYear]
|
||||
include-tagged::{sql-specs}/docs.csv-spec[dayOfYear]
|
||||
--------------------------------------------------
|
||||
|
|
|
@ -78,6 +78,8 @@ public abstract class ShowTestCase extends CliIntegrationTestCase {
|
|||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_OF_WEEK\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*DAY_OF_YEAR\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*HOUR_OF_DAY\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*ISODAYOFWEEK\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*ISO_DAY_OF_WEEK\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertThat(readLine(), RegexMatcher.matches("\\s*MINUTE_OF_DAY\\s*\\|\\s*SCALAR\\s*"));
|
||||
assertEquals("", readLine());
|
||||
}
|
||||
|
|
|
@ -40,6 +40,15 @@ DOW |SCALAR
|
|||
DOY |SCALAR
|
||||
HOUR |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
IDOW |SCALAR
|
||||
ISODAYOFWEEK |SCALAR
|
||||
ISODOW |SCALAR
|
||||
ISOWEEK |SCALAR
|
||||
ISOWEEKOFYEAR |SCALAR
|
||||
ISO_DAY_OF_WEEK |SCALAR
|
||||
ISO_WEEK_OF_YEAR|SCALAR
|
||||
IW |SCALAR
|
||||
IWOY |SCALAR
|
||||
MINUTE |SCALAR
|
||||
MINUTE_OF_DAY |SCALAR
|
||||
MINUTE_OF_HOUR |SCALAR
|
||||
|
@ -156,6 +165,8 @@ DAY_OF_MONTH |SCALAR
|
|||
DAY_OF_WEEK |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
ISODAYOFWEEK |SCALAR
|
||||
ISO_DAY_OF_WEEK|SCALAR
|
||||
MINUTE_OF_DAY |SCALAR
|
||||
;
|
||||
|
||||
|
|
|
@ -54,10 +54,10 @@ d:i | l:s
|
|||
;
|
||||
|
||||
//
|
||||
// Date (in H2 these start at 0 instead of 1...)
|
||||
// Date
|
||||
//
|
||||
dateTimeDayOfWeek
|
||||
SELECT DAY_OF_WEEK(birth_date) d, last_name l FROM "test_emp" WHERE emp_no < 10010 ORDER BY DAY_OF_WEEK(birth_date);
|
||||
dateTimeIsoDayOfWeek
|
||||
SELECT ISO_DAY_OF_WEEK(birth_date) d, last_name l FROM "test_emp" WHERE emp_no < 10010 ORDER BY ISO_DAY_OF_WEEK(birth_date);
|
||||
|
||||
d:i | l:s
|
||||
1 | Preusig
|
||||
|
@ -86,10 +86,96 @@ d:i | l:s
|
|||
110 | Peac
|
||||
;
|
||||
|
||||
weekOfYear
|
||||
SELECT WEEK(birth_date) week, birth_date FROM test_emp ORDER BY WEEK(birth_date) DESC, birth_date DESC LIMIT 15;
|
||||
|
||||
week:i | birth_date:ts
|
||||
---------------+------------------------
|
||||
52 |1962-12-29T00:00:00.000Z
|
||||
52 |1959-12-25T00:00:00.000Z
|
||||
52 |1952-12-24T00:00:00.000Z
|
||||
51 |1960-12-17T00:00:00.000Z
|
||||
50 |1956-12-13T00:00:00.000Z
|
||||
49 |1959-12-03T00:00:00.000Z
|
||||
49 |1957-12-03T00:00:00.000Z
|
||||
48 |1963-11-26T00:00:00.000Z
|
||||
48 |1962-11-26T00:00:00.000Z
|
||||
47 |1962-11-19T00:00:00.000Z
|
||||
46 |1956-11-14T00:00:00.000Z
|
||||
46 |1952-11-13T00:00:00.000Z
|
||||
45 |1962-11-07T00:00:00.000Z
|
||||
45 |1953-11-07T00:00:00.000Z
|
||||
44 |1961-11-02T00:00:00.000Z
|
||||
;
|
||||
|
||||
weekOfYearWithFilter
|
||||
SELECT WEEK(birth_date) week, birth_date FROM test_emp WHERE WEEK(birth_date) > 50 OR WEEK(birth_date) < 4 ORDER BY WEEK(birth_date) DESC, birth_date DESC;
|
||||
|
||||
week:i | birth_date:ts
|
||||
---------------+------------------------
|
||||
52 |1962-12-29T00:00:00.000Z
|
||||
52 |1959-12-25T00:00:00.000Z
|
||||
52 |1952-12-24T00:00:00.000Z
|
||||
51 |1960-12-17T00:00:00.000Z
|
||||
2 |1965-01-03T00:00:00.000Z
|
||||
2 |1953-01-07T00:00:00.000Z
|
||||
;
|
||||
|
||||
//
|
||||
// Aggregate
|
||||
//
|
||||
|
||||
dateTimeAggByIsoDayOfWeekWithFilter
|
||||
SELECT IDOW(birth_date) day, DAY_NAME(birth_date) name, COUNT(*) c FROM test_emp WHERE IDOW(birth_date) < 6 GROUP BY day, name ORDER BY day desc;
|
||||
|
||||
day:i | name:s | c:l
|
||||
---------------+---------------+---------------
|
||||
5 |Friday |12
|
||||
4 |Thursday |15
|
||||
3 |Wednesday |14
|
||||
2 |Tuesday |18
|
||||
1 |Monday |8
|
||||
;
|
||||
|
||||
dateTimeAggByIsoDayOfWeek
|
||||
SELECT IDOW(birth_date) day, DAY_NAME(birth_date) name, COUNT(*) c FROM test_emp GROUP BY day, name ORDER BY day desc;
|
||||
|
||||
day:i | name:s | c:l
|
||||
---------------+---------------+---------------
|
||||
7 |Sunday |10
|
||||
6 |Saturday |13
|
||||
5 |Friday |12
|
||||
4 |Thursday |15
|
||||
3 |Wednesday |14
|
||||
2 |Tuesday |18
|
||||
1 |Monday |8
|
||||
null |null |10
|
||||
;
|
||||
|
||||
dateTimeAggByIsoWeekOfYear
|
||||
SELECT IW(birth_date) iso_week, WEEK(birth_date) week FROM test_emp WHERE IW(birth_date) < 20 GROUP BY iso_week, week ORDER BY iso_week;
|
||||
|
||||
iso_week:i | week:i
|
||||
---------------+---------------
|
||||
1 |2
|
||||
3 |4
|
||||
4 |4
|
||||
4 |5
|
||||
6 |7
|
||||
7 |7
|
||||
8 |8
|
||||
8 |9
|
||||
9 |9
|
||||
10 |11
|
||||
12 |12
|
||||
14 |14
|
||||
14 |15
|
||||
15 |16
|
||||
16 |16
|
||||
16 |17
|
||||
18 |18
|
||||
;
|
||||
|
||||
dateTimeAggByYear
|
||||
SELECT YEAR(birth_date) AS d, CAST(SUM(emp_no) AS INT) s FROM "test_emp" GROUP BY YEAR(birth_date) ORDER BY YEAR(birth_date) LIMIT 13;
|
||||
|
||||
|
@ -166,112 +252,22 @@ d:i | c:l | s:i
|
|||
null |10 |100445
|
||||
;
|
||||
|
||||
constantYear
|
||||
// tag::year
|
||||
SELECT YEAR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS year;
|
||||
weekOfYearGroupBy
|
||||
SELECT WEEK(birth_date) week, COUNT(*) c FROM test_emp WHERE MOD(WEEK(birth_date), 4) = 0 GROUP BY week ORDER BY WEEK(birth_date);
|
||||
|
||||
year
|
||||
---------------
|
||||
2018
|
||||
// end::year
|
||||
;
|
||||
|
||||
constantMonthOfYear
|
||||
// tag::monthOfYear
|
||||
SELECT MONTH_OF_YEAR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS month;
|
||||
|
||||
month
|
||||
---------------
|
||||
2
|
||||
// end::monthOfYear
|
||||
;
|
||||
|
||||
constantWeekOfYear
|
||||
// tag::weekOfYear
|
||||
SELECT WEEK_OF_YEAR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS week;
|
||||
|
||||
week
|
||||
---------------
|
||||
8
|
||||
// end::weekOfYear
|
||||
;
|
||||
|
||||
constantDayOfYear
|
||||
// tag::dayOfYear
|
||||
SELECT DAY_OF_YEAR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
50
|
||||
// end::dayOfYear
|
||||
;
|
||||
|
||||
extractDayOfYear
|
||||
// tag::extractDayOfYear
|
||||
SELECT EXTRACT(DAY_OF_YEAR FROM CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
50
|
||||
// end::extractDayOfYear
|
||||
;
|
||||
|
||||
constantDayOfMonth
|
||||
// tag::dayOfMonth
|
||||
SELECT DAY_OF_MONTH(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
19
|
||||
// end::dayOfMonth
|
||||
;
|
||||
|
||||
constantDayOfWeek
|
||||
// tag::dayOfWeek
|
||||
SELECT DAY_OF_WEEK(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
1
|
||||
// end::dayOfWeek
|
||||
;
|
||||
|
||||
constantHourOfDay
|
||||
// tag::hourOfDay
|
||||
SELECT HOUR_OF_DAY(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS hour;
|
||||
|
||||
hour
|
||||
---------------
|
||||
10
|
||||
// end::hourOfDay
|
||||
;
|
||||
|
||||
constantMinuteOfDay
|
||||
// tag::minuteOfDay
|
||||
SELECT MINUTE_OF_DAY(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS minute;
|
||||
|
||||
minute
|
||||
---------------
|
||||
623
|
||||
// end::minuteOfDay
|
||||
;
|
||||
|
||||
constantMinuteOfHour
|
||||
// tag::minuteOfHour
|
||||
SELECT MINUTE_OF_HOUR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS minute;
|
||||
|
||||
minute
|
||||
---------------
|
||||
23
|
||||
// end::minuteOfHour
|
||||
;
|
||||
|
||||
constantSecondOfMinute
|
||||
// tag::secondOfMinute
|
||||
SELECT SECOND_OF_MINUTE(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS second;
|
||||
|
||||
second
|
||||
---------------
|
||||
27
|
||||
// end::secondOfMinute
|
||||
week:i | c:l
|
||||
---------------+---------------
|
||||
4 |3
|
||||
8 |2
|
||||
12 |1
|
||||
16 |3
|
||||
20 |1
|
||||
24 |2
|
||||
28 |3
|
||||
32 |1
|
||||
36 |3
|
||||
40 |4
|
||||
44 |2
|
||||
48 |2
|
||||
52 |3
|
||||
;
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
// Time NOT IMPLEMENTED in H2 on TIMESTAMP WITH TIME ZONE - hence why these are moved to CSV
|
||||
//
|
||||
|
||||
// WEEK_OF_YEAR moved to CSV tests, because H2 builds its Calendar with the local Locale, we consider ROOT as the default Locale
|
||||
// This has implications on the results, which could change given specific locales where the rules for determining the start of a year are different.
|
||||
|
||||
//
|
||||
// Date
|
||||
//
|
||||
|
@ -31,6 +34,9 @@ SELECT DAYNAME(CAST('2018-09-03' AS TIMESTAMP)) day FROM "test_emp" limit 1;
|
|||
quarterSelect
|
||||
SELECT QUARTER(hire_date) q, hire_date FROM test_emp ORDER BY hire_date LIMIT 15;
|
||||
|
||||
dayOfWeek
|
||||
SELECT DAY_OF_WEEK(birth_date) day, birth_date FROM test_emp ORDER BY DAY_OF_WEEK(birth_date);
|
||||
|
||||
//
|
||||
// Filter
|
||||
//
|
||||
|
@ -59,6 +65,9 @@ SELECT first_name, last_name FROM "test_emp" WHERE DAYNAME(hire_date) = 'Sunday'
|
|||
quarterWithFilter
|
||||
SELECT QUARTER(hire_date) quarter, hire_date FROM test_emp WHERE QUARTER(hire_date) > 2 ORDER BY hire_date LIMIT 15;
|
||||
|
||||
dayOfWeekWithFilter
|
||||
SELECT DAY_OF_WEEK(birth_date) day, birth_date FROM test_emp WHERE DAY_OF_WEEK(birth_date) IN (6,7) ORDER BY DAY_OF_WEEK(birth_date);
|
||||
|
||||
//
|
||||
// Aggregate
|
||||
//
|
||||
|
@ -102,3 +111,6 @@ SELECT CAST(MAX(salary) AS DOUBLE) max_salary, DAYNAME(hire_date) day_name FROM
|
|||
|
||||
quarterWithGroupByAndOrderBy
|
||||
SELECT QUARTER(hire_date) quarter, COUNT(*) hires FROM test_emp GROUP BY QUARTER(hire_date) ORDER BY QUARTER(hire_date);
|
||||
|
||||
dayOfWeekGroupBy
|
||||
SELECT DAY_OF_WEEK(birth_date) day, COUNT(*) c FROM test_emp WHERE DAY_OF_WEEK(birth_date) < 6 GROUP BY day ORDER BY DAY_OF_WEEK(birth_date);
|
||||
|
|
|
@ -217,6 +217,15 @@ DOW |SCALAR
|
|||
DOY |SCALAR
|
||||
HOUR |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
IDOW |SCALAR
|
||||
ISODAYOFWEEK |SCALAR
|
||||
ISODOW |SCALAR
|
||||
ISOWEEK |SCALAR
|
||||
ISOWEEKOFYEAR |SCALAR
|
||||
ISO_DAY_OF_WEEK |SCALAR
|
||||
ISO_WEEK_OF_YEAR|SCALAR
|
||||
IW |SCALAR
|
||||
IWOY |SCALAR
|
||||
MINUTE |SCALAR
|
||||
MINUTE_OF_DAY |SCALAR
|
||||
MINUTE_OF_HOUR |SCALAR
|
||||
|
@ -345,6 +354,8 @@ DAY_OF_MONTH |SCALAR
|
|||
DAY_OF_WEEK |SCALAR
|
||||
DAY_OF_YEAR |SCALAR
|
||||
HOUR_OF_DAY |SCALAR
|
||||
ISODAYOFWEEK |SCALAR
|
||||
ISO_DAY_OF_WEEK|SCALAR
|
||||
MINUTE_OF_DAY |SCALAR
|
||||
|
||||
// end::showFunctionsWithPattern
|
||||
|
@ -1518,6 +1529,11 @@ SELECT TRUNCATE(-345.153, 1) AS trimmed;
|
|||
// end::mathTruncateWithPositiveParameter
|
||||
;
|
||||
|
||||
///////////////////////////////
|
||||
//
|
||||
// Null handling
|
||||
//
|
||||
///////////////////////////////
|
||||
|
||||
coalesceReturnNonNull
|
||||
// tag::coalesceReturnNonNull
|
||||
|
@ -1686,6 +1702,12 @@ true
|
|||
// end::nullEqualsCompareTwoNulls
|
||||
;
|
||||
|
||||
///////////////////////////////
|
||||
//
|
||||
// System functions
|
||||
//
|
||||
///////////////////////////////
|
||||
|
||||
// ignored because tests run with a docs-not-worthy cluster name
|
||||
// at the time of this test being ignored, the cluster name was x-pack_plugin_sql_qa_single-node_integTestCluster
|
||||
database-Ignore
|
||||
|
@ -1709,3 +1731,172 @@ SELECT USER();
|
|||
elastic
|
||||
// end::user
|
||||
;
|
||||
|
||||
///////////////////////////////
|
||||
//
|
||||
// Date-Time functions
|
||||
//
|
||||
///////////////////////////////
|
||||
|
||||
constantYear
|
||||
// tag::year
|
||||
SELECT YEAR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS year;
|
||||
|
||||
year
|
||||
---------------
|
||||
2018
|
||||
// end::year
|
||||
;
|
||||
|
||||
constantMonthOfYear
|
||||
// tag::monthOfYear
|
||||
SELECT MONTH_OF_YEAR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS month;
|
||||
|
||||
month
|
||||
---------------
|
||||
2
|
||||
// end::monthOfYear
|
||||
;
|
||||
|
||||
constantIsoWeekOfYear
|
||||
// tag::isoWeekOfYear
|
||||
SELECT ISO_WEEK_OF_YEAR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS week;
|
||||
|
||||
week
|
||||
---------------
|
||||
8
|
||||
// end::isoWeekOfYear
|
||||
;
|
||||
|
||||
// Ignored because of https://github.com/elastic/elasticsearch/issues/33796
|
||||
constantDayName-Ignore
|
||||
// tag::dayName
|
||||
SELECT DAY_NAME(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
Monday
|
||||
// end::dayName
|
||||
;
|
||||
|
||||
|
||||
// Ignored because of https://github.com/elastic/elasticsearch/issues/33796
|
||||
constantMonthName-Ignore
|
||||
// tag::monthName
|
||||
SELECT MONTH_NAME(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS month;
|
||||
|
||||
month
|
||||
---------------
|
||||
February
|
||||
// end::monthName
|
||||
;
|
||||
|
||||
constantDayOfYear
|
||||
// tag::dayOfYear
|
||||
SELECT DAY_OF_YEAR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
50
|
||||
// end::dayOfYear
|
||||
;
|
||||
|
||||
extractDayOfYear
|
||||
// tag::extractDayOfYear
|
||||
SELECT EXTRACT(DAY_OF_YEAR FROM CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
50
|
||||
// end::extractDayOfYear
|
||||
;
|
||||
|
||||
constantDayOfMonth
|
||||
// tag::dayOfMonth
|
||||
SELECT DAY_OF_MONTH(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
19
|
||||
// end::dayOfMonth
|
||||
;
|
||||
|
||||
constantDayOfWeek
|
||||
// tag::dayOfWeek
|
||||
SELECT DAY_OF_WEEK(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
2
|
||||
// end::dayOfWeek
|
||||
;
|
||||
|
||||
constantIsoDayOfWeek
|
||||
// tag::isoDayOfWeek
|
||||
SELECT ISO_DAY_OF_WEEK(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS day;
|
||||
|
||||
day
|
||||
---------------
|
||||
1
|
||||
// end::isoDayOfWeek
|
||||
;
|
||||
|
||||
constantHourOfDay
|
||||
// tag::hourOfDay
|
||||
SELECT HOUR_OF_DAY(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS hour;
|
||||
|
||||
hour
|
||||
---------------
|
||||
10
|
||||
// end::hourOfDay
|
||||
;
|
||||
|
||||
constantMinuteOfDay
|
||||
// tag::minuteOfDay
|
||||
SELECT MINUTE_OF_DAY(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS minute;
|
||||
|
||||
minute
|
||||
---------------
|
||||
623
|
||||
// end::minuteOfDay
|
||||
;
|
||||
|
||||
constantMinuteOfHour
|
||||
// tag::minuteOfHour
|
||||
SELECT MINUTE_OF_HOUR(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS minute;
|
||||
|
||||
minute
|
||||
---------------
|
||||
23
|
||||
// end::minuteOfHour
|
||||
;
|
||||
|
||||
constantSecondOfMinute
|
||||
// tag::secondOfMinute
|
||||
SELECT SECOND_OF_MINUTE(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS second;
|
||||
|
||||
second
|
||||
---------------
|
||||
27
|
||||
// end::secondOfMinute
|
||||
;
|
||||
|
||||
constantQuarter
|
||||
// tag::quarter
|
||||
SELECT QUARTER(CAST('2018-02-19T10:23:27Z' AS TIMESTAMP)) AS quarter;
|
||||
|
||||
quarter
|
||||
---------------
|
||||
1
|
||||
// end::quarter
|
||||
;
|
||||
|
||||
constantWeekOfYear
|
||||
// tag::weekOfYear
|
||||
SELECT WEEK(CAST('1988-01-05T09:22:10Z' AS TIMESTAMP)) AS week, ISOWEEK(CAST('1988-01-05T09:22:10Z' AS TIMESTAMP)) AS isoweek;
|
||||
|
||||
week | isoweek
|
||||
---------------+---------------
|
||||
2 |1
|
||||
// end::weekOfYear
|
||||
;
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfMont
|
|||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfWeek;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfYear;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.HourOfDay;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.IsoDayOfWeek;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.IsoWeekOfYear;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MinuteOfDay;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MinuteOfHour;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MonthName;
|
||||
|
@ -151,7 +153,7 @@ public class FunctionRegistry {
|
|||
def(Skewness.class, Skewness::new, "SKEWNESS"),
|
||||
def(Kurtosis.class, Kurtosis::new, "KURTOSIS"));
|
||||
// Scalar functions
|
||||
// conditional
|
||||
// Conditional
|
||||
addToMap(def(Coalesce.class, Coalesce::new, "COALESCE"),
|
||||
def(IfNull.class, IfNull::new, "IFNULL", "ISNULL", "NVL"),
|
||||
def(NullIf.class, NullIf::new, "NULLIF"),
|
||||
|
@ -163,6 +165,8 @@ public class FunctionRegistry {
|
|||
def(DayOfWeek.class, DayOfWeek::new, "DAY_OF_WEEK", "DAYOFWEEK", "DOW"),
|
||||
def(DayOfYear.class, DayOfYear::new, "DAY_OF_YEAR", "DAYOFYEAR", "DOY"),
|
||||
def(HourOfDay.class, HourOfDay::new, "HOUR_OF_DAY", "HOUR"),
|
||||
def(IsoDayOfWeek.class, IsoDayOfWeek::new, "ISO_DAY_OF_WEEK", "ISODAYOFWEEK", "ISODOW", "IDOW"),
|
||||
def(IsoWeekOfYear.class, IsoWeekOfYear::new, "ISO_WEEK_OF_YEAR", "ISOWEEKOFYEAR", "ISOWEEK", "IWOY", "IW"),
|
||||
def(MinuteOfDay.class, MinuteOfDay::new, "MINUTE_OF_DAY"),
|
||||
def(MinuteOfHour.class, MinuteOfHour::new, "MINUTE_OF_HOUR", "MINUTE"),
|
||||
def(MonthName.class, MonthName::new, "MONTH_NAME", "MONTHNAME"),
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
|||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NonIsoDateTimeProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor;
|
||||
|
@ -78,6 +79,7 @@ public final class Processors {
|
|||
// datetime
|
||||
entries.add(new Entry(Processor.class, DateTimeProcessor.NAME, DateTimeProcessor::new));
|
||||
entries.add(new Entry(Processor.class, NamedDateTimeProcessor.NAME, NamedDateTimeProcessor::new));
|
||||
entries.add(new Entry(Processor.class, NonIsoDateTimeProcessor.NAME, NonIsoDateTimeProcessor::new));
|
||||
entries.add(new Entry(Processor.class, QuarterProcessor.NAME, QuarterProcessor::new));
|
||||
// math
|
||||
entries.add(new Entry(Processor.class, MathProcessor.NAME, MathProcessor::new));
|
||||
|
|
|
@ -18,14 +18,14 @@ public class DateTimeProcessor extends BaseDateTimeProcessor {
|
|||
|
||||
public enum DateTimeExtractor {
|
||||
DAY_OF_MONTH(ChronoField.DAY_OF_MONTH),
|
||||
DAY_OF_WEEK(ChronoField.DAY_OF_WEEK),
|
||||
ISO_DAY_OF_WEEK(ChronoField.DAY_OF_WEEK),
|
||||
DAY_OF_YEAR(ChronoField.DAY_OF_YEAR),
|
||||
HOUR_OF_DAY(ChronoField.HOUR_OF_DAY),
|
||||
MINUTE_OF_DAY(ChronoField.MINUTE_OF_DAY),
|
||||
MINUTE_OF_HOUR(ChronoField.MINUTE_OF_HOUR),
|
||||
MONTH_OF_YEAR(ChronoField.MONTH_OF_YEAR),
|
||||
SECOND_OF_MINUTE(ChronoField.SECOND_OF_MINUTE),
|
||||
WEEK_OF_YEAR(ChronoField.ALIGNED_WEEK_OF_YEAR),
|
||||
ISO_WEEK_OF_YEAR(ChronoField.ALIGNED_WEEK_OF_YEAR),
|
||||
YEAR(ChronoField.YEAR);
|
||||
|
||||
private final ChronoField field;
|
||||
|
|
|
@ -6,18 +6,19 @@
|
|||
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NonIsoDateTimeProcessor.NonIsoDateTimeExtractor;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Extract the day of the week from a datetime. 1 is Monday, 2 is Tuesday, etc.
|
||||
* Extract the day of the week from a datetime in non-ISO format. 1 is Sunday, 2 is Monday, etc.
|
||||
*/
|
||||
public class DayOfWeek extends DateTimeFunction {
|
||||
public class DayOfWeek extends NonIsoDateTimeFunction {
|
||||
|
||||
public DayOfWeek(Location location, Expression field, TimeZone timeZone) {
|
||||
super(location, field, timeZone, DateTimeExtractor.DAY_OF_WEEK);
|
||||
super(location, field, timeZone, NonIsoDateTimeExtractor.DAY_OF_WEEK);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,9 +30,4 @@ public class DayOfWeek extends DateTimeFunction {
|
|||
protected DayOfWeek replaceChild(Expression newChild) {
|
||||
return new DayOfWeek(location(), newChild, timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dateTimeFormat() {
|
||||
return "e";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Extract the day of the week (following the ISO standard) from a datetime. 1 is Monday, 2 is Tuesday, etc.
|
||||
*/
|
||||
public class IsoDayOfWeek extends DateTimeFunction {
|
||||
public IsoDayOfWeek(Location location, Expression field, TimeZone timeZone) {
|
||||
super(location, field, timeZone, DateTimeExtractor.ISO_DAY_OF_WEEK);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
|
||||
return IsoDayOfWeek::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IsoDayOfWeek replaceChild(Expression newChild) {
|
||||
return new IsoDayOfWeek(location(), newChild, timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dateTimeFormat() {
|
||||
return "e";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Extract the week of the year from a datetime following the ISO standard.
|
||||
*/
|
||||
public class IsoWeekOfYear extends DateTimeFunction {
|
||||
public IsoWeekOfYear(Location location, Expression field, TimeZone timeZone) {
|
||||
super(location, field, timeZone, DateTimeExtractor.ISO_WEEK_OF_YEAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NodeCtor2<Expression, TimeZone, BaseDateTimeFunction> ctorForInfo() {
|
||||
return IsoWeekOfYear::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IsoWeekOfYear replaceChild(Expression newChild) {
|
||||
return new IsoWeekOfYear(location(), newChild, timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dateTimeFormat() {
|
||||
return "w";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.FieldAttribute;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NonIsoDateTimeProcessor.NonIsoDateTimeExtractor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
|
||||
import org.elasticsearch.xpack.sql.expression.gen.script.ScriptTemplate;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.type.DataType;
|
||||
import org.elasticsearch.xpack.sql.util.StringUtils;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
||||
|
||||
/*
|
||||
* Base class for date/time functions that behave differently in a non-ISO format
|
||||
*/
|
||||
abstract class NonIsoDateTimeFunction extends BaseDateTimeFunction {
|
||||
|
||||
private final NonIsoDateTimeExtractor extractor;
|
||||
|
||||
NonIsoDateTimeFunction(Location location, Expression field, TimeZone timeZone, NonIsoDateTimeExtractor extractor) {
|
||||
super(location, field, timeZone);
|
||||
this.extractor = extractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object doFold(ZonedDateTime dateTime) {
|
||||
return extractor.extract(dateTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptTemplate scriptWithField(FieldAttribute field) {
|
||||
return new ScriptTemplate(
|
||||
formatTemplate(format(Locale.ROOT, "{sql}.%s(doc[{}].value, {})",
|
||||
StringUtils.underscoreToLowerCamelCase(extractor.name()))),
|
||||
paramsBuilder()
|
||||
.variable(field.name())
|
||||
.variable(timeZone().getID()).build(),
|
||||
dataType());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Processor makeProcessor() {
|
||||
return new NonIsoDateTimeProcessor(extractor, timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataType dataType() {
|
||||
return DataType.INTEGER;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
||||
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.TimeZone;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class NonIsoDateTimeProcessor extends BaseDateTimeProcessor {
|
||||
|
||||
public enum NonIsoDateTimeExtractor {
|
||||
DAY_OF_WEEK(zdt -> {
|
||||
// by ISO 8601 standard, Monday is the first day of the week and has the value 1
|
||||
// non-ISO 8601 standard considers Sunday as the first day of the week and value 1
|
||||
int dayOfWeek = zdt.get(ChronoField.DAY_OF_WEEK) + 1;
|
||||
return dayOfWeek == 8 ? 1 : dayOfWeek;
|
||||
}),
|
||||
WEEK_OF_YEAR(zdt -> {
|
||||
// by ISO 8601 standard, the first week of a year is the first week with a majority (4 or more) of its days in January.
|
||||
// Other Locales may have their own standards (see Arabic or Japanese calendars).
|
||||
LocalDateTime ld = zdt.toLocalDateTime();
|
||||
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(zdt.getZone()), Locale.ROOT);
|
||||
cal.clear();
|
||||
cal.set(ld.get(ChronoField.YEAR), ld.get(ChronoField.MONTH_OF_YEAR) - 1, ld.get(ChronoField.DAY_OF_MONTH),
|
||||
ld.get(ChronoField.HOUR_OF_DAY), ld.get(ChronoField.MINUTE_OF_HOUR), ld.get(ChronoField.SECOND_OF_MINUTE));
|
||||
|
||||
return cal.get(Calendar.WEEK_OF_YEAR);
|
||||
});
|
||||
|
||||
private final Function<ZonedDateTime, Integer> apply;
|
||||
|
||||
NonIsoDateTimeExtractor(Function<ZonedDateTime, Integer> apply) {
|
||||
this.apply = apply;
|
||||
}
|
||||
|
||||
public final Integer extract(ZonedDateTime dateTime) {
|
||||
return apply.apply(dateTime);
|
||||
}
|
||||
|
||||
public final Integer extract(ZonedDateTime millis, String tzId) {
|
||||
return apply.apply(millis.withZoneSameInstant(ZoneId.of(tzId)));
|
||||
}
|
||||
}
|
||||
|
||||
public static final String NAME = "nidt";
|
||||
|
||||
private final NonIsoDateTimeExtractor extractor;
|
||||
|
||||
public NonIsoDateTimeProcessor(NonIsoDateTimeExtractor extractor, TimeZone timeZone) {
|
||||
super(timeZone);
|
||||
this.extractor = extractor;
|
||||
}
|
||||
|
||||
public NonIsoDateTimeProcessor(StreamInput in) throws IOException {
|
||||
super(in);
|
||||
extractor = in.readEnum(NonIsoDateTimeExtractor.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeEnum(extractor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWriteableName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
NonIsoDateTimeExtractor extractor() {
|
||||
return extractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object doProcess(ZonedDateTime dateTime) {
|
||||
return extractor.extract(dateTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(extractor, timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || obj.getClass() != getClass()) {
|
||||
return false;
|
||||
}
|
||||
NonIsoDateTimeProcessor other = (NonIsoDateTimeProcessor) obj;
|
||||
return Objects.equals(extractor, other.extractor)
|
||||
&& Objects.equals(timeZone(), other.timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return extractor.toString();
|
||||
}
|
||||
}
|
|
@ -6,18 +6,19 @@
|
|||
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
||||
|
||||
import org.elasticsearch.xpack.sql.expression.Expression;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NonIsoDateTimeProcessor.NonIsoDateTimeExtractor;
|
||||
import org.elasticsearch.xpack.sql.tree.Location;
|
||||
import org.elasticsearch.xpack.sql.tree.NodeInfo.NodeCtor2;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Extract the week of the year from a datetime.
|
||||
* Extract the week of the year from a datetime following the non-ISO standard.
|
||||
*/
|
||||
public class WeekOfYear extends DateTimeFunction {
|
||||
public class WeekOfYear extends NonIsoDateTimeFunction {
|
||||
|
||||
public WeekOfYear(Location location, Expression field, TimeZone timeZone) {
|
||||
super(location, field, timeZone, DateTimeExtractor.WEEK_OF_YEAR);
|
||||
super(location, field, timeZone, NonIsoDateTimeExtractor.WEEK_OF_YEAR);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -29,9 +30,4 @@ public class WeekOfYear extends DateTimeFunction {
|
|||
protected WeekOfYear replaceChild(Expression newChild) {
|
||||
return new WeekOfYear(location(), newChild, timeZone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String dateTimeFormat() {
|
||||
return "w";
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import org.elasticsearch.script.JodaCompatibleZonedDateTime;
|
|||
import org.elasticsearch.xpack.sql.SqlIllegalArgumentException;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeFunction;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NamedDateTimeProcessor.NameExtractor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NonIsoDateTimeProcessor.NonIsoDateTimeExtractor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.QuarterProcessor;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.BinaryMathProcessor.BinaryMathOperation;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.MathProcessor.MathOperation;
|
||||
|
@ -314,6 +315,13 @@ public final class InternalSqlScriptUtils {
|
|||
return NameExtractor.DAY_NAME.extract(asDateTime(dateTime), tzId);
|
||||
}
|
||||
|
||||
public static Integer dayOfWeek(Object dateTime, String tzId) {
|
||||
if (dateTime == null || tzId == null) {
|
||||
return null;
|
||||
}
|
||||
return NonIsoDateTimeExtractor.DAY_OF_WEEK.extract(asDateTime(dateTime), tzId);
|
||||
}
|
||||
|
||||
public static String monthName(Object dateTime, String tzId) {
|
||||
if (dateTime == null || tzId == null) {
|
||||
return null;
|
||||
|
@ -328,6 +336,13 @@ public final class InternalSqlScriptUtils {
|
|||
return QuarterProcessor.quarter(asDateTime(dateTime), tzId);
|
||||
}
|
||||
|
||||
public static Integer weekOfYear(Object dateTime, String tzId) {
|
||||
if (dateTime == null || tzId == null) {
|
||||
return null;
|
||||
}
|
||||
return NonIsoDateTimeExtractor.WEEK_OF_YEAR.extract(asDateTime(dateTime), tzId);
|
||||
}
|
||||
|
||||
public static ZonedDateTime asDateTime(Object dateTime) {
|
||||
if (dateTime instanceof JodaCompatibleZonedDateTime) {
|
||||
return ((JodaCompatibleZonedDateTime) dateTime).getZonedDateTime();
|
||||
|
|
|
@ -98,8 +98,10 @@ class org.elasticsearch.xpack.sql.expression.function.scalar.whitelist.InternalS
|
|||
#
|
||||
Integer dateTimeChrono(Object, String, String)
|
||||
String dayName(Object, String)
|
||||
Integer dayOfWeek(Object, String)
|
||||
String monthName(Object, String)
|
||||
Integer quarter(Object, String)
|
||||
Integer weekOfYear(Object, String)
|
||||
IntervalDayTime intervalDayTime(String, String)
|
||||
IntervalYearMonth intervalYearMonth(String, String)
|
||||
ZonedDateTime asDateTime(Object)
|
||||
|
|
|
@ -163,7 +163,7 @@ public class VerifierErrorMessagesTests extends ESTestCase {
|
|||
}
|
||||
|
||||
public void testMissingExtractSimilarMany() {
|
||||
assertEquals("1:8: Unknown datetime field [DOP], did you mean any of [DOM, DOW, DOY]?",
|
||||
assertEquals("1:8: Unknown datetime field [DOP], did you mean any of [DOM, DOW, DOY, IDOW]?",
|
||||
error("SELECT EXTRACT(DOP FROM date) FROM test"));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
|
||||
|
||||
import org.elasticsearch.common.io.stream.Writeable.Reader;
|
||||
import org.elasticsearch.test.AbstractWireSerializingTestCase;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.NonIsoDateTimeProcessor.NonIsoDateTimeExtractor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeTestUtils.dateTime;
|
||||
|
||||
public class NonIsoDateTimeProcessorTests extends AbstractWireSerializingTestCase<NonIsoDateTimeProcessor> {
|
||||
|
||||
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
|
||||
|
||||
public static NonIsoDateTimeProcessor randomNonISODateTimeProcessor() {
|
||||
return new NonIsoDateTimeProcessor(randomFrom(NonIsoDateTimeExtractor.values()), UTC);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NonIsoDateTimeProcessor createTestInstance() {
|
||||
return randomNonISODateTimeProcessor();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Reader<NonIsoDateTimeProcessor> instanceReader() {
|
||||
return NonIsoDateTimeProcessor::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NonIsoDateTimeProcessor mutateInstance(NonIsoDateTimeProcessor instance) throws IOException {
|
||||
NonIsoDateTimeExtractor replaced = randomValueOtherThan(instance.extractor(), () -> randomFrom(NonIsoDateTimeExtractor.values()));
|
||||
return new NonIsoDateTimeProcessor(replaced, UTC);
|
||||
}
|
||||
|
||||
public void testNonISOWeekOfYearInUTC() {
|
||||
NonIsoDateTimeProcessor proc = new NonIsoDateTimeProcessor(NonIsoDateTimeExtractor.WEEK_OF_YEAR, UTC);
|
||||
assertEquals(2, proc.process(dateTime(568372930000L))); //1988-01-05T09:22:10Z[UTC]
|
||||
assertEquals(6, proc.process(dateTime(981278530000L))); //2001-02-04T09:22:10Z[UTC]
|
||||
assertEquals(7, proc.process(dateTime(224241730000L))); //1977-02-08T09:22:10Z[UTC]
|
||||
|
||||
assertEquals(12, proc.process(dateTime(132744130000L))); //1974-03-17T09:22:10Z[UTC]
|
||||
assertEquals(17, proc.process(dateTime(230376130000L))); //1977-04-20T09:22:10Z[UTC]
|
||||
assertEquals(17, proc.process(dateTime(766833730000L))); //1994-04-20T09:22:10Z[UTC]
|
||||
assertEquals(29, proc.process(dateTime(79780930000L))); //1972-07-12T09:22:10Z[UTC]
|
||||
assertEquals(33, proc.process(dateTime(902913730000L))); //1998-08-12T09:22:10Z[UTC]
|
||||
}
|
||||
|
||||
public void testNonISOWeekOfYearInNonUTCTimeZone() {
|
||||
NonIsoDateTimeProcessor proc = new NonIsoDateTimeProcessor(NonIsoDateTimeExtractor.WEEK_OF_YEAR, TimeZone.getTimeZone("GMT-10:00"));
|
||||
assertEquals(2, proc.process(dateTime(568372930000L)));
|
||||
assertEquals(5, proc.process(dateTime(981278530000L)));
|
||||
assertEquals(7, proc.process(dateTime(224241730000L)));
|
||||
|
||||
assertEquals(11, proc.process(dateTime(132744130000L)));
|
||||
assertEquals(17, proc.process(dateTime(230376130000L)));
|
||||
assertEquals(17, proc.process(dateTime(766833730000L)));
|
||||
assertEquals(29, proc.process(dateTime(79780930000L)));
|
||||
assertEquals(33, proc.process(dateTime(902913730000L)));
|
||||
}
|
||||
|
||||
public void testNonISODayOfWeekInUTC() {
|
||||
NonIsoDateTimeProcessor proc = new NonIsoDateTimeProcessor(NonIsoDateTimeExtractor.DAY_OF_WEEK, UTC);
|
||||
assertEquals(3, proc.process(dateTime(568372930000L))); //1988-01-05T09:22:10Z[UTC]
|
||||
assertEquals(1, proc.process(dateTime(981278530000L))); //2001-02-04T09:22:10Z[UTC]
|
||||
assertEquals(3, proc.process(dateTime(224241730000L))); //1977-02-08T09:22:10Z[UTC]
|
||||
|
||||
assertEquals(1, proc.process(dateTime(132744130000L))); //1974-03-17T09:22:10Z[UTC]
|
||||
assertEquals(4, proc.process(dateTime(230376130000L))); //1977-04-20T09:22:10Z[UTC]
|
||||
assertEquals(4, proc.process(dateTime(766833730000L))); //1994-04-20T09:22:10Z[UTC]
|
||||
assertEquals(7, proc.process(dateTime(333451330000L))); //1980-07-26T09:22:10Z[UTC]
|
||||
assertEquals(6, proc.process(dateTime(874660930000L))); //1997-09-19T09:22:10Z[UTC]
|
||||
}
|
||||
|
||||
public void testNonISODayOfWeekInNonUTCTimeZone() {
|
||||
NonIsoDateTimeProcessor proc = new NonIsoDateTimeProcessor(NonIsoDateTimeExtractor.DAY_OF_WEEK, TimeZone.getTimeZone("GMT-10:00"));
|
||||
assertEquals(2, proc.process(dateTime(568372930000L)));
|
||||
assertEquals(7, proc.process(dateTime(981278530000L)));
|
||||
assertEquals(2, proc.process(dateTime(224241730000L)));
|
||||
|
||||
assertEquals(7, proc.process(dateTime(132744130000L)));
|
||||
assertEquals(3, proc.process(dateTime(230376130000L)));
|
||||
assertEquals(3, proc.process(dateTime(766833730000L)));
|
||||
assertEquals(6, proc.process(dateTime(333451330000L)));
|
||||
assertEquals(5, proc.process(dateTime(874660930000L)));
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayName;
|
|||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfMonth;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DayOfYear;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.MonthOfYear;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.WeekOfYear;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.IsoWeekOfYear;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.Year;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ACos;
|
||||
import org.elasticsearch.xpack.sql.expression.function.scalar.math.ASin;
|
||||
|
@ -333,9 +333,9 @@ public class OptimizerTests extends ESTestCase {
|
|||
assertEquals(1, foldFunction(new MonthOfYear(EMPTY, cast, UTC)));
|
||||
assertEquals(19, foldFunction(new DayOfMonth(EMPTY, cast, UTC)));
|
||||
assertEquals(19, foldFunction(new DayOfYear(EMPTY, cast, UTC)));
|
||||
assertEquals(3, foldFunction(new WeekOfYear(EMPTY, cast, UTC)));
|
||||
assertEquals(3, foldFunction(new IsoWeekOfYear(EMPTY, cast, UTC)));
|
||||
assertNull(foldFunction(
|
||||
new WeekOfYear(EMPTY, new Literal(EMPTY, null, DataType.NULL), UTC)));
|
||||
new IsoWeekOfYear(EMPTY, new Literal(EMPTY, null, DataType.NULL), UTC)));
|
||||
}
|
||||
|
||||
public void testConstantFoldingIn() {
|
||||
|
|
Loading…
Reference in New Issue