-
Notifications
You must be signed in to change notification settings - Fork 199
Add variable precision time and timestamp support #229
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
Changes from all commits
adf5394
9d38bf9
386e6ff
d21007f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| import math | ||
| from datetime import timedelta, datetime, date, time | ||
| import pytest | ||
| import pytz | ||
| from decimal import Decimal | ||
| import trino | ||
|
|
||
|
|
@@ -200,6 +202,159 @@ def test_digest(trino_connection): | |
| .execute() | ||
|
|
||
|
|
||
| def test_date(trino_connection): | ||
| SqlTest(trino_connection) \ | ||
| .add_field(sql="CAST(null AS DATE)", python=None) \ | ||
| .add_field(sql="DATE '2001-08-22'", python=date(2001, 8, 22)) \ | ||
| .add_field(sql="DATE '0001-01-01'", python=date(1, 1, 1)) \ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's a good idea to have the dates sorted and to include a min value and max value so it's obvious what the boundaries are. Also add a test to verify we get useful errors on querying years < 1 or years > 9999. |
||
| .add_field(sql="DATE '1582-10-04'", python=date(1582, 10, 4)) \ | ||
| .add_field(sql="DATE '1582-10-05'", python=date(1582, 10, 5)) \ | ||
| .add_field(sql="DATE '1582-10-14'", python=date(1582, 10, 14)) \ | ||
| .execute() | ||
|
|
||
|
|
||
| def test_time(trino_connection): | ||
| time_0 = time(1, 23, 45) | ||
| time_3 = time(1, 23, 45, 123000) | ||
| time_6 = time(1, 23, 45, 123456) | ||
| time_round = time(1, 23, 45, 123457) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we only test upwards rounding. Add cases for:
Zero value with precision preserved
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for test_time_with_timezone
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually the rounding code does not work, and the only examples I could fine involve third party packages such as numpy. So open to suggestions for a better approach
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry I added one more 9 in every case. Edited to correct. |
||
|
|
||
| SqlTest(trino_connection) \ | ||
| .add_field(sql="CAST(null AS TIME)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(0))", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(3))", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(6))", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(9))", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(12))", python=None) \ | ||
| .add_field(sql="CAST('01:23:45' AS TIME(0))", python=time_0) \ | ||
| .add_field(sql="TIME '01:23:45.123'", python=time_3) \ | ||
| .add_field(sql="CAST('01:23:45.123' AS TIME(3))", python=time_3) \ | ||
| .add_field(sql="CAST('01:23:45.123456' AS TIME(6))", python=time_6) \ | ||
| .add_field(sql="CAST('01:23:45.123456789' AS TIME(9))", python=time_round) \ | ||
| .add_field(sql="CAST('01:23:45.123456789123' AS TIME(12))", python=time_round) \ | ||
| .execute() | ||
|
|
||
|
|
||
| def test_time_with_timezone(trino_connection): | ||
| query_time_with_timezone(trino_connection, '-08:00') | ||
| query_time_with_timezone(trino_connection, '+08:00') | ||
| query_time_with_timezone(trino_connection, '+05:30') | ||
hashhar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| def query_time_with_timezone(trino_connection, tz_str): | ||
| tz = datetime.strptime('+00:00', "%z").tzinfo | ||
|
|
||
| hours_shift = int(tz_str[:3]) | ||
| minutes_shift = int(tz_str[4:]) | ||
| delta = timedelta(hours=hours_shift, minutes=minutes_shift) | ||
|
|
||
| time_0 = (datetime(2, 1, 1, 11, 23, 45, 0) - delta).time().replace(tzinfo=tz) | ||
| time_3 = (datetime(2, 1, 1, 11, 23, 45, 123000) - delta).time().replace(tzinfo=tz) | ||
| time_6 = (datetime(2, 1, 1, 11, 23, 45, 123456) - delta).time().replace(tzinfo=tz) | ||
| time_round = (datetime(2, 1, 1, 11, 23, 45, 123457) - delta).time().replace(tzinfo=tz) | ||
|
|
||
| SqlTest(trino_connection) \ | ||
| .add_field(sql="CAST(null AS TIME WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(0) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(3) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(6) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(9) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIME(12) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST('11:23:45 %s' AS TIME(0) WITH TIME ZONE)" % (tz_str), python=time_0) \ | ||
| .add_field(sql="TIME '11:23:45.123 %s'" % (tz_str), python=time_3) \ | ||
| .add_field(sql="CAST('11:23:45.123 %s' AS TIME(3) WITH TIME ZONE)" % (tz_str), python=time_3) \ | ||
| .add_field(sql="CAST('11:23:45.123456 %s' AS TIME(6) WITH TIME ZONE)" % (tz_str), python=time_6) \ | ||
| .add_field(sql="CAST('11:23:45.123456789 %s' AS TIME(9) WITH TIME ZONE)" % (tz_str), python=time_round) \ | ||
| .add_field(sql="CAST('11:23:45.123456789123 %s' AS TIME(12) WITH TIME ZONE)" % (tz_str), python=time_round) \ | ||
| .execute() | ||
|
|
||
|
|
||
| def test_timestamp(trino_connection): | ||
| timestamp_0 = datetime(2001, 8, 22, 1, 23, 45, 0) | ||
| timestamp_3 = datetime(2001, 8, 22, 1, 23, 45, 123000) | ||
| timestamp_6 = datetime(2001, 8, 22, 1, 23, 45, 123456) | ||
| timestamp_round = datetime(2001, 8, 22, 1, 23, 45, 123457) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TIMESTAMP '1970-01-01 00:00:00.12345671' -> TIMESTAMP '1970-01-01 00:00:00.1234567' (round down)
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also sort according to value + add min and max supported value + verify what error we get for max. |
||
| timestamp_ce = datetime(1, 1, 1, 1, 23, 45, 123000) | ||
| timestamp_julian = datetime(1582, 10, 4, 1, 23, 45, 123000) | ||
| timestamp_during_switch = datetime(1582, 10, 5, 1, 23, 45, 123000) | ||
| timestamp_gregorian = datetime(1582, 10, 14, 1, 23, 45, 123000) | ||
|
|
||
| SqlTest(trino_connection) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(0))", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(3))", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(6))", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(9))", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(12))", python=None) \ | ||
| .add_field(sql="CAST('2001-08-22 01:23:45' AS TIMESTAMP(0))", python=timestamp_0) \ | ||
| .add_field(sql="TIMESTAMP '2001-08-22 01:23:45.123'", python=timestamp_3) \ | ||
| .add_field(sql="TIMESTAMP '0001-01-01 01:23:45.123'", python=timestamp_ce) \ | ||
| .add_field(sql="TIMESTAMP '1582-10-04 01:23:45.123'", python=timestamp_julian) \ | ||
| .add_field(sql="TIMESTAMP '1582-10-05 01:23:45.123'", python=timestamp_during_switch) \ | ||
| .add_field(sql="TIMESTAMP '1582-10-14 01:23:45.123'", python=timestamp_gregorian) \ | ||
| .add_field(sql="CAST('2001-08-22 01:23:45.123' AS TIMESTAMP(3))", python=timestamp_3) \ | ||
| .add_field(sql="CAST('2001-08-22 01:23:45.123456' AS TIMESTAMP(6))", python=timestamp_6) \ | ||
| .add_field(sql="CAST('2001-08-22 01:23:45.123456111' AS TIMESTAMP(9))", python=timestamp_6) \ | ||
| .add_field(sql="CAST('2001-08-22 01:23:45.123456789' AS TIMESTAMP(9))", python=timestamp_round) \ | ||
| .add_field(sql="CAST('2001-08-22 01:23:45.123456111111' AS TIMESTAMP(12))", python=timestamp_6) \ | ||
| .add_field(sql="CAST('2001-08-22 01:23:45.123456789123' AS TIMESTAMP(12))", python=timestamp_round) \ | ||
| .execute() | ||
|
|
||
|
|
||
| def test_timestamp_with_timezone(trino_connection): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Squash "Refactor some test function names for consistency" since it changes something introduced in the first commit itself. |
||
| query_timestamp_with_timezone(trino_connection, '-08:00') | ||
| query_timestamp_with_timezone(trino_connection, '+08:00') | ||
| query_timestamp_with_timezone(trino_connection, '+05:30') | ||
| query_timestamp_with_timezone(trino_connection, 'US/Eastern') | ||
| query_timestamp_with_timezone(trino_connection, 'Asia/Kolkata') | ||
| query_timestamp_with_timezone(trino_connection, 'GMT') | ||
|
|
||
|
|
||
| def query_timestamp_with_timezone(trino_connection, tz_str): | ||
| if tz_str.startswith('+') or tz_str.startswith('-'): | ||
| hours_shift = int(tz_str[:3]) | ||
| minutes_shift = int(tz_str[4:]) | ||
| else: | ||
| tz = pytz.timezone(tz_str) | ||
| offset = tz.utcoffset(datetime.now()) | ||
| offset_seconds = offset.total_seconds() | ||
| hours_shift = int(offset_seconds / 3600) | ||
| minutes_shift = offset_seconds % 3600 / 60 | ||
|
|
||
| tz = pytz.timezone('Etc/GMT') | ||
| delta = timedelta(hours=hours_shift, minutes=minutes_shift) | ||
|
|
||
| timestamp_0 = tz.localize(datetime(2001, 8, 22, 11, 23, 45, 0)) - delta | ||
| timestamp_3 = tz.localize(datetime(2001, 8, 22, 11, 23, 45, 123000)) - delta | ||
| timestamp_6 = tz.localize(datetime(2001, 8, 22, 11, 23, 45, 123456)) - delta | ||
| timestamp_round = tz.localize(datetime(2001, 8, 22, 11, 23, 45, 123457)) - delta | ||
|
Comment on lines
+327
to
+330
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is not how timezones work. Depending on exact date the shift value can be different. i.e. offset = tz.utcoffset(datetime.now()) will give different offsets based on different time of year or dates. Is there no way to "apply" a timezone to a datetime? |
||
|
|
||
| SqlTest(trino_connection) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(0) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(3) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(6) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(9) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST(null AS TIMESTAMP(12) WITH TIME ZONE)", python=None) \ | ||
| .add_field(sql="CAST('2001-08-22 11:23:45 %s' AS TIMESTAMP(0) WITH TIME ZONE)" % (tz_str), | ||
| python=timestamp_0) \ | ||
| .add_field(sql="TIMESTAMP '2001-08-22 11:23:45.123 %s'" % (tz_str), | ||
| python=timestamp_3) \ | ||
| .add_field(sql="CAST('2001-08-22 11:23:45.123 %s' AS TIMESTAMP(3) WITH TIME ZONE)" % (tz_str), | ||
| python=timestamp_3) \ | ||
| .add_field(sql="CAST('2001-08-22 11:23:45.123456 %s' AS TIMESTAMP(6) WITH TIME ZONE)" % (tz_str), | ||
| python=timestamp_6) \ | ||
| .add_field(sql="CAST('2001-08-22 11:23:45.123456111 %s' AS TIMESTAMP(9) WITH TIME ZONE)" % (tz_str), | ||
| python=timestamp_6) \ | ||
| .add_field(sql="CAST('2001-08-22 11:23:45.123456789 %s' AS TIMESTAMP(9) WITH TIME ZONE)" % (tz_str), | ||
| python=timestamp_round) \ | ||
| .add_field(sql="CAST('2001-08-22 11:23:45.123456111111 %s' AS TIMESTAMP(12) WITH TIME ZONE)" % (tz_str), | ||
| python=timestamp_6) \ | ||
| .add_field(sql="CAST('2001-08-22 11:23:45.123456789123 %s' AS TIMESTAMP(12) WITH TIME ZONE)" % (tz_str), | ||
| python=timestamp_round) \ | ||
| .execute() | ||
|
|
||
|
|
||
| class SqlTest: | ||
| def __init__(self, trino_connection): | ||
| self.cur = trino_connection.cursor(experimental_python_types=True) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.