杰瑞科技汇

python oracle date

Of course! Working with Oracle dates in Python is a common task, especially when interacting with databases. The key is to handle the conversion between Python's datetime objects and Oracle's DATE or TIMESTAMP data types correctly.

python oracle date-图1
(图片来源网络,侵删)

Here’s a comprehensive guide covering the most common scenarios, using the popular cx_Oracle driver.

Prerequisites: Install the Oracle Driver

First, you need to install the Oracle client library and the Python driver. The easiest way is to use the pre-compiled cx_Oracle wheels.

# Install the Python driver
pip install cx_Oracle

The cx_Oracle package will automatically attempt to find the Oracle client libraries. If it can't find them, you'll need to install them manually and set the LD_LIBRARY_PATH (Linux/macOS) or PATH (Windows) environment variable to point to the Oracle client's bin directory.


Scenario 1: Inserting a Python datetime into an Oracle Table

This is the most frequent operation. You have a Python datetime object and want to save it to an Oracle DATE column.

python oracle date-图2
(图片来源网络,侵删)

The Problem by Default

If you try to pass a Python datetime object directly to cursor.execute(), you'll likely get a TypeError. Oracle expects its own date format.

import cx_Oracle
from datetime import datetime
# --- Setup (replace with your actual connection details) ---
# Ensure your TNS_ADMIN environment variable is set, or provide the dsn
try:
    conn = cx_Oracle.connect(user="your_username", password="your_password", dsn="your_dsn")
    print("Successfully connected to Oracle Database")
except cx_Oracle.DatabaseError as e:
    print(f"Error connecting to Oracle: {e}")
    exit()
# --- Problematic Code ---
try:
    cursor = conn.cursor()
    my_date = datetime(2025, 10, 27, 10, 30, 0) # A Python datetime object
    # This will FAIL with a TypeError
    # cursor.execute("INSERT INTO my_table (id, event_date) VALUES (1, :1)", (my_date,))
    # print("Insert successful (this won't run)")
except Exception as e:
    print(f"An error occurred: {e}")

The Solution: Use cursor.setinputsizes()

The standard and most robust way to handle this is to tell cx_Oracle what data type to expect for your variable using cursor.setinputsizes().

import cx_Oracle
from datetime import datetime
# Assume 'conn' is your active connection from the previous example
cursor = conn.cursor()
# 1. Create a table for the example (if it doesn't exist)
cursor.execute("""
    BEGIN
        EXECUTE IMMEDIATE 'DROP TABLE my_date_table';
    EXCEPTION
        WHEN OTHERS THEN NULL;
    END;
""")
cursor.execute("""
    CREATE TABLE my_date_table (
        id          NUMBER PRIMARY KEY,
        event_date  DATE,
        description VARCHAR2(100)
    )
""")
# 2. Define your Python datetime object
my_date = datetime(2025, 10, 27, 10, 30, 0)
# 3. Tell the cursor to expect an Oracle DATE type for the second variable
#    This is the key step!
cursor.setinputsizes(cx_Oracle.DATETIME) 
# 4. Now, execute the insert. It will work perfectly.
try:
    cursor.execute(
        "INSERT INTO my_date_table (id, event_date, description) VALUES (:1, :2, :3)",
        (101, my_date, "Python datetime inserted")
    )
    conn.commit()
    print("Successfully inserted datetime into Oracle.")
except cx_Oracle.DatabaseError as e:
    print(f"Error inserting: {e}")
    conn.rollback()
cursor.close()

Scenario 2: Fetching an Oracle Date into a Python datetime

When you query an Oracle DATE column, cx_Oracle automatically converts it into a Python datetime object. This is usually what you want.

# Assume the data from the previous example is in the table
cursor = conn.cursor()
try:
    cursor.execute("SELECT id, event_date, description FROM my_date_table WHERE id = 101")
    # Fetch one row
    row = cursor.fetchone()
    if row:
        id_val, event_date, desc = row
        # 'event_date' is now a Python datetime object
        print(f"Fetched ID: {id_val}")
        print(f"Fetched Date Type: {type(event_date)}")  # <class 'datetime.datetime'>
        print(f"Fetched Date Value: {event_date}")
        print(f"Fetched Description: {desc}")
        # You can now use it like any other Python datetime
        print(f"Formatted Date: {event_date.strftime('%Y-%m-%d %H:%M:%S')}")
except cx_Oracle.DatabaseError as e:
    print(f"Error fetching: {e}")
cursor.close()

Scenario 3: Working with Oracle TIMESTAMP Data Types

Oracle's TIMESTAMP data type is more precise than DATE (it can include fractional seconds and time zone information). cx_Oracle handles this gracefully.

Inserting a datetime into a TIMESTAMP column

The process is almost identical. You just need to specify the correct type.

# Assume a table with a TIMESTAMP column
cursor.execute("""
    CREATE TABLE my_timestamp_table (
        id          NUMBER PRIMARY KEY,
        event_ts    TIMESTAMP(6), -- TIMESTAMP with 6 fractional digits
        description VARCHAR2(100)
    )
""")
my_datetime = datetime(2025, 10, 27, 10, 30, 45, 123456) # Includes microseconds
# Tell the cursor to expect an Oracle TIMESTAMP type
cursor.setinputsizes(cx_Oracle.TIMESTAMP)
cursor.execute(
    "INSERT INTO my_timestamp_table (id, event_ts, description) VALUES (:1, :2, :3)",
    (201, my_datetime, "Python datetime with microseconds")
)
conn.commit()
print("Successfully inserted datetime into TIMESTAMP column.")

Fetching a TIMESTAMP into a Python datetime

When you fetch a TIMESTAMP, cx_Oracle converts it into a Python datetime object. The microseconds will be preserved.

cursor.execute("SELECT id, event_ts FROM my_timestamp_table WHERE id = 201")
row = cursor.fetchone()
if row:
    id_val, event_ts = row
    print(f"Fetched ID: {id_val}")
    print(f"Fetched Timestamp Type: {type(event_ts)}") # <class 'datetime.datetime'>
    print(f"Fetched Timestamp Value: {event_ts}")
    print(f"Microseconds: {event_ts.microsecond}")

Advanced: Handling Time Zones with TIMESTAMP WITH TIME ZONE

If your Oracle column is TIMESTAMP WITH TIME ZONE, you'll get a Python datetime object with a tzinfo attribute.

# Create a table with a TIMESTAMP WITH TIME ZONE column
cursor.execute("""
    CREATE TABLE my_timestamptz_table (
        id          NUMBER PRIMARY KEY,
        event_tstz  TIMESTAMP WITH TIME ZONE
    )
""")
# You need a timezone-aware datetime object
from datetime import timezone, timedelta
tz_aware_datetime = datetime(2025, 10, 27, 15, 0, 0, tzinfo=timezone(timedelta(hours=5))) # UTC+5
# Tell the cursor to expect the correct type
cursor.setinputsizes(cx_Oracle.TIMESTAMP)
cursor.execute("INSERT INTO my_timestamptz_table (id, event_tstz) VALUES (:1, :2)", (301, tz_aware_datetime))
conn.commit()
print("Successfully inserted timezone-aware datetime.")
# --- Fetching it back ---
cursor.execute("SELECT id, event_tstz FROM my_timestamptz_table WHERE id = 301")
row = cursor.fetchone()
if row:
    id_val, event_tstz = row
    print(f"\nFetched TZ-Aware Timestamp: {event_tstz}")
    print(f"Timezone Info: {event_tstz.tzinfo}")

Summary and Best Practices

Task Python Object Oracle Type Method
Insert datetime into DATE datetime.datetime DATE Use cursor.setinputsizes(cx_Oracle.DATETIME) before cursor.execute().
Insert datetime into TIMESTAMP datetime.datetime TIMESTAMP Use cursor.setinputsizes(cx_Oracle.TIMESTAMP) before cursor.execute().
Insert datetime into TIMESTAMP WITH TZ datetime.datetime with tzinfo TIMESTAMP WITH TIME ZONE Use cursor.setinputsizes(cx_Oracle.TIMESTAMP). The object must be timezone-aware.
Fetch any Oracle Date/Timestamp datetime.datetime DATE, TIMESTAMP, etc. It happens automatically. No special handling needed.

Key Takeaways:

  1. For Inserts: Always use cursor.setinputsizes() to explicitly define the Oracle data type (cx_Oracle.DATETIME, cx_Oracle.TIMESTAMP). This is the most reliable method.
  2. For Fetches: cx_Oracle does the heavy lifting for you, converting Oracle dates into Python datetime objects.
  3. Time Zones: Be mindful of time zones. If your Oracle column stores time zone information, ensure your Python datetime object is timezone-aware (has a tzinfo attribute).
  4. Connection Handling: Always use try...except blocks for database operations and conn.commit() to save changes. Use conn.rollback() in your except block to undo any partial transactions in case of an error.
分享:
扫描分享到社交APP
上一篇
下一篇