skip to Main Content

When I run select now() - pg_last_xact_replay_timestamp() AS replication_delay directly on the database, the output is

replication_delay
-------------------
 -00:00:00.55072
(1 row)

When I put the same query in a python script

import psycopg2

 try:
    connection = psycopg2.connect(user="postgres",
                              host="x.x.x.x",
                              port="5432",
                              database="postgres")

    cursor = connection.cursor()
    postgreSQL_select_Query = "select now() - pg_last_xact_replay_timestamp() AS 
    replication_delay;"

    cursor.execute(postgreSQL_select_Query)
    records = cursor.fetchall()
    print (records)

    except (Exception, psycopg2.Error) as error:
    print("Error while fetching data from PostgreSQL", error)

    finally:
    # closing database connection.
        if connection:
           cursor.close()
           connection.close()
           print("PostgreSQL connection is closed")

The output is

    [(datetime.timedelta(days=-1, seconds=86399, microseconds=521719),)]

How can I get the output from the script to display like the command line output?

 00:00:00.55072

2

Answers


  1. You’re getting an array of tuples because you’re using fetchall to fetch all rows. Since you’re only fetching one row, use fetchone to get just a tuple.

    Then get the first item in the tuple.

    cursor.execute(postgreSQL_select_Query)
    records = cursor.fetchone()
    delta = records[0]
    

    Now you have just the time interval.


    psycopg2 has mapped the Postgresql interval type to a datetime.timedelta object. You need to format it. Problem is, there’s no built in way to format a timedelta.

    Worse, datetime.timedelta(days=-1, seconds=86399, microseconds=521719 is a very, very strange way to represent -0.478281 seconds, but that’s how timedelta works. Normally you’d just str(delta) to get what you want, but when we try the above we get -1 day, 23:59:59.521719 which is not useful.

    Instead, if it’s negative take the absolute value (which will turn it into datetime.timedelta(microseconds=478281)), turn it into a string, and add the negative sign.

    from datetime import timedelta
    from math import modf
    
    def format_timedelta(delta):
      if delta < timedelta(0):
        return "-" + str(abs(delta))
      else:
        return str(delta)
    
    Login or Signup to reply.
  2. As example:

    select now() - (now() + '.55072 secs'::interval);
        ?column?     
    -----------------
     -00:00:00.55072
    
    
    --The type of the result.
    select pg_typeof(now() - (now() - '.3925 secs'::interval));
     pg_typeof 
    -----------
     interval
    

    From here Interval output see Table 8.18. Interval Output Style Examples. The formatted value returned is going to depend on the intervalstyle setting. In the case above the default ‘postgres` style is used:

    show intervalstyle;
     IntervalStyle 
    ---------------
     postgres
    
    

    This is heads up that if a different `intervalstyle is used the output will differ:

    set intervalstyle = postgres_verbose;
    
    select now() - (now() + '.55072 secs'::interval);
          ?column?      
    --------------------
     @ 0.55072 secs ago
    
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search