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

Oracle datetimetz incorrectly parsed due to disagreement between OraclePlatform->getDateTimeTzFormatString() and Oracle driver's InitializeSession #6469

Open
wayne530 opened this issue Jul 15, 2024 · 0 comments

Comments

@wayne530
Copy link

wayne530 commented Jul 15, 2024

Bug Report

Q A
Version all versions >= 3.7.0 (I did not check prior versions)

Summary

This issue was documented in #2332 however simply because a workaround exists, I would not consider the issue "fixed" as everyone using datetimetz will encounter this issue when using Oracle and as a result, will have many corrupted datetimetz values that need to be corrected even after the workaround is discovered and applied. tl;dr This is a major issue with a relatively trivial fix so rather than rely on a workaround (which requires digging through your issues to find), how about just fixing it in all actively maintained version branches?

Current behaviour

Timestamps that have a negative offset from GMT, for example PST (UTC-8) or PDT (UTC-7) are incorrectly parsed as positive offsets from GMT. For example, datetimetz values with a -08:00 offset are stored in Oracle as +08:00.

How to reproduce

Reproducing this issue is quite straightforward. The Oracle InitializeSession middleware sets NLS_TIMESTAMP_TZ_FORMAT to YYYY-MM-DD HH24:MI:SS TZH:TZM:

                $connection->exec(
                    'ALTER SESSION SET'
                        . " NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
                        . " NLS_TIME_FORMAT = 'HH24:MI:SS'"
                        . " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
                        . " NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS TZH:TZM'"
                        . " NLS_NUMERIC_CHARACTERS = '.,'",
                );

while OraclePlatform->getDateTimeTzFormatString() uses:

    public function getDateTimeTzFormatString(): string
    {
        return 'Y-m-d H:i:sP';
    }

Thus, if I wish set set a datetimetz from the current datetime in my location at the time of this writing, which is 2024-07-15T11:16:00-07:00, I would take the DateTime instance and format it to a string using the format provided by OraclePlatform, or 2024-07-15 11:16:00-07:00.

Connect to an Oracle database using credentials that allow you to create tables and insert. Initialize the session as the Oracle middleware would:

ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_TIME_FORMAT = 'HH24:MI:SS' NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS' NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS TZH:TZM' NLS_NUMERIC_CHARACTERS = '.,';

Create a table with a single column that is a TIMESTAMP WITH TIME ZONE type:

CREATE TABLE test (created_at TIMESTAMP WITH TIME ZONE);

Insert a row into the table and provide the string formatted datetimetz as OraclePlatform would provide:

INSERT INTO test (created_at) VALUES ('2024-07-15 11:16:00-07:00');

Now view the stored row:

SELECT * FROM test;

Expected output:

2024-07-15 11:16:00 -07:00

Actual output:

2024-07-15 11:16:00 +07:00

Expected behaviour

datetimetz values should be stored with the correct UTC offset. Hopefully this is not controversial.

The fix

The fix is quite straightforward. Make OraclePlatform->getDateTimeTzFormatString() and Oracle middleware's InitializeSession agree on a datetimetz format, whether that is with OR without a space. For example, leave OraclePlatform as is and simply update InitializeSession as follows:

                $connection->exec(
                    'ALTER SESSION SET'
                        . " NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
                        . " NLS_TIME_FORMAT = 'HH24:MI:SS'"
                        . " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"
                        . " NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SSTZH:TZM'"
                        . " NLS_NUMERIC_CHARACTERS = '.,'",
                );
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

No branches or pull requests

1 participant