pythonoracle-databasetimeto-date

Problem: Incorrect displaying of time difference (in months) between Python and Oracle


The background of my problem is:

The particular part of the query:

ROUND(MONTHS_BETWEEN(sysdate, TO_DATE(c.registration_date, 'dd.mm.yy')) / 12, 1) AS Years_Client

The problem:

<class 'pandas.core.series.Series'>


Solution

  • NEVER use TO_DATE on a column that is already a DATE.

    TO_DATE takes a string as the first argument and with you pass it a DATE then Oracle needs to convert it to a string so that TO_DATE can convert it back to a date - which either:

    1. is pointless (as it was already a date); or

    2. will cause errors (as is your case) because Oracle will convert your query to:

      ROUND(
        MONTHS_BETWEEN(
          sysdate,
          TO_DATE(
            TO_CHAR(
              c.registration_date,
              (SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_DATE_FORMAT')
            ),
            'dd.mm.yy'
          )
        ) / 12,
        1
      )
      

      and if the NLS_DATE_FORMAT does not match dd.mm.yy then it will either raise an exception or you will get an erroneous value.

    In your case:

    To solve it, remove the TO_DATE:

    ROUND(MONTHS_BETWEEN(sysdate, c.registration_date) / 12, 1) AS Years_Client
    

    For example, if you have the data:

    CREATE TABLE table_name (registration_date) AS
    SELECT SYSDATE FROM DUAL UNION ALL
    SELECT DATE '2024-04-01' FROM DUAL UNION ALL
    SELECT DATE '1901-04-24' FROM DUAL;
    

    and the NLS_DATE_FORMAT is YY-MM-DD then:

    SELECT ROUND(MONTHS_BETWEEN(sysdate, TO_DATE(c.registration_date, 'dd.mm.yy')) / 12, 1)
            AS Years_Client,
           ROUND(MONTHS_BETWEEN(sysdate, c.registration_date) / 12, 1)
            AS actual_Years_Client
    FROM   table_name c
    

    Outputs

    YEARS_CLIENT ACTUAL_YEARS_CLIENT
    4 0
    23 .1
    .1 123

    fiddle