Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TIMEDIFF and DATEDIFF functions. #131

Merged

Conversation

Yury-Fridlyand
Copy link

@Yury-Fridlyand Yury-Fridlyand commented Oct 7, 2022

Signed-off-by: Yury-Fridlyand yuryf@bitquilltech.com

Description

I referred to MySQL docs and tried to reproduce MySQL v.8.0.30 behavior as a reference.

New function: TIMEDIFF.

Changes

Signature

(TIME, TIME) -> TIME

Future changes (TODOs):

  1. Accept more/different types if and after [Discussion] Do we need to support more than 24 hours in TIME? opensearch-project/sql#852
  2. Accept strings

Test queries:

-- OpenSearch
SELECT TIMEDIFF('23:59:59', '13:00:00');
-- MySQL
SELECT TIMEDIFF('2007-12-31 23:59:59', '13:00:00');
SELECT TIMEDIFF('2007-12-31 23:59:59', '2004-01-01 13:00:00');
SELECT TIMEDIFF('2000-01-01 00:00:00', now());
SELECT TIMEDIFF(DATE('2008-12-12'), DATE('2008-11-15'));

New function: DATEDIFF.

Changes

Calculates the difference of date part of given values.

Fully compliant with MySQL.

Signature

(DATE/DATETIME/TIMESTAMP/TIME, DATE/DATETIME/TIMESTAMP/TIME) -> LONG

Future changes (TODOs):

Accept strings if it gives performance gain

Test queries:

SELECT DATEDIFF(TIMESTAMP('2000-01-02 00:00:00'), TIMESTAMP('2000-01-01 23:59:59'));
SELECT DATEDIFF(TIME('23:59:59'), TIMESTAMP('2004-01-01 00:00:00'));
SELECT DATEDIFF(TIME('23:59:59'), TIME('00:00:00'));
SELECT DATEDIFF(TIMESTAMP('2000-01-02 00:00:00'), DATETIME('2000-01-01 23:59:59'));

Test data

I found that first 6 rows from date0, time0, time1, datetime0 are good for testing - these columns have different data types in MySQL. In OpenSearch SQL all [date][time] columns have timestamp type, so I use CAST for clear testing.

data
mysql> show fields from Calcs where field IN ('date0', 'time0', 'time1', 'datetime0');
+-----------+-----------+------+-----+---------+-------+
| Field     | Type      | Null | Key | Default | Extra |
+-----------+-----------+------+-----+---------+-------+
| date0     | date      | YES  |     | NULL    |       |
| time0     | datetime  | YES  |     | NULL    |       |
| time1     | time      | YES  |     | NULL    |       |
| datetime0 | timestamp | YES  |     | NULL    |       |
+-----------+-----------+------+-----+---------+-------+
4 rows in set (0.00 sec)
mysql> select date0, time0, time1, datetime0 from calcs;
+------------+---------------------+----------+---------------------+
| date0      | time0               | time1    | datetime0           |
+------------+---------------------+----------+---------------------+
| 2004-04-15 | 1899-12-30 21:07:32 | 19:36:22 | 2004-07-09 10:17:35 |
| 1972-07-04 | 1900-01-01 13:48:48 | 02:05:25 | 2004-07-26 12:30:34 |
| 1975-11-12 | 1900-01-01 18:21:08 | 09:33:31 | 2004-08-02 07:59:23 |
| 2004-06-04 | 1900-01-01 18:51:48 | 22:50:16 | 2004-07-05 13:14:20 |
| 2004-06-19 | 1900-01-01 15:01:19 | NULL     | 2004-07-28 23:30:22 |
| NULL       | 1900-01-01 08:59:39 | 19:57:33 | 2004-07-22 00:30:23 |
| NULL       | 1900-01-01 07:37:48 | NULL     | 2004-07-28 06:54:50 |
| NULL       | 1900-01-01 19:45:54 | 19:48:23 | 2004-07-12 17:30:16 |
| NULL       | 1900-01-01 09:00:59 | 22:20:14 | 2004-07-04 22:49:28 |
| NULL       | 1900-01-01 20:36:00 | NULL     | 2004-07-23 21:13:37 |
| NULL       | 1900-01-01 01:31:32 | 00:05:57 | 2004-07-14 08:16:44 |
| NULL       | 1899-12-30 22:15:40 | 04:40:49 | 2004-07-25 15:22:26 |
| NULL       | 1900-01-01 13:53:46 | 04:48:07 | 2004-07-17 14:01:56 |
| NULL       | 1900-01-01 04:57:51 | NULL     | 2004-07-19 22:21:31 |
| NULL       | 1899-12-30 22:42:43 | 18:58:41 | 2004-07-31 11:57:52 |
| NULL       | 1899-12-30 22:24:08 | NULL     | 2004-07-14 07:43:00 |
| NULL       | 1900-01-01 11:58:29 | 12:33:57 | 2004-07-28 12:34:28 |
+------------+---------------------+----------+---------------------+
17 rows in set (0.00 sec)

Check List

  • New functionality includes testing.
    • All tests pass, including unit test, integration test and doctest
  • New functionality has been documented.
    • New functionality has javadoc added
    • New functionality has user manual doc added
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@codecov
Copy link

codecov bot commented Oct 7, 2022

Codecov Report

Merging #131 (8f97419) into integ-datetime-diff-functions (64a3794) will increase coverage by 0.02%.
The diff coverage is 100.00%.

@@                         Coverage Diff                         @@
##             integ-datetime-diff-functions     #131      +/-   ##
===================================================================
+ Coverage                            95.78%   95.81%   +0.02%     
- Complexity                            3503     3528      +25     
===================================================================
  Files                                  350      350              
  Lines                                 9310     9367      +57     
  Branches                               669      674       +5     
===================================================================
+ Hits                                  8918     8975      +57     
  Misses                                 334      334              
  Partials                                58       58              
Flag Coverage Δ
query-workbench 62.76% <ø> (ø)
sql-engine 98.31% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
...a/org/opensearch/sql/data/model/ExprDateValue.java 100.00% <100.00%> (ø)
...g/opensearch/sql/data/model/ExprDatetimeValue.java 100.00% <100.00%> (ø)
...a/org/opensearch/sql/data/model/ExprTimeValue.java 100.00% <100.00%> (ø)
.../opensearch/sql/data/model/ExprTimestampValue.java 100.00% <100.00%> (ø)
.../org/opensearch/sql/data/model/ExprValueUtils.java 100.00% <100.00%> (ø)
...arch/sql/expression/datetime/DateTimeFunction.java 100.00% <100.00%> (ø)
...h/sql/expression/function/BuiltinFunctionName.java 100.00% <100.00%> (ø)
...pensearch/sql/expression/function/FunctionDSL.java 100.00% <100.00%> (ø)
...n/java/org/opensearch/sql/utils/DateTimeUtils.java 100.00% <100.00%> (ø)

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@MitchellGale
Copy link

It can accept invalid dates.

opensearchsql> SELECT DATEDIFF(TIMESTAMP('2050-01-02 10:00:00'), TIMESTAMP('2000-01-01 23:59:59')); 
..............                                                                                                                                                                                                                                              
fetched rows / total rows = 1/1
+--------------------------------------------------------------------------------+
| DATEDIFF(TIMESTAMP('2050-01-02 10:00:00'), TIMESTAMP('2000-01-01 23:59:59'))   |
|--------------------------------------------------------------------------------|
| 18264                                                                          |
+--------------------------------------------------------------------------------+
opensearchsql> SELECT DATEDIFF(TIMESTAMP('2050-02-30 10:00:00'), TIMESTAMP('2000-01-01 23:59:59')); 
..............                                                                                                                                                                                                                                              
fetched rows / total rows = 1/1
+--------------------------------------------------------------------------------+
| DATEDIFF(TIMESTAMP('2050-02-30 10:00:00'), TIMESTAMP('2000-01-01 23:59:59'))   |
|--------------------------------------------------------------------------------|
| 18321                                                                          |
+--------------------------------------------------------------------------------+
opensearchsql> SELECT DATEDIFF(TIMESTAMP('2050-02-31 10:00:00'), TIMESTAMP('2000-01-01 23:59:59')); 
..............                                                                                                                                                                                                                                              
fetched rows / total rows = 1/1
+--------------------------------------------------------------------------------+
| DATEDIFF(TIMESTAMP('2050-02-31 10:00:00'), TIMESTAMP('2000-01-01 23:59:59'))   |
|--------------------------------------------------------------------------------|
| 18321                                                                          |
+--------------------------------------------------------------------------------+

Expected:

mysql> select datediff('2050-02-31 10:00:00', '2000-01-01 23:59:59');
+--------------------------------------------------------+
| datediff('2050-02-31 10:00:00', '2000-01-01 23:59:59') |
+--------------------------------------------------------+
|                                                   NULL |
+--------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

@MitchellGale
Copy link

24:00:00 should return null

opensearchsql> SELECT DATEDIFF(TIMESTAMP('2000-01-02 24:00:00'), TIMESTAMP('2000-01-01 23:59:59')); 
..............                                                                                                                                                                                                                                              
fetched rows / total rows = 1/1
+--------------------------------------------------------------------------------+
| DATEDIFF(TIMESTAMP('2000-01-02 24:00:00'), TIMESTAMP('2000-01-01 23:59:59'))   |
|--------------------------------------------------------------------------------|
| 2                                                                              |
+--------------------------------------------------------------------------------+

Expected:

mysql> select datediff('2050-02-10 24:00:00', '2000-01-01 23:59:59');
+--------------------------------------------------------+
| datediff('2050-02-10 24:00:00', '2000-01-01 23:59:59') |
+--------------------------------------------------------+
|                                                   NULL |
+--------------------------------------------------------+
1 row in set, 1 warning (0.01 sec)

** Also extends to any invalid time, it should return null

@MitchellGale
Copy link

When second argument is larger than the first argument the returned time is second argument

opensearchsql> select timediff('20:00:00', '22:00:00');                                                                                                                                                                                                     
fetched rows / total rows = 1/1
+------------------------------------+
| timediff('20:00:00', '22:00:00')   |
|------------------------------------|
| 22:00:00                           |
+------------------------------------+

Should give negative time:

mysql> select timediff('20:00:00', '22:00:00'); 
+----------------------------------+
| timediff('20:00:00', '22:00:00') |
+----------------------------------+
| -02:00:00                        |
+----------------------------------+


// Function signature is:
// (DATE/DATETIME/TIMESTAMP/TIME, DATE/DATETIME/TIMESTAMP/TIME) -> LONG
private static Stream<Arguments> getTestData() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add test cases covering the comments I made in the conversations tab.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When second argument is larger than the first argument the returned time is second argument

Should give negative time:

Unfortunately, there is no negative time or time > 24 hours in OpenSearch.
If you start a 22 hour timer at 22:00, it will stop at 20:00 next day. Try playing with other numbers to avoid being confused, e.g. 7 AM/PM and 10 AM/PM.

@Yury-Fridlyand
Copy link
Author

24:00:00 should return null

That's a bug of TIMESTAMP function as well as accepting February 30th - it doesn't use STRICT parser. Will be fixed in scope of another PR.

@acarbonetto acarbonetto changed the title Add TIMEDIFF and DATEDIFF functions. [BLOCKED] Add TIMEDIFF and DATEDIFF functions. Oct 25, 2022
Yury-Fridlyand and others added 7 commits December 9, 2022 19:17
Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
…orresponding tests.

Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>

Co-authored-by: Max Ksyunz <maxk@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
@Yury-Fridlyand Yury-Fridlyand force-pushed the dev-datetime-diff-functions branch from 8cd8f78 to 5468caa Compare December 10, 2022 03:43
@Yury-Fridlyand Yury-Fridlyand changed the title [BLOCKED] Add TIMEDIFF and DATEDIFF functions. Add TIMEDIFF and DATEDIFF functions. Dec 10, 2022
Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
@@ -30,7 +30,7 @@ public class ExprTimestampValue extends AbstractExprValue {
/**
* todo. only support UTC now.
*/
private static final ZoneId ZONE = ZoneId.of("UTC");
public static final ZoneId ZONE = ZoneId.of("UTC");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to make it UTC_ZONE in case other zones are made later

@Yury-Fridlyand Yury-Fridlyand merged commit b235550 into integ-datetime-diff-functions Dec 19, 2022
@Yury-Fridlyand Yury-Fridlyand deleted the dev-datetime-diff-functions branch December 19, 2022 20:57
Yury-Fridlyand added a commit that referenced this pull request Jan 6, 2023
)

* Add `TIMEDIFF` and `DATEDIFF` functions.

Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
Co-authored-by: Max Ksyunz <maxk@bitquilltech.com>

Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
Co-authored-by: Max Ksyunz <maxk@bitquilltech.com>
GabeFernandez310 pushed a commit that referenced this pull request Jan 7, 2023
) (opensearch-project#1234)

* Add `TIMEDIFF` and `DATEDIFF` functions.

Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
Co-authored-by: Max Ksyunz <maxk@bitquilltech.com>

Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
Co-authored-by: Max Ksyunz <maxk@bitquilltech.com>
(cherry picked from commit 438c44d)

Co-authored-by: Yury-Fridlyand <yury.fridlyand@improving.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants