From 39e7363971db5d4ea3e36913813234b2a0cb1793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B4mulo=20Farias?= Date: Fri, 15 Aug 2025 10:27:26 +0200 Subject: [PATCH 1/6] Add month name --- .../functions/description/month_name.md | 6 + .../functions/examples/month_name.md | 10 ++ .../_snippets/functions/layout/month_name.md | 26 +++ .../functions/parameters/month_name.md | 7 + .../_snippets/functions/types/month_name.md | 9 ++ .../_snippets/lists/date-time-functions.md | 1 + .../date-time-functions.md | 3 + .../esql/images/functions/month_name.svg | 1 + .../definition/functions/month_name.json | 37 +++++ .../esql/kibana/docs/functions/month_name.md | 9 ++ .../src/main/resources/date.csv-spec | 94 +++++++++++ .../scalar/date/MonthNameMillisEvaluator.java | 139 ++++++++++++++++ .../scalar/date/MonthNameNanosEvaluator.java | 139 ++++++++++++++++ .../xpack/esql/action/EsqlCapabilities.java | 5 + .../function/EsqlFunctionRegistry.java | 2 + .../scalar/ScalarFunctionWritables.java | 2 + .../function/scalar/date/MonthName.java | 141 ++++++++++++++++ .../scalar/date/MonthNameErrorTests.java | 41 +++++ .../date/MonthNameSerializationTests.java | 32 ++++ .../function/scalar/date/MonthNameTests.java | 150 ++++++++++++++++++ 20 files changed, 854 insertions(+) create mode 100644 docs/reference/query-languages/esql/_snippets/functions/description/month_name.md create mode 100644 docs/reference/query-languages/esql/_snippets/functions/examples/month_name.md create mode 100644 docs/reference/query-languages/esql/_snippets/functions/layout/month_name.md create mode 100644 docs/reference/query-languages/esql/_snippets/functions/parameters/month_name.md create mode 100644 docs/reference/query-languages/esql/_snippets/functions/types/month_name.md create mode 100644 docs/reference/query-languages/esql/images/functions/month_name.svg create mode 100644 docs/reference/query-languages/esql/kibana/definition/functions/month_name.json create mode 100644 docs/reference/query-languages/esql/kibana/docs/functions/month_name.md create mode 100644 x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameMillisEvaluator.java create mode 100644 x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameNanosEvaluator.java create mode 100644 x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameErrorTests.java create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameSerializationTests.java create mode 100644 x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameTests.java diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/month_name.md b/docs/reference/query-languages/esql/_snippets/functions/description/month_name.md new file mode 100644 index 0000000000000..49619266fd1f8 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/description/month_name.md @@ -0,0 +1,6 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Description** + +Returns the name of the month for provided date based on the configured Locale. + diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/month_name.md b/docs/reference/query-languages/esql/_snippets/functions/examples/month_name.md new file mode 100644 index 0000000000000..2f7b0164387b3 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/examples/month_name.md @@ -0,0 +1,10 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Example** + +```esql +ROW dt = to_datetime("1996-03-21T00:00:00.000Z") +| EVAL weekday = MONTH_NAME(dt); +``` + + diff --git a/docs/reference/query-languages/esql/_snippets/functions/layout/month_name.md b/docs/reference/query-languages/esql/_snippets/functions/layout/month_name.md new file mode 100644 index 0000000000000..bdd7b834e0ee3 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/layout/month_name.md @@ -0,0 +1,26 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +## `MONTH_NAME` [esql-month_name] +```{applies_to} +stack: ga 9.2.0 +``` + +**Syntax** + +:::{image} ../../../images/functions/month_name.svg +:alt: Embedded +:class: text-center +::: + + +:::{include} ../parameters/month_name.md +::: + +:::{include} ../description/month_name.md +::: + +:::{include} ../types/month_name.md +::: + +:::{include} ../examples/month_name.md +::: diff --git a/docs/reference/query-languages/esql/_snippets/functions/parameters/month_name.md b/docs/reference/query-languages/esql/_snippets/functions/parameters/month_name.md new file mode 100644 index 0000000000000..43182ad4b2d26 --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/parameters/month_name.md @@ -0,0 +1,7 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Parameters** + +`date` +: Date expression. If `null`, the function returns `null`. + diff --git a/docs/reference/query-languages/esql/_snippets/functions/types/month_name.md b/docs/reference/query-languages/esql/_snippets/functions/types/month_name.md new file mode 100644 index 0000000000000..097955acd2cfa --- /dev/null +++ b/docs/reference/query-languages/esql/_snippets/functions/types/month_name.md @@ -0,0 +1,9 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +**Supported types** + +| date | result | +| --- | --- | +| date | keyword | +| date_nanos | keyword | + diff --git a/docs/reference/query-languages/esql/_snippets/lists/date-time-functions.md b/docs/reference/query-languages/esql/_snippets/lists/date-time-functions.md index b59db4d50bf58..2000eab6bb33d 100644 --- a/docs/reference/query-languages/esql/_snippets/lists/date-time-functions.md +++ b/docs/reference/query-languages/esql/_snippets/lists/date-time-functions.md @@ -4,4 +4,5 @@ * [`DATE_PARSE`](../../functions-operators/date-time-functions.md#esql-date_parse) * [`DATE_TRUNC`](../../functions-operators/date-time-functions.md#esql-date_trunc) * [`DAY_NAME`](../../functions-operators/date-time-functions.md#esql-day_name) +* [`MONTH_NAME`](../../functions-operators/date-time-functions.md#esql-month-name) * [`NOW`](../../functions-operators/date-time-functions.md#esql-now) diff --git a/docs/reference/query-languages/esql/functions-operators/date-time-functions.md b/docs/reference/query-languages/esql/functions-operators/date-time-functions.md index 4823468b0bb97..284b475909c35 100644 --- a/docs/reference/query-languages/esql/functions-operators/date-time-functions.md +++ b/docs/reference/query-languages/esql/functions-operators/date-time-functions.md @@ -31,6 +31,9 @@ mapped_pages: :::{include} ../_snippets/functions/layout/day_name.md ::: +:::{include} ../_snippets/functions/layout/month_name.md +::: + :::{include} ../_snippets/functions/layout/now.md ::: diff --git a/docs/reference/query-languages/esql/images/functions/month_name.svg b/docs/reference/query-languages/esql/images/functions/month_name.svg new file mode 100644 index 0000000000000..7b603e15902cb --- /dev/null +++ b/docs/reference/query-languages/esql/images/functions/month_name.svg @@ -0,0 +1 @@ +MONTH_NAME(date) \ No newline at end of file diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json b/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json new file mode 100644 index 0000000000000..0935a9fb59453 --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json @@ -0,0 +1,37 @@ +{ + "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.", + "type" : "scalar", + "name" : "month_name", + "description" : "Returns the name of the month for provided date based on the configured Locale.", + "signatures" : [ + { + "params" : [ + { + "name" : "date", + "type" : "date", + "optional" : false, + "description" : "Date expression. If `null`, the function returns `null`." + } + ], + "variadic" : false, + "returnType" : "keyword" + }, + { + "params" : [ + { + "name" : "date", + "type" : "date_nanos", + "optional" : false, + "description" : "Date expression. If `null`, the function returns `null`." + } + ], + "variadic" : false, + "returnType" : "keyword" + } + ], + "examples" : [ + "ROW dt = to_datetime(\"1996-03-21T00:00:00.000Z\")\n| EVAL weekday = MONTH_NAME(dt);" + ], + "preview" : false, + "snapshot_only" : false +} diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md b/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md new file mode 100644 index 0000000000000..09575aae7e483 --- /dev/null +++ b/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md @@ -0,0 +1,9 @@ +% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. + +### MONTH NAME +Returns the name of the month for provided date based on the configured Locale. + +```esql +ROW dt = to_datetime("1996-03-21T00:00:00.000Z") +| EVAL weekday = MONTH_NAME(dt); +``` diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec index 2b97b2985e7b9..d4bc7b61fe20a 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec @@ -1930,3 +1930,97 @@ from employees | where emp_no == 10040 | eval x = day_name(birth_date) | keep em emp_no:integer | birth_date:date | hire_date:date | x:keyword 10040 | null | 1993-02-14T00:00:00.000Z | null ; + +monthNameRowTest +required_capability:fn_month_name +// tag::docsMonthName[] +ROW dt = to_datetime("1996-03-21T00:00:00.000Z") +| EVAL weekday = MONTH_NAME(dt); +// end::docsMonthName[] + +dt:date | weekday:keyword +1996-03-21T00:00:00.000Z | March +; + +monthNameSimple +required_capability:fn_month_name +from employees +| sort emp_no +| keep emp_no, hire_date +| eval day = month_name(hire_date) +| limit 1; + +emp_no:integer | hire_date:date | day:keyword +10001 | 1986-06-26T00:00:00.000Z | June +; + +monthNameTruncate +required_capability:fn_month_name +FROM employees +| EVAL a = hire_date +| RENAME hire_date as b +| WHERE a > "1987-01-01" and a < "1988-01-01" +| EVAL y = date_trunc(1 month, b) +| STATS c = count(emp_no) by y +| EVAL week_day = month_name(y) +| SORT y +| KEEP y, c, week_day +| LIMIT 5; + +y:date | c:long | week_day:keyword +1987-03-01T00:00:00.000Z | 5 | March +1987-04-01T00:00:00.000Z | 3 | April +1987-05-01T00:00:00.000Z | 1 | May +1987-07-01T00:00:00.000Z | 1 | July +1987-08-01T00:00:00.000Z | 2 | August +; + +monthNameNestedCall +required_capability:fn_month_name +from employees +| sort emp_no +| eval first_day_of_month = month_name(date_trunc(1 month, hire_date)) +| keep emp_no, hire_date, first_day_of_month +| limit 10; + +emp_no:integer | hire_date:datetime | first_day_of_month:keyword +10001 | 1986-06-26T00:00:00.000Z | June +10002 | 1985-11-21T00:00:00.000Z | November +10003 | 1986-08-28T00:00:00.000Z | August +10004 | 1986-12-01T00:00:00.000Z | December +10005 | 1989-09-12T00:00:00.000Z | September +10006 | 1989-06-02T00:00:00.000Z | June +10007 | 1989-02-10T00:00:00.000Z | February +10008 | 1994-09-15T00:00:00.000Z | September +10009 | 1985-02-18T00:00:00.000Z | February +10010 | 1989-08-24T00:00:00.000Z | August +; + +monthNameNestedCall +required_capability:fn_month_name +from employees +| sort emp_no desc +| eval first_day_of_month = to_upper(month_name(date_trunc(1 month, hire_date))) +| keep emp_no, hire_date, first_day_of_month +| limit 10; + +emp_no:integer | hire_date:datetime | first_day_of_month:keyword +10100 | 1987-09-21T00:00:00.000Z | SEPTEMBER +10099 | 1988-10-18T00:00:00.000Z | OCTOBER +10098 | 1985-05-13T00:00:00.000Z | MAY +10097 | 1990-09-15T00:00:00.000Z | SEPTEMBER +10096 | 1990-01-14T00:00:00.000Z | JANUARY +10095 | 1986-07-15T00:00:00.000Z | JULY +10094 | 1987-04-18T00:00:00.000Z | APRIL +10093 | 1996-11-05T00:00:00.000Z | NOVEMBER +10092 | 1989-09-22T00:00:00.000Z | SEPTEMBER +10091 | 1992-11-18T00:00:00.000Z | NOVEMBER +; + +monthNameNull +required_capability:fn_month_name +from employees | where emp_no == 10040 | eval x = day_name(birth_date) | keep emp_no, birth_date, hire_date, x; + +emp_no:integer | birth_date:date | hire_date:date | x:keyword +10040 | null | 1993-02-14T00:00:00.000Z | null +; diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameMillisEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameMillisEvaluator.java new file mode 100644 index 0000000000000..e5c5eac0c1b13 --- /dev/null +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameMillisEvaluator.java @@ -0,0 +1,139 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License +// 2.0; you may not use this file except in compliance with the Elastic License +// 2.0. +package org.elasticsearch.xpack.esql.expression.function.scalar.date; + +import java.lang.IllegalArgumentException; +import java.lang.Override; +import java.lang.String; +import java.time.ZoneId; +import java.util.Locale; +import org.elasticsearch.compute.data.Block; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.BytesRefVector; +import org.elasticsearch.compute.data.LongBlock; +import org.elasticsearch.compute.data.LongVector; +import org.elasticsearch.compute.data.Page; +import org.elasticsearch.compute.operator.DriverContext; +import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.compute.operator.Warnings; +import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MonthName}. + * This class is generated. Edit {@code EvaluatorImplementer} instead. + */ +public final class MonthNameMillisEvaluator implements EvalOperator.ExpressionEvaluator { + private final Source source; + + private final EvalOperator.ExpressionEvaluator val; + + private final ZoneId zoneId; + + private final Locale locale; + + private final DriverContext driverContext; + + private Warnings warnings; + + public MonthNameMillisEvaluator(Source source, EvalOperator.ExpressionEvaluator val, + ZoneId zoneId, Locale locale, DriverContext driverContext) { + this.source = source; + this.val = val; + this.zoneId = zoneId; + this.locale = locale; + this.driverContext = driverContext; + } + + @Override + public Block eval(Page page) { + try (LongBlock valBlock = (LongBlock) val.eval(page)) { + LongVector valVector = valBlock.asVector(); + if (valVector == null) { + return eval(page.getPositionCount(), valBlock); + } + return eval(page.getPositionCount(), valVector).asBlock(); + } + } + + public BytesRefBlock eval(int positionCount, LongBlock valBlock) { + try(BytesRefBlock.Builder result = driverContext.blockFactory().newBytesRefBlockBuilder(positionCount)) { + position: for (int p = 0; p < positionCount; p++) { + if (valBlock.isNull(p)) { + result.appendNull(); + continue position; + } + if (valBlock.getValueCount(p) != 1) { + if (valBlock.getValueCount(p) > 1) { + warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value")); + } + result.appendNull(); + continue position; + } + result.appendBytesRef(MonthName.processMillis(valBlock.getLong(valBlock.getFirstValueIndex(p)), this.zoneId, this.locale)); + } + return result.build(); + } + } + + public BytesRefVector eval(int positionCount, LongVector valVector) { + try(BytesRefVector.Builder result = driverContext.blockFactory().newBytesRefVectorBuilder(positionCount)) { + position: for (int p = 0; p < positionCount; p++) { + result.appendBytesRef(MonthName.processMillis(valVector.getLong(p), this.zoneId, this.locale)); + } + return result.build(); + } + } + + @Override + public String toString() { + return "MonthNameMillisEvaluator[" + "val=" + val + ", zoneId=" + zoneId + ", locale=" + locale + "]"; + } + + @Override + public void close() { + Releasables.closeExpectNoException(val); + } + + private Warnings warnings() { + if (warnings == null) { + this.warnings = Warnings.createWarnings( + driverContext.warningsMode(), + source.source().getLineNumber(), + source.source().getColumnNumber(), + source.text() + ); + } + return warnings; + } + + static class Factory implements EvalOperator.ExpressionEvaluator.Factory { + private final Source source; + + private final EvalOperator.ExpressionEvaluator.Factory val; + + private final ZoneId zoneId; + + private final Locale locale; + + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory val, ZoneId zoneId, + Locale locale) { + this.source = source; + this.val = val; + this.zoneId = zoneId; + this.locale = locale; + } + + @Override + public MonthNameMillisEvaluator get(DriverContext context) { + return new MonthNameMillisEvaluator(source, val.get(context), zoneId, locale, context); + } + + @Override + public String toString() { + return "MonthNameMillisEvaluator[" + "val=" + val + ", zoneId=" + zoneId + ", locale=" + locale + "]"; + } + } +} diff --git a/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameNanosEvaluator.java b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameNanosEvaluator.java new file mode 100644 index 0000000000000..e8f44271fe4c0 --- /dev/null +++ b/x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameNanosEvaluator.java @@ -0,0 +1,139 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License +// 2.0; you may not use this file except in compliance with the Elastic License +// 2.0. +package org.elasticsearch.xpack.esql.expression.function.scalar.date; + +import java.lang.IllegalArgumentException; +import java.lang.Override; +import java.lang.String; +import java.time.ZoneId; +import java.util.Locale; +import org.elasticsearch.compute.data.Block; +import org.elasticsearch.compute.data.BytesRefBlock; +import org.elasticsearch.compute.data.BytesRefVector; +import org.elasticsearch.compute.data.LongBlock; +import org.elasticsearch.compute.data.LongVector; +import org.elasticsearch.compute.data.Page; +import org.elasticsearch.compute.operator.DriverContext; +import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.compute.operator.Warnings; +import org.elasticsearch.core.Releasables; +import org.elasticsearch.xpack.esql.core.tree.Source; + +/** + * {@link EvalOperator.ExpressionEvaluator} implementation for {@link MonthName}. + * This class is generated. Edit {@code EvaluatorImplementer} instead. + */ +public final class MonthNameNanosEvaluator implements EvalOperator.ExpressionEvaluator { + private final Source source; + + private final EvalOperator.ExpressionEvaluator val; + + private final ZoneId zoneId; + + private final Locale locale; + + private final DriverContext driverContext; + + private Warnings warnings; + + public MonthNameNanosEvaluator(Source source, EvalOperator.ExpressionEvaluator val, ZoneId zoneId, + Locale locale, DriverContext driverContext) { + this.source = source; + this.val = val; + this.zoneId = zoneId; + this.locale = locale; + this.driverContext = driverContext; + } + + @Override + public Block eval(Page page) { + try (LongBlock valBlock = (LongBlock) val.eval(page)) { + LongVector valVector = valBlock.asVector(); + if (valVector == null) { + return eval(page.getPositionCount(), valBlock); + } + return eval(page.getPositionCount(), valVector).asBlock(); + } + } + + public BytesRefBlock eval(int positionCount, LongBlock valBlock) { + try(BytesRefBlock.Builder result = driverContext.blockFactory().newBytesRefBlockBuilder(positionCount)) { + position: for (int p = 0; p < positionCount; p++) { + if (valBlock.isNull(p)) { + result.appendNull(); + continue position; + } + if (valBlock.getValueCount(p) != 1) { + if (valBlock.getValueCount(p) > 1) { + warnings().registerException(new IllegalArgumentException("single-value function encountered multi-value")); + } + result.appendNull(); + continue position; + } + result.appendBytesRef(MonthName.processNanos(valBlock.getLong(valBlock.getFirstValueIndex(p)), this.zoneId, this.locale)); + } + return result.build(); + } + } + + public BytesRefVector eval(int positionCount, LongVector valVector) { + try(BytesRefVector.Builder result = driverContext.blockFactory().newBytesRefVectorBuilder(positionCount)) { + position: for (int p = 0; p < positionCount; p++) { + result.appendBytesRef(MonthName.processNanos(valVector.getLong(p), this.zoneId, this.locale)); + } + return result.build(); + } + } + + @Override + public String toString() { + return "MonthNameNanosEvaluator[" + "val=" + val + ", zoneId=" + zoneId + ", locale=" + locale + "]"; + } + + @Override + public void close() { + Releasables.closeExpectNoException(val); + } + + private Warnings warnings() { + if (warnings == null) { + this.warnings = Warnings.createWarnings( + driverContext.warningsMode(), + source.source().getLineNumber(), + source.source().getColumnNumber(), + source.text() + ); + } + return warnings; + } + + static class Factory implements EvalOperator.ExpressionEvaluator.Factory { + private final Source source; + + private final EvalOperator.ExpressionEvaluator.Factory val; + + private final ZoneId zoneId; + + private final Locale locale; + + public Factory(Source source, EvalOperator.ExpressionEvaluator.Factory val, ZoneId zoneId, + Locale locale) { + this.source = source; + this.val = val; + this.zoneId = zoneId; + this.locale = locale; + } + + @Override + public MonthNameNanosEvaluator get(DriverContext context) { + return new MonthNameNanosEvaluator(source, val.get(context), zoneId, locale, context); + } + + @Override + public String toString() { + return "MonthNameNanosEvaluator[" + "val=" + val + ", zoneId=" + zoneId + ", locale=" + locale + "]"; + } + } +} diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java index a397a84343e43..6d88b479b59f4 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java @@ -240,6 +240,11 @@ public enum Cap { */ FN_DAY_NAME, + /** + * Support for function MONTH_NAME + */ + FN_MONTH_NAME, + /** * Fixes for multiple functions not serializing their source, and emitting warnings with wrong line number and text. */ diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java index f52c51cf8d3f9..0202661acf76d 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/EsqlFunctionRegistry.java @@ -88,6 +88,7 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateParse; import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc; import org.elasticsearch.xpack.esql.expression.function.scalar.date.DayName; +import org.elasticsearch.xpack.esql.expression.function.scalar.date.MonthName; import org.elasticsearch.xpack.esql.expression.function.scalar.date.Now; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.IpPrefix; @@ -395,6 +396,7 @@ private static FunctionDefinition[][] functions() { def(DateParse.class, DateParse::new, "date_parse"), def(DateTrunc.class, DateTrunc::new, "date_trunc"), def(DayName.class, DayName::new, "day_name"), + def(MonthName.class, MonthName::new, "month_name"), def(Now.class, Now::new, "now") }, // spatial new FunctionDefinition[] { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ScalarFunctionWritables.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ScalarFunctionWritables.java index 684e685e2eafb..4e0d28fd7d6a6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ScalarFunctionWritables.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/ScalarFunctionWritables.java @@ -19,6 +19,7 @@ import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateParse; import org.elasticsearch.xpack.esql.expression.function.scalar.date.DateTrunc; import org.elasticsearch.xpack.esql.expression.function.scalar.date.DayName; +import org.elasticsearch.xpack.esql.expression.function.scalar.date.MonthName; import org.elasticsearch.xpack.esql.expression.function.scalar.date.Now; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.CIDRMatch; import org.elasticsearch.xpack.esql.expression.function.scalar.ip.IpPrefix; @@ -84,6 +85,7 @@ public static List getNamedWriteables() { entries.add(DateParse.ENTRY); entries.add(DateTrunc.ENTRY); entries.add(DayName.ENTRY); + entries.add(MonthName.ENTRY); entries.add(IpPrefix.ENTRY); entries.add(Least.ENTRY); entries.add(Left.ENTRY); diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java new file mode 100644 index 0000000000000..3530cfb3b2b9a --- /dev/null +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.scalar.date; + +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.io.stream.NamedWriteableRegistry; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.compute.ann.Evaluator; +import org.elasticsearch.compute.ann.Fixed; +import org.elasticsearch.compute.operator.EvalOperator; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.TypeResolutions; +import org.elasticsearch.xpack.esql.core.tree.NodeInfo; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.Example; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo; +import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle; +import org.elasticsearch.xpack.esql.expression.function.FunctionInfo; +import org.elasticsearch.xpack.esql.expression.function.Param; +import org.elasticsearch.xpack.esql.expression.function.scalar.EsqlConfigurationFunction; +import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput; +import org.elasticsearch.xpack.esql.session.Configuration; + +import java.io.IOException; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.TextStyle; +import java.util.List; +import java.util.Locale; + +import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; + +public class MonthName extends EsqlConfigurationFunction { + public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "MonthName", MonthName::new); + + private final Expression field; + + @FunctionInfo( + returnType = "keyword", + description = "Returns the name of the month for provided date based on the configured Locale.", + examples = @Example(file = "date", tag = "docsMonthName"), + appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.GA, version = "9.2.0") } + ) + public MonthName( + Source source, + @Param( + name = "date", + type = { "date", "date_nanos" }, + description = "Date expression. If `null`, the function returns `null`." + ) Expression date, + Configuration configuration + ) { + super(source, List.of(date), configuration); + this.field = date; + } + + private MonthName(StreamInput in) throws IOException { + this(Source.readFrom((PlanStreamInput) in), in.readNamedWriteable(Expression.class), ((PlanStreamInput) in).configuration()); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + source().writeTo(out); + out.writeNamedWriteable(field); + } + + @Override + public String getWriteableName() { + return ENTRY.name; + } + + Expression field() { + return field; + } + + @Override + public DataType dataType() { + return DataType.KEYWORD; + } + + @Override + protected TypeResolution resolveType() { + if (childrenResolved() == false) { + return new TypeResolution("Unresolved children"); + } + + String operationName = sourceText(); + TypeResolution resolution = TypeResolutions.isType(field, DataType::isDate, operationName, FIRST, "datetime or date_nanos"); + if (resolution.unresolved()) { + return resolution; + } + + return TypeResolution.TYPE_RESOLVED; + } + + @Override + public boolean foldable() { + return field.foldable(); + } + + @Override + public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) { + var fieldEvaluator = toEvaluator.apply(field); + if (field().dataType() == DataType.DATE_NANOS) { + return new MonthNameNanosEvaluator.Factory(source(), fieldEvaluator, configuration().zoneId(), configuration().locale()); + } + return new MonthNameMillisEvaluator.Factory(source(), fieldEvaluator, configuration().zoneId(), configuration().locale()); + } + + @Override + public Expression replaceChildren(List newChildren) { + return new MonthName(source(), newChildren.get(0), configuration()); + } + + @Override + protected NodeInfo info() { + return NodeInfo.create(this, MonthName::new, field, configuration()); + } + + @Evaluator(extraName = "Millis") + static BytesRef processMillis(long val, @Fixed ZoneId zoneId, @Fixed Locale locale) { + ZonedDateTime dateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(val), zoneId); + String displayName = dateTime.getMonth().getDisplayName(TextStyle.FULL, locale); + return new BytesRef(displayName); + } + + @Evaluator(extraName = "Nanos") + static BytesRef processNanos(long val, @Fixed ZoneId zoneId, @Fixed Locale locale) { + ZonedDateTime dateTime = ZonedDateTime.ofInstant(Instant.ofEpochSecond(0L, val), zoneId); + String displayName = dateTime.getMonth().getDisplayName(TextStyle.FULL, locale); + return new BytesRef(displayName); + } +} diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameErrorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameErrorTests.java new file mode 100644 index 0000000000000..433a97673d1e2 --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameErrorTests.java @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.scalar.date; + +import org.elasticsearch.xpack.esql.EsqlTestUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.ErrorsForCasesWithoutExamplesTestCase; +import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; +import org.hamcrest.Matcher; + +import java.util.List; +import java.util.Set; + +import static org.hamcrest.Matchers.equalTo; + +public class MonthNameErrorTests extends ErrorsForCasesWithoutExamplesTestCase { + @Override + protected List cases() { + return paramsToSuppliers(MonthNameTests.parameters()); + } + + @Override + protected Expression build(Source source, List args) { + return new MonthName(source, args.get(0), EsqlTestUtils.TEST_CFG); + } + + @Override + protected Matcher expectedTypeErrorMatcher(List> validPerPosition, List signature) { + // Single argument version + String source = sourceForSignature(signature); + String name = signature.get(0).typeName(); + return equalTo("first argument of [" + source + "] must be [datetime or date_nanos], found value [] type [" + name + "]"); + } +} diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameSerializationTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameSerializationTests.java new file mode 100644 index 0000000000000..348c7f9be8cc6 --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameSerializationTests.java @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.scalar.date; + +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.expression.AbstractExpressionSerializationTests; + +import java.io.IOException; + +public class MonthNameSerializationTests extends AbstractExpressionSerializationTests { + + @Override + protected MonthName createTestInstance() { + Source source = randomSource(); + Expression date = randomChild(); + return new MonthName(source, date, configuration()); + } + + @Override + protected MonthName mutateInstance(MonthName instance) throws IOException { + Source source = instance.source(); + Expression date = instance.field(); + return new MonthName(source, randomValueOtherThan(date, AbstractExpressionSerializationTests::randomChild), configuration()); + } + +} diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameTests.java new file mode 100644 index 0000000000000..460a532527a00 --- /dev/null +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameTests.java @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.esql.expression.function.scalar.date; + +import com.carrotsearch.randomizedtesting.annotations.Name; +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.apache.lucene.util.BytesRef; +import org.elasticsearch.common.lucene.BytesRefs; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.time.DateUtils; +import org.elasticsearch.xpack.esql.core.expression.Expression; +import org.elasticsearch.xpack.esql.core.expression.FoldContext; +import org.elasticsearch.xpack.esql.core.expression.Literal; +import org.elasticsearch.xpack.esql.core.tree.Source; +import org.elasticsearch.xpack.esql.core.type.DataType; +import org.elasticsearch.xpack.esql.expression.function.TestCaseSupplier; +import org.elasticsearch.xpack.esql.expression.function.scalar.AbstractConfigurationFunctionTestCase; +import org.elasticsearch.xpack.esql.plugin.EsqlPlugin; +import org.elasticsearch.xpack.esql.plugin.QueryPragmas; +import org.elasticsearch.xpack.esql.session.Configuration; +import org.hamcrest.Matchers; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.TextStyle; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.Supplier; + +import static org.hamcrest.Matchers.equalTo; + +public class MonthNameTests extends AbstractConfigurationFunctionTestCase { + + public MonthNameTests(@Name("TestCase") Supplier testCaseSupplier) { + this.testCase = testCaseSupplier.get(); + } + + @Override + protected Expression buildWithConfiguration(Source source, List args, Configuration configuration) { + return new MonthName(source, args.get(0), configuration); + } + + @ParametersFactory + public static Iterable parameters() { + List suppliers = new ArrayList<>(); + suppliers.addAll(generateTest("1994-01-19T00:00:00.00Z", "January")); + suppliers.addAll(generateTest("1995-02-20T23:59:59.99Z", "February")); + suppliers.addAll(generateTest("1996-03-21T23:12:32.12Z", "March")); + suppliers.addAll(generateTest("1997-04-22T07:39:01.28Z", "April")); + suppliers.addAll(generateTest("1998-05-23T10:25:33.38Z", "May")); + suppliers.addAll(generateTest("1999-06-24T22:55:33.82Z", "June")); + suppliers.addAll(generateTest("2000-07-25T01:01:29.49Z", "July")); + suppliers.addAll(generateTest("2001-08-25T01:01:29.49Z", "August")); + suppliers.addAll(generateTest("2002-09-25T01:01:29.49Z", "September")); + suppliers.addAll(generateTest("2003-10-25T01:01:29.49Z", "October")); + suppliers.addAll(generateTest("2004-11-25T01:01:29.49Z", "November")); + suppliers.addAll(generateTest("2005-12-25T01:01:29.49Z", "December")); + + suppliers.add( + new TestCaseSupplier( + List.of(DataType.DATETIME), + () -> new TestCaseSupplier.TestCase( + List.of(new TestCaseSupplier.TypedData(null, DataType.DATETIME, "date")), + Matchers.startsWith("MonthNameMillisEvaluator[val=Attribute[channel=0], zoneId=Z, locale=en_US]"), + DataType.KEYWORD, + equalTo(null) + ) + ) + ); + + return parameterSuppliersFromTypedDataWithDefaultChecksNoErrors(true, suppliers); + } + + private static List generateTest(String dateTime, String expectedMonthName) { + return List.of( + new TestCaseSupplier( + List.of(DataType.DATETIME), + () -> new TestCaseSupplier.TestCase( + List.of(new TestCaseSupplier.TypedData(toMillis(dateTime), DataType.DATETIME, "date")), + Matchers.startsWith("MonthNameMillisEvaluator[val=Attribute[channel=0], zoneId=Z, locale=en_US]"), + DataType.KEYWORD, + equalTo(new BytesRef(expectedMonthName)) + ) + ), + new TestCaseSupplier( + List.of(DataType.DATE_NANOS), + () -> new TestCaseSupplier.TestCase( + List.of(new TestCaseSupplier.TypedData(toNanos(dateTime), DataType.DATE_NANOS, "date")), + Matchers.is("MonthNameNanosEvaluator[val=Attribute[channel=0], zoneId=Z, locale=en_US]"), + DataType.KEYWORD, + equalTo(new BytesRef(expectedMonthName)) + ) + ) + ); + } + + private static long toMillis(String timestamp) { + return Instant.parse(timestamp).toEpochMilli(); + } + + private static long toNanos(String timestamp) { + return DateUtils.toLong(Instant.parse(timestamp)); + } + + public void testRandomLocale() { + long randomMillis = randomMillisUpToYear9999(); + Configuration cfg = configWithZoneAndLocale(randomZone(), randomLocale(random())); + String expected = Instant.ofEpochMilli(randomMillis) + .atZone(cfg.zoneId()) + .getMonth() + .getDisplayName(TextStyle.FULL, cfg.locale()); + + MonthName func = new MonthName(Source.EMPTY, new Literal(Source.EMPTY, randomMillis, DataType.DATETIME), cfg); + assertThat(BytesRefs.toBytesRef(expected), equalTo(func.fold(FoldContext.small()))); + } + + public void testFixedLocaleAndTime() { + long randomMillis = toMillis("1996-03-21T00:00:00.00Z"); + Configuration cfg = configWithZoneAndLocale(ZoneId.of("America/Sao_Paulo"), Locale.of("pt", "br")); + String expected = "março"; + + MonthName func = new MonthName(Source.EMPTY, new Literal(Source.EMPTY, randomMillis, DataType.DATETIME), cfg); + assertThat(BytesRefs.toBytesRef(expected), equalTo(func.fold(FoldContext.small()))); + } + + private Configuration configWithZoneAndLocale(ZoneId zone, Locale locale) { + return new Configuration( + zone, + locale, + null, + null, + new QueryPragmas(Settings.EMPTY), + EsqlPlugin.QUERY_RESULT_TRUNCATION_MAX_SIZE.getDefault(Settings.EMPTY), + EsqlPlugin.QUERY_RESULT_TRUNCATION_DEFAULT_SIZE.getDefault(Settings.EMPTY), + "", + false, + Map.of(), + System.nanoTime(), + randomBoolean() + ); + } +} From 43ccc49354a6ea9aea2c368cdb2cbdb8c3890733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B4mulo=20Farias?= Date: Fri, 15 Aug 2025 10:32:54 +0200 Subject: [PATCH 2/6] Improve docs --- .../esql/_snippets/functions/description/month_name.md | 2 +- .../esql/kibana/definition/functions/month_name.json | 2 +- .../query-languages/esql/kibana/docs/functions/month_name.md | 2 +- .../xpack/esql/expression/function/scalar/date/MonthName.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/reference/query-languages/esql/_snippets/functions/description/month_name.md b/docs/reference/query-languages/esql/_snippets/functions/description/month_name.md index 49619266fd1f8..ba0b299c2cad4 100644 --- a/docs/reference/query-languages/esql/_snippets/functions/description/month_name.md +++ b/docs/reference/query-languages/esql/_snippets/functions/description/month_name.md @@ -2,5 +2,5 @@ **Description** -Returns the name of the month for provided date based on the configured Locale. +Returns the month name for the provided date based on the configured Locale. diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json b/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json index 0935a9fb59453..65c99051ea542 100644 --- a/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json +++ b/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json @@ -2,7 +2,7 @@ "comment" : "This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.", "type" : "scalar", "name" : "month_name", - "description" : "Returns the name of the month for provided date based on the configured Locale.", + "description" : "Returns the month name for the provided date based on the configured Locale.", "signatures" : [ { "params" : [ diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md b/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md index 09575aae7e483..5b34835f5ae47 100644 --- a/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md +++ b/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md @@ -1,7 +1,7 @@ % This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it. ### MONTH NAME -Returns the name of the month for provided date based on the configured Locale. +Returns the month name for the provided date based on the configured Locale. ```esql ROW dt = to_datetime("1996-03-21T00:00:00.000Z") diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java index 3530cfb3b2b9a..82b2567caa4d7 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java @@ -45,7 +45,7 @@ public class MonthName extends EsqlConfigurationFunction { @FunctionInfo( returnType = "keyword", - description = "Returns the name of the month for provided date based on the configured Locale.", + description = "Returns the month name for the provided date based on the configured Locale.", examples = @Example(file = "date", tag = "docsMonthName"), appliesTo = { @FunctionAppliesTo(lifeCycle = FunctionAppliesToLifecycle.GA, version = "9.2.0") } ) From c340cf0b4d4b1325dabcfad9f06ed30b168b5a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B4mulo=20Farias?= Date: Fri, 15 Aug 2025 10:41:37 +0200 Subject: [PATCH 3/6] Improve tests naming --- .../functions/examples/month_name.md | 2 +- .../definition/functions/month_name.json | 2 +- .../esql/kibana/docs/functions/month_name.md | 2 +- .../src/main/resources/date.csv-spec | 34 +++++++++++-------- 4 files changed, 22 insertions(+), 18 deletions(-) diff --git a/docs/reference/query-languages/esql/_snippets/functions/examples/month_name.md b/docs/reference/query-languages/esql/_snippets/functions/examples/month_name.md index 2f7b0164387b3..81fad547bcfb8 100644 --- a/docs/reference/query-languages/esql/_snippets/functions/examples/month_name.md +++ b/docs/reference/query-languages/esql/_snippets/functions/examples/month_name.md @@ -4,7 +4,7 @@ ```esql ROW dt = to_datetime("1996-03-21T00:00:00.000Z") -| EVAL weekday = MONTH_NAME(dt); +| EVAL monthName = MONTH_NAME(dt); ``` diff --git a/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json b/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json index 65c99051ea542..a8aae09948877 100644 --- a/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json +++ b/docs/reference/query-languages/esql/kibana/definition/functions/month_name.json @@ -30,7 +30,7 @@ } ], "examples" : [ - "ROW dt = to_datetime(\"1996-03-21T00:00:00.000Z\")\n| EVAL weekday = MONTH_NAME(dt);" + "ROW dt = to_datetime(\"1996-03-21T00:00:00.000Z\")\n| EVAL monthName = MONTH_NAME(dt);" ], "preview" : false, "snapshot_only" : false diff --git a/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md b/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md index 5b34835f5ae47..84f7709322091 100644 --- a/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md +++ b/docs/reference/query-languages/esql/kibana/docs/functions/month_name.md @@ -5,5 +5,5 @@ Returns the month name for the provided date based on the configured Locale. ```esql ROW dt = to_datetime("1996-03-21T00:00:00.000Z") -| EVAL weekday = MONTH_NAME(dt); +| EVAL monthName = MONTH_NAME(dt); ``` diff --git a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec index d4bc7b61fe20a..e5efc9e7a37aa 100644 --- a/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec +++ b/x-pack/plugin/esql/qa/testFixtures/src/main/resources/date.csv-spec @@ -1931,14 +1931,15 @@ emp_no:integer | birth_date:date | hire_date:date 10040 | null | 1993-02-14T00:00:00.000Z | null ; + monthNameRowTest required_capability:fn_month_name // tag::docsMonthName[] ROW dt = to_datetime("1996-03-21T00:00:00.000Z") -| EVAL weekday = MONTH_NAME(dt); +| EVAL monthName = MONTH_NAME(dt); // end::docsMonthName[] -dt:date | weekday:keyword +dt:date | monthName:keyword 1996-03-21T00:00:00.000Z | March ; @@ -1947,10 +1948,10 @@ required_capability:fn_month_name from employees | sort emp_no | keep emp_no, hire_date -| eval day = month_name(hire_date) +| eval monthName = month_name(hire_date) | limit 1; -emp_no:integer | hire_date:date | day:keyword +emp_no:integer | hire_date:date | monthName:keyword 10001 | 1986-06-26T00:00:00.000Z | June ; @@ -1962,12 +1963,12 @@ FROM employees | WHERE a > "1987-01-01" and a < "1988-01-01" | EVAL y = date_trunc(1 month, b) | STATS c = count(emp_no) by y -| EVAL week_day = month_name(y) +| EVAL monthName = month_name(y) | SORT y -| KEEP y, c, week_day +| KEEP y, c, monthName | LIMIT 5; -y:date | c:long | week_day:keyword +y:date | c:long | monthName:keyword 1987-03-01T00:00:00.000Z | 5 | March 1987-04-01T00:00:00.000Z | 3 | April 1987-05-01T00:00:00.000Z | 1 | May @@ -1979,11 +1980,11 @@ monthNameNestedCall required_capability:fn_month_name from employees | sort emp_no -| eval first_day_of_month = month_name(date_trunc(1 month, hire_date)) -| keep emp_no, hire_date, first_day_of_month +| eval monthName = month_name(date_trunc(1 month, hire_date)) +| keep emp_no, hire_date, monthName | limit 10; -emp_no:integer | hire_date:datetime | first_day_of_month:keyword +emp_no:integer | hire_date:datetime | monthName:keyword 10001 | 1986-06-26T00:00:00.000Z | June 10002 | 1985-11-21T00:00:00.000Z | November 10003 | 1986-08-28T00:00:00.000Z | August @@ -2000,11 +2001,11 @@ monthNameNestedCall required_capability:fn_month_name from employees | sort emp_no desc -| eval first_day_of_month = to_upper(month_name(date_trunc(1 month, hire_date))) -| keep emp_no, hire_date, first_day_of_month +| eval monthName = to_upper(month_name(date_trunc(1 month, hire_date))) +| keep emp_no, hire_date, monthName | limit 10; -emp_no:integer | hire_date:datetime | first_day_of_month:keyword +emp_no:integer | hire_date:datetime | monthName:keyword 10100 | 1987-09-21T00:00:00.000Z | SEPTEMBER 10099 | 1988-10-18T00:00:00.000Z | OCTOBER 10098 | 1985-05-13T00:00:00.000Z | MAY @@ -2019,8 +2020,11 @@ emp_no:integer | hire_date:datetime | first_day_of_month:keyword monthNameNull required_capability:fn_month_name -from employees | where emp_no == 10040 | eval x = day_name(birth_date) | keep emp_no, birth_date, hire_date, x; +from employees +| where emp_no == 10040 +| eval monthName = month_name(birth_date) +| keep emp_no, birth_date, hire_date, monthName; -emp_no:integer | birth_date:date | hire_date:date | x:keyword +emp_no:integer | birth_date:date | hire_date:date | monthName:keyword 10040 | null | 1993-02-14T00:00:00.000Z | null ; From 1f2db16f1a929f84e9c612343d16db066b570d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B4mulo=20Farias?= Date: Fri, 15 Aug 2025 10:43:44 +0200 Subject: [PATCH 4/6] Remove unecessary comment --- .../esql/expression/function/scalar/date/DayNameErrorTests.java | 1 - .../expression/function/scalar/date/MonthNameErrorTests.java | 1 - 2 files changed, 2 deletions(-) diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DayNameErrorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DayNameErrorTests.java index b47f8dd8ec1cb..f443fc041e67c 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DayNameErrorTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/DayNameErrorTests.java @@ -33,7 +33,6 @@ protected Expression build(Source source, List args) { @Override protected Matcher expectedTypeErrorMatcher(List> validPerPosition, List signature) { - // Single argument version String source = sourceForSignature(signature); String name = signature.get(0).typeName(); return equalTo("first argument of [" + source + "] must be [datetime or date_nanos], found value [] type [" + name + "]"); diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameErrorTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameErrorTests.java index 433a97673d1e2..945cc0a0806a2 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameErrorTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameErrorTests.java @@ -33,7 +33,6 @@ protected Expression build(Source source, List args) { @Override protected Matcher expectedTypeErrorMatcher(List> validPerPosition, List signature) { - // Single argument version String source = sourceForSignature(signature); String name = signature.get(0).typeName(); return equalTo("first argument of [" + source + "] must be [datetime or date_nanos], found value [] type [" + name + "]"); From 30893f1a93c02075da94fcf998ab2ce3cd948fde Mon Sep 17 00:00:00 2001 From: elasticsearchmachine Date: Fri, 15 Aug 2025 08:50:58 +0000 Subject: [PATCH 5/6] [CI] Auto commit changes from spotless --- .../esql/expression/function/scalar/date/MonthName.java | 6 +++++- .../expression/function/scalar/date/MonthNameTests.java | 5 +---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java index 82b2567caa4d7..84ee8130d13dc 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthName.java @@ -39,7 +39,11 @@ import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.FIRST; public class MonthName extends EsqlConfigurationFunction { - public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "MonthName", MonthName::new); + public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry( + Expression.class, + "MonthName", + MonthName::new + ); private final Expression field; diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameTests.java index 460a532527a00..0b29c1d3053b7 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/date/MonthNameTests.java @@ -113,10 +113,7 @@ private static long toNanos(String timestamp) { public void testRandomLocale() { long randomMillis = randomMillisUpToYear9999(); Configuration cfg = configWithZoneAndLocale(randomZone(), randomLocale(random())); - String expected = Instant.ofEpochMilli(randomMillis) - .atZone(cfg.zoneId()) - .getMonth() - .getDisplayName(TextStyle.FULL, cfg.locale()); + String expected = Instant.ofEpochMilli(randomMillis).atZone(cfg.zoneId()).getMonth().getDisplayName(TextStyle.FULL, cfg.locale()); MonthName func = new MonthName(Source.EMPTY, new Literal(Source.EMPTY, randomMillis, DataType.DATETIME), cfg); assertThat(BytesRefs.toBytesRef(expected), equalTo(func.fold(FoldContext.small()))); From 590df5c6adb48dcd856b303ae204a3a7ee468de4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B4mulo=20Farias?= Date: Fri, 15 Aug 2025 12:32:59 +0200 Subject: [PATCH 6/6] Fix docs reference --- .../query-languages/esql/_snippets/lists/date-time-functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/query-languages/esql/_snippets/lists/date-time-functions.md b/docs/reference/query-languages/esql/_snippets/lists/date-time-functions.md index 2000eab6bb33d..137e14e3fa52e 100644 --- a/docs/reference/query-languages/esql/_snippets/lists/date-time-functions.md +++ b/docs/reference/query-languages/esql/_snippets/lists/date-time-functions.md @@ -4,5 +4,5 @@ * [`DATE_PARSE`](../../functions-operators/date-time-functions.md#esql-date_parse) * [`DATE_TRUNC`](../../functions-operators/date-time-functions.md#esql-date_trunc) * [`DAY_NAME`](../../functions-operators/date-time-functions.md#esql-day_name) -* [`MONTH_NAME`](../../functions-operators/date-time-functions.md#esql-month-name) +* [`MONTH_NAME`](../../functions-operators/date-time-functions.md#esql-month_name) * [`NOW`](../../functions-operators/date-time-functions.md#esql-now)