SQL: Implement DATETIME_FORMAT function for date/time formatting#54832
SQL: Implement DATETIME_FORMAT function for date/time formatting#54832matriv merged 8 commits intoelastic:masterfrom
Conversation
Implement TO_CHAR(<date/datetime/time>, <pattern>) function with aliases: TOCHAR, DATE_FORMAT, FORMAT which allows for formatting a timestamp to the specified format. The patterns allowed as those of `java.time.format.DateTimeFormatter`. Related to elastic#53714
|
Pinging @elastic/es-ql (:Query Languages/SQL) |
costin
left a comment
There was a problem hiding this comment.
Left some comments - the only remark I have is about the function name.
Looks good otherwise.
| *Description*: Returns the date/datetime/time as a string using the format specified in the 2nd argument. The formatting | ||
| pattern used is the one from | ||
| https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/time/format/DateTimeFormatter.html[`java.time.format.DateTimeFormatter`]. | ||
| If any of the two arguments is `null` or the pattern is an empty string a `null` is returned. |
There was a problem hiding this comment.
drop a : is string null is returned.
If the pattern is empty, null be returned - is that the behavior of the other DBs?
There was a problem hiding this comment.
MySQL and PostgreSQL return null for empty pattern, SQL Server returns string in the default format.
| DOW |SCALAR | ||
| DOY |SCALAR | ||
| DOY |SCALAR | ||
| FORMAT |SCALAR |
There was a problem hiding this comment.
FORMAT seems a bit too generic - is there any DB that uses it?
| import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isString; | ||
| import static org.elasticsearch.xpack.sql.expression.SqlTypeResolutions.isDateOrTime; | ||
|
|
||
| public class ToChar extends BinaryDateTimeFunction { |
There was a problem hiding this comment.
Why is the function called ToChar and not DateFormat?
There was a problem hiding this comment.
No real reason, I just started with the to_char from PostgreSQL.
There was a problem hiding this comment.
Will rename it according to the name of the function we decide to use finally.
| -------------------------------------------------- | ||
|
|
||
| [[sql-functions-datetime-dateformat]] | ||
| ==== `DATE_FORMAT/FORMAT/TO_CHAR/TOCHAR` |
There was a problem hiding this comment.
Do all the function names exist in other DBs? I'd like one which is unique to us due to the Java time format - maybe datetime_format (and datetime_parse) - or vice-versa - format_datetime and parse_datetime.
My point is, I think going forward it would be good to have our own function which uses Java time and then support the rest of the DB functions as translating implementation for the given arguments to our class.
For example DATE_FORMAT which is MySQL specific would exist as such but the MySQL arguments would then be converted into the java.time pattern.
Otherwise looking like MySQL but not supporting its pattern is confusing.
Since the pattern support is tedious, I'm fine with doing that in a separate support for the future. However I'd like to clarify the approach in the docs.
MySQL DATE_FORMAT: https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_date-format
SQL Server FORMAT: https://docs.microsoft.com/en-us/sql/t-sql/functions/format-transact-sql?view=sql-server-ver15#ExampleD
Postgres TO_CHAR: https://www.postgresql.org/docs/9.1/functions-formatting.html
Oracle TOCHAR: https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34510
Note that outside MySQL, the rest of the functions accept multiple formats and data types so to avoid confusion, I would not create aliases for them yet.
But rather treat them separately since if we are to introduce such functions, we would essentially have to obey their semantics rather then ours.
There was a problem hiding this comment.
Renamed to DATETIME_FORMAT
There was a problem hiding this comment.
Changed now, but it seems sane to me, 👍.
Co-Authored-By: Bogdan Pintea <bpintea@gmail.com>
astefan
left a comment
There was a problem hiding this comment.
LGTM. Left just couple of insignificant comments.
| def(MonthName.class, MonthName::new, "MONTH_NAME", "MONTHNAME"), | ||
| def(MonthOfYear.class, MonthOfYear::new, "MONTH_OF_YEAR", "MONTH"), | ||
| def(SecondOfMinute.class, SecondOfMinute::new, "SECOND_OF_MINUTE", "SECOND"), | ||
| def(DateTimeFormat.class, DateTimeFormat::new, "DATETIME_FORMAT"), |
There was a problem hiding this comment.
Any particular reason for not using the alphabetical order (as it is now in the registry)?
There was a problem hiding this comment.
Good catch, will fix, It was because of the original name ToChar.
| format( | ||
| null, | ||
| "first argument of [{}] must be one of {} or their aliases; found value [{}]", | ||
| sourceText(), | ||
| validDateTimeFieldValues(), | ||
| Expressions.name(left()) | ||
| ) |
| if (resolution.unresolved()) { | ||
| return resolution; | ||
| } | ||
| resolution = isString(right(), sourceText(), Expressions.ParamOrdinal.SECOND); |
There was a problem hiding this comment.
isString is enough here? (vs. isStringAndExact)
There was a problem hiding this comment.
Yep, it's enough, tried for example:
SELECT * FROM test WHERE DATETIME_FORMAT(field1, 'uuuu-MM-dd') = '2020-04-08';
SELECT DATETIME_FORMAT(field1, 'uuuu-MM-dd') FROM test;
on an index:
{
"mappings": {
"properties": {
"field1": {
"type": "date"
},
"field2": {
"type": "text"
}
}
}
}
and data:
{
"field1": "05/04/2020 10:20:30",
"field2": "uuuu-MM-dd"
}
and it works.
Implement to_char according to the PostgreSQL spec: https://www.postgresql.org/docs/9.1/functions-formatting.html by translating to the java.time patterns used in DATETIME_FORMAT. Follows: elastic#54832
Implement to_char according to the PostgreSQL spec: https://www.postgresql.org/docs/9.1/functions-formatting.html by translating to the java.time patterns used in DATETIME_FORMAT. Follows: elastic#54832
Implement DATETIME_FORMAT(<date/datetime/time>, ) function
which allows for formatting a timestamp to the specified format. The patterns
allowed as those of
java.time.format.DateTimeFormatter.Related to #53714