Skip to content
This repository has been archived by the owner on Oct 9, 2023. It is now read-only.

Python client datetimes are influenced by time zone #298

Closed
steenstral opened this issue May 31, 2023 · 6 comments · Fixed by #301
Closed

Python client datetimes are influenced by time zone #298

steenstral opened this issue May 31, 2023 · 6 comments · Fixed by #301

Comments

@steenstral
Copy link

Description

The Python client API is inconsistent with time zones. When a datetime attribute is inserted, everything is fine. However, when this same attribute is queried, there is an offset of 2 hours (UTC+01:00 + summertime).

Environment

  1. OS: Windows 10
  2. TypeDB version: TypeDB 2.17.0
  3. TypeDB client-python version: client-python 2.17.0 (the newest release 2.18.0 crashes at this moment for some reason)
  4. Python version: Python 3.10.6, Python 3.8.2 and Python 3.7.8 (tested the issue on these three versions)
  5. Other environment details: Clean venv with only typedb-client installed

Reproducible Steps

  1. Make sure that the system time is NOT on (UTC+00:00) or summer/wintertime is ENABLED
  2. Create a virtual environment and install the client
python3 -m venv venv               # Create virtual environment in Python 3
.\venv\Scripts\activate            # Activate the virtual environment
pip install typedb-client==2.17.0  # Install the typedb-client (version 2.18.0 crashes)
  1. Run the TypeDB server
typedb server  # Version 2.17.0
  1. Run this minimal test python file
from typedb.client import TypeDB, SessionType, TransactionType


KEYSPACE = "datetime_issue"


def main() -> None:
    # Create a client
    with TypeDB.core_client(TypeDB.DEFAULT_ADDRESS) as client:
        # Create the keyspace if it does not exist
        if not client.databases().contains(KEYSPACE):
            client.databases().create(KEYSPACE)

        # Create a schema session
        with client.session(KEYSPACE, SessionType.SCHEMA) as session:
            with session.transaction(TransactionType.WRITE) as write_schema_transaction:
                # Only define a datetime attribute
                query = "define test_date sub attribute, value datetime;"
                write_schema_transaction.query().define(query)
                write_schema_transaction.commit()

        # Create a data session
        with client.session(KEYSPACE, SessionType.DATA) as session:
            with session.transaction(TransactionType.WRITE) as write_data_transaction:
                # Insert first of every month, at 00:00:00
                query = """insert
                $time_date_jan isa test_date;  $time_date_jan 2023-01-01T00:00:00;
                $time_date_feb isa test_date;  $time_date_feb 2023-02-01T00:00:00;
                $time_date_mar isa test_date;  $time_date_mar 2023-03-01T00:00:00;
                $time_date_apr isa test_date;  $time_date_apr 2023-04-01T00:00:00;
                $time_date_may isa test_date;  $time_date_may 2023-05-01T00:00:00;
                $time_date_jun isa test_date;  $time_date_jun 2023-06-01T00:00:00;
                $time_date_jul isa test_date;  $time_date_jul 2023-07-01T00:00:00;
                $time_date_aug isa test_date;  $time_date_aug 2023-08-01T00:00:00;
                $time_date_sep isa test_date;  $time_date_sep 2023-09-01T00:00:00;
                $time_date_oct isa test_date;  $time_date_oct 2023-10-01T00:00:00;
                $time_date_nov isa test_date;  $time_date_nov 2023-11-01T00:00:00;
                $time_date_dec isa test_date;  $time_date_dec 2023-12-01T00:00:00;
                """
                write_data_transaction.query().insert(query)
                write_data_transaction.commit()

            with session.transaction(TransactionType.READ) as read_data_transaction:
                # Match all date attributes and print them
                query = "match $date isa test_date; get $date;"
                answer = read_data_transaction.query().match(query)  # <- PROBLEM IS HERE
                dates = [ans.get("date") for ans in answer]
                for date in dates:
                    print(f"Retrieved date: {date.get_value()}")


if __name__ == "__main__":
    main()

Expected Output

I would expect to retrieve back the exact same dates as inserted in the query().insert():

Retrieved date: 2023-01-01 00:00:00
Retrieved date: 2023-02-01 00:00:00
Retrieved date: 2023-03-01 00:00:00
Retrieved date: 2023-04-01 00:00:00
Retrieved date: 2023-05-01 00:00:00
Retrieved date: 2023-06-01 00:00:00
Retrieved date: 2023-07-01 00:00:00
Retrieved date: 2023-08-01 00:00:00
Retrieved date: 2023-09-01 00:00:00
Retrieved date: 2023-10-01 00:00:00
Retrieved date: 2023-11-01 00:00:00
Retrieved date: 2023-12-01 00:00:00

Actual Output

Instead, there is a clear offset in time, 1 hour in wintertime and 2 hours in summertime (exactly UTC+01:00).

Retrieved date: 2023-01-01 01:00:00
Retrieved date: 2023-02-01 01:00:00
Retrieved date: 2023-03-01 01:00:00
Retrieved date: 2023-04-01 02:00:00
Retrieved date: 2023-05-01 02:00:00
Retrieved date: 2023-06-01 02:00:00
Retrieved date: 2023-07-01 02:00:00
Retrieved date: 2023-08-01 02:00:00
Retrieved date: 2023-09-01 02:00:00
Retrieved date: 2023-10-01 02:00:00
Retrieved date: 2023-11-01 01:00:00
Retrieved date: 2023-12-01 01:00:00

Additional information

  • Issue is in the Python client (TypeDB Studio works fine)
    Doing a read data match query in the datetime_issue keyspace inside of TypeDB Studio 2.11.0 on Windows, does NOT have this time offset. This means that the problem is clearly in the Python API, especially in the transaction.query().match(query) method.
  • It depends on the system time
    When the system time in Windows is changed to UTC+00:00 and summer-/wintertime is disabled, there is no time offset.
@hezhichenghzc
Copy link

I met the same issue, does anybody have a solution?

@flyingsilverfin
Copy link
Member

Hi all, we're working on this :) It comes from the fact that the we've used the local date time with your system time zone when sending data to TypeDB. It shouldn't be too hard to resolve but we want to make sure to be systematic about it. We're hoping to have this fixed and released early next week

flyingsilverfin pushed a commit that referenced this issue Jun 30, 2023
## What is the goal of this PR?

Enables the BDD tests to check timezone-invariance of inserting and reading datetime attributes.

## What are the changes implemented in this PR?

- During deserialization of datetime, we incorrectly used `fromtimestamp` function. This function is environment timezone-sensitive. The correct function to use is `utcfromtimestamp` which converts the milliseconds since epoch to UTC datetime object. This conforms to the serialization process: we convert datetime object to milliseconds since epoch assuming the datetime is in UTC.
- Added step which sets environment timezone to `time_zone_label`
- Fixed parsing of class `AttributeMatcher` and `ValueMatcher`.


Fixes #298.
@flyingsilverfin
Copy link
Member

@hezhichenghzc @steenstral FYI the release is out on github & pip, please let us know if there are any remaining issues :)

@steenstral
Copy link
Author

@flyingsilverfin Unfortunately I cannot test it yet, because there is a version mismatch between te client (2.18.1) and the server (2.17.0). When trying to create a client I get the following error:

Error traceback

Traceback (most recent call last):
  File "c:\<path_to_workspace>\datetime_example.py", line 55, in <module>
    main()
  File "c:\<path_to_workspace>\datetime_example.py", line 9, in main   
    with TypeDB.core_client(TypeDB.DEFAULT_ADDRESS) as client:
  File "C:\<path_to_workspace>\venv\lib\site-packages\typedb\client.py", line 70, in core_client
    return _CoreClient(address, parallelisation)
  File "C:\<path_to_workspace>\venv\lib\site-packages\typedb\connection\core\client.py", line 35, in __init__
    self._channel, self._stub = self.new_channel_and_stub()
  File "C:\<path_to_workspace>\venv\lib\site-packages\typedb\connection\core\client.py", line 52, in new_channel_and_stub
    return channel, _CoreStub(channel)
  File "C:\<path_to_workspace>\venv\lib\site-packages\typedb\connection\core\stub.py", line 42, in __init__
    raise e
  File "C:\<path_to_workspace>\venv\lib\site-packages\typedb\connection\core\stub.py", line 39, in __init__
    self._stub.connection_open(connection_open_req())
  File "C:\<path_to_workspace>\venv\lib\site-packages\grpc\_channel.py", line 1030, in __call__
    return _end_unary_response_blocking(state, call, False, None)
  File "C:\<path_to_workspace>\venv\lib\site-packages\grpc\_channel.py", line 910, in _end_unary_response_blocking
    raise _InactiveRpcError(state)  # pytype: disable=not-instantiable
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
        status = StatusCode.UNAVAILABLE
        details = "failed to connect to all addresses; last error: UNAVAILABLE: ipv6:%5B::1%5D:1729: 
WSA Error"
        debug_error_string = "UNKNOWN:failed to connect to all addresses; last error: UNAVAILABLE: ipv6:%5B::1%5D:1729: WSA Error {grpc_status:14, created_time:"2023-07-06T08:58:42.245912889+00:00"}"   
>

I saw this issue also passing by on Discord. Is there a way I can test this patch update, or do I need to wait for the new TypeDB server release?

@dmitrii-ubskii
Copy link
Member

dmitrii-ubskii commented Jul 6, 2023

@steenstral

Unfortunately I cannot test it yet, because there is a version mismatch between te client (2.18.1) and the server (2.17.0).

TypeDB 2.19 is available on the Releases page (https://github.com/vaticle/typedb/releases/tag/2.19.0), and in package managers like apt and brew.

@steenstral
Copy link
Author

I updated my TypeDB server version, and I can confirm that it is working and that I now get the expected result. Thank you for solving this issue!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
6 participants