Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El controlador mssql-python gestiona los tipos de fecha y hora de SQL Server y los mapea a los objetos de módulo de datetime Python. SQL Server ofrece múltiples tipos de fecha y hora con precisión y capacidades variables:
| Tipo de SQL | Tipo de Python | Alcance | Precisión |
|---|---|---|---|
| date | datetime.date |
0001-01-01 a 9999-12-31 | Un día |
| time | datetime.time |
00:00:00.0000000 a 23:59:59.99999999 | 100 nanosegundos |
| datetime | datetime.datetime |
1753-01-01 a 9999-12-31 | 3,33 milisegundos |
| datetime2 | datetime.datetime |
0001-01-01 a 9999-12-31 | 100 nanosegundos |
| smalldatetime | datetime.datetime |
1900-01-01 a 2079-06-06 | 1 minuto |
| datetimeoffset |
datetime.datetime (con tzinfo) |
0001-01-01 a 9999-12-31 | 100 nanosegundos + zona horaria |
Insertar valores de fecha-hora
Utiliza objetos de fecha y hora de Python
El siguiente ejemplo inserta diferentes tipos de fecha y hora en SQL Server usando el módulo de datetime Python:
from datetime import datetime, date, time
import mssql_python
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
# Create a temp table with date, time, and datetime columns
cursor.execute("""
CREATE TABLE #Events (
EventDate DATE,
StartTime TIME,
LogTime DATETIME2
)
""")
# Insert date
cursor.execute(
"INSERT INTO #Events (EventDate) VALUES (%(date)s)",
{"date": date(2024, 12, 25)}
)
# Insert time
cursor.execute(
"INSERT INTO #Events (StartTime) VALUES (%(time)s)",
{"time": time(14, 30, 0)}
)
# Insert datetime
cursor.execute(
"INSERT INTO #Events (LogTime) VALUES (%(ts)s)",
{"ts": datetime(2024, 3, 15, 14, 30, 45)}
)
conn.commit()
Insertar marca de tiempo actual
Puedes insertar la fecha y hora actuales usando datetime.now() o la función GETDATE() de SQL Server:
from datetime import datetime
# Create temp table for the demo
cursor.execute("CREATE TABLE #Logs (Message NVARCHAR(200), CreatedAt DATETIME2)")
# Python current time
now = datetime.now()
cursor.execute("INSERT INTO #Logs (Message, CreatedAt) VALUES (%(msg)s, %(ts)s)",
{"msg": "Event occurred", "ts": now})
# Or use SQL Server's GETDATE()
cursor.execute("INSERT INTO #Logs (Message, CreatedAt) VALUES (%(msg)s, GETDATE())",
{"msg": "Event occurred"})
conn.commit()
Fecha de alta precisión2
Para marcas de tiempo de mayor precisión, utilice el datetime2 tipo que soporta una precisión de 100 nanosegundos:
from datetime import datetime
# Create temp table with a datetime2(7) column
cursor.execute("CREATE TABLE #PreciseLogs (EventTime DATETIME2(7))")
# Microsecond precision (Python supports up to microseconds)
precise_time = datetime(2024, 3, 15, 14, 30, 45, 123456)
cursor.execute(
"INSERT INTO #PreciseLogs (EventTime) VALUES (%(ts)s)", # datetime2(7) column
{"ts": precise_time}
)
conn.commit()
Recuperar valores de fecha y hora
Buscar fechas y horas
Al recuperar valores de fecha-hora de SQL Server, se convierten automáticamente a objetos Pythondatetime:
from datetime import date, time, datetime
# Create and populate a temp table with date, time, and datetime columns
cursor.execute("""
CREATE TABLE #Events (
ID INT,
EventDate DATE,
StartTime TIME,
CreatedAt DATETIME2
)
""")
cursor.execute(
"INSERT INTO #Events (ID, EventDate, StartTime, CreatedAt) VALUES (1, %(d)s, %(t)s, %(dt)s)",
{"d": date(2024, 12, 25), "t": time(14, 30, 0), "dt": datetime(2024, 3, 15, 14, 30, 45)}
)
conn.commit()
cursor.execute("SELECT EventDate, StartTime, CreatedAt FROM #Events WHERE ID = 1")
row = cursor.fetchone()
print(type(row.EventDate)) # <class 'datetime.date'>
print(type(row.StartTime)) # <class 'datetime.time'>
print(type(row.CreatedAt)) # <class 'datetime.datetime'>
print(row.EventDate) # 2024-12-25
print(row.StartTime) # 14:30:00
print(row.CreatedAt) # 2024-03-15 14:30:45
Acceder a los componentes de fecha y hora
Los objetos de fecha y hora de Python proporcionan atributos para acceder a componentes individuales de fecha y hora:
cursor.execute("SELECT OrderDate FROM Sales.SalesOrderHeader WHERE SalesOrderID = 43659")
row = cursor.fetchone()
dt = row.OrderDate
# Date components
print(dt.year)
print(dt.month)
print(dt.day)
# Time components
print(dt.hour)
print(dt.minute)
print(dt.second)
print(dt.microsecond)
Zonas horarias
Fechas y horas con desfase frente a fechas y horas sin desfase
Los objetos datetime de Python son o bien conscientes del desplazamiento (tienen tzinfo) o bien ajenos al desplazamiento (sin información de zona horaria). SQL Server tiene ambos tipos de columnas:
| Tipo de SQL Server | Expectativas | ¿Zona horaria de las tiendas? |
|---|---|---|
| datetime, datetime2, smalldatetime | Offset-naïve | No |
| datetimeoffset | Consciente del desplazamiento | Sí |
Enviar una fecha y hora con zona horaria a una columna datetime2 funciona, pero la información de la zona horaria se descarta silenciosamente. Enviar una fecha y hora ingenua a una datetimeoffset columna asigna UTC (+00:00) como desplazamiento. Sé explícito sobre qué tipo envías:
El siguiente ejemplo muestra cómo crear y usar fechas de offset ingenuas y conscientes de offset:
from datetime import datetime, timezone, timedelta
# Create temp tables: one datetime2 column and one datetimeoffset column
cursor.execute("CREATE TABLE #Logs (LogTime DATETIME2)")
cursor.execute("CREATE TABLE #GlobalEvents (EventTime DATETIMEOFFSET)")
# Offset-naive - use for datetime2 columns
naive_dt = datetime(2024, 3, 15, 14, 30, 45)
cursor.execute(
"INSERT INTO #Logs (LogTime) VALUES (%(log_time)s)", # datetime2 column
{"log_time": naive_dt}
)
# Offset-aware - use for datetimeoffset columns
eastern = timezone(timedelta(hours=-5))
aware_dt = datetime(2024, 3, 15, 14, 30, 45, tzinfo=eastern)
cursor.execute(
"INSERT INTO #GlobalEvents (EventTime) VALUES (%(event_time)s)", # datetimeoffset column
{"event_time": aware_dt}
)
conn.commit()
Para convertir entre ambos:
from datetime import datetime, timezone
# Make naive datetime timezone-aware
naive = datetime(2024, 3, 15, 14, 30)
aware = naive.replace(tzinfo=timezone.utc)
# Strip timezone from aware datetime
aware = datetime.now(timezone.utc)
naive = aware.replace(tzinfo=None)
FechatiempoTipo Offset
SQL Server datetimeoffset almacena información sobre la zona horaria. El siguiente ejemplo demuestra cómo insertar y recuperar fechas y horarios con función de la zona horaria:
from datetime import datetime, timezone, timedelta
# Create temp table with a datetimeoffset column
cursor.execute("CREATE TABLE #GlobalEvents (ID INT, EventTime DATETIMEOFFSET)")
# Create timezone-aware datetime
eastern = timezone(timedelta(hours=-5))
dt_eastern = datetime(2024, 3, 15, 14, 30, tzinfo=eastern)
cursor.execute(
"INSERT INTO #GlobalEvents (ID, EventTime) VALUES (1, %(ts)s)", # datetimeoffset column
{"ts": dt_eastern}
)
conn.commit()
# Retrieve timezone-aware datetime
cursor.execute("SELECT EventTime FROM #GlobalEvents WHERE ID = 1")
row = cursor.fetchone()
print(row.EventTime) # 2024-03-15 14:30:00-05:00
print(row.EventTime.tzinfo) # UTC-05:00
Conversión entre husos horarios
Utiliza los métodos de zona horaria de Python para convertir valores de desfase de fecha y tiempo entre diferentes representaciones de zonas horarias:
from datetime import datetime, timezone, timedelta
# Create and populate a temp table with a datetimeoffset column
cursor.execute("CREATE TABLE #GlobalEvents (EventTime DATETIMEOFFSET)")
eastern = timezone(timedelta(hours=-5))
cursor.execute(
"INSERT INTO #GlobalEvents (EventTime) VALUES (%(ts)s)",
{"ts": datetime(2024, 3, 15, 14, 30, tzinfo=eastern)}
)
conn.commit()
# Retrieve as-stored
cursor.execute("SELECT EventTime FROM #GlobalEvents")
row = cursor.fetchone()
stored_time = row.EventTime # Has timezone info
# Convert to UTC
utc_time = stored_time.astimezone(timezone.utc)
print(utc_time)
# Convert to local timezone
local_time = stored_time.astimezone() # System timezone
print(local_time)
AT TIME ZONE en SQL
La cláusula AT TIME ZONE de SQL Server convierte los valores datetimeoffset entre zonas horarias en una consulta:
from datetime import datetime, timezone, timedelta
# Create and populate a temp table with a datetimeoffset column
cursor.execute("CREATE TABLE #GlobalEvents (EventTime DATETIMEOFFSET)")
eastern = timezone(timedelta(hours=-5))
cursor.execute(
"INSERT INTO #GlobalEvents (EventTime) VALUES (%(ts)s)",
{"ts": datetime(2024, 3, 15, 14, 30, tzinfo=eastern)}
)
conn.commit()
# Convert timezone in SQL Server (2016+)
cursor.execute("""
SELECT
EventTime,
EventTime AT TIME ZONE 'Pacific Standard Time' AS PacificTime,
EventTime AT TIME ZONE 'UTC' AS UTCTime
FROM #GlobalEvents
""")
for row in cursor:
print(f"Original: {row.EventTime}")
print(f"Pacific: {row.PacificTime}")
print(f"UTC: {row.UTCTime}")
Aritmética de fechas
Calcular las diferencias de fecha
Calcula el número de días entre dos fechas restando objetos de fecha:
from datetime import timedelta
cursor.execute("SELECT OrderDate, ShipDate FROM Sales.SalesOrderHeader WHERE SalesOrderID = 43659")
row = cursor.fetchone()
# Days between dates
if row.ShipDate and row.OrderDate:
difference = row.ShipDate - row.OrderDate
print(f"Shipped in {difference.days} days")
Añadir intervalos
Úsalo timedelta para sumar o restar días, meses u otros intervalos de una fecha:
from datetime import datetime, timedelta
# Create and populate a temp table
cursor.execute("""
CREATE TABLE #Subscriptions (
ID INT,
CreatedAt DATETIME2,
ExpiresAt DATETIME2
)
""")
cursor.execute(
"INSERT INTO #Subscriptions (ID, CreatedAt) VALUES (1, %(created)s)",
{"created": datetime(2024, 1, 1, 12, 0, 0)}
)
conn.commit()
cursor.execute("SELECT CreatedAt FROM #Subscriptions WHERE ID = 1")
row = cursor.fetchone()
# Calculate expiration (30 days from creation)
expiration = row.CreatedAt + timedelta(days=30)
print(f"Expires: {expiration}")
# Update with calculated date
cursor.execute(
"UPDATE #Subscriptions SET ExpiresAt = %(exp)s WHERE ID = %(id)s",
{"exp": expiration, "id": 1}
)
conn.commit()
DATEADD en SQL
La función de DATEADD SQL Server realiza la aritmética de fechas directamente en las consultas:
# Use SQL Server date functions
cursor.execute("""
SELECT
OrderDate,
DATEADD(day, 30, OrderDate) AS DueDate,
DATEADD(month, 1, OrderDate) AS NextMonth
FROM Sales.SalesOrderHeader
""")
Valores de formato
Formato de visualización
Dar formato a los valores de fecha y hora para mostrarlos usando strftime() con especificadores de formato:
from datetime import datetime
cursor.execute("SELECT TOP(10) OrderDate FROM Sales.SalesOrderHeader")
for row in cursor:
# strftime formatting
print(row.OrderDate.strftime("%Y-%m-%d")) # 2024-03-15
print(row.OrderDate.strftime("%B %d, %Y")) # March 15, 2024
print(row.OrderDate.strftime("%m/%d/%Y %I:%M %p")) # 03/15/2024 02:30 PM
Analizar a partir de cadenas
Convierte las representaciones de cadenas a objetos de fecha y hora en Python usandostrptime():
from datetime import datetime
# Create temp table for the demo
cursor.execute("CREATE TABLE #Events (EventDate DATE)")
# Parse incoming date strings
date_string = "2024-03-15"
parsed_date = datetime.strptime(date_string, "%Y-%m-%d").date()
cursor.execute(
"INSERT INTO #Events (EventDate) VALUES (%(date)s)",
{"date": parsed_date}
)
conn.commit()
Formato ISO 8601
El formato ISO 8601 es útil para APIs y serialización JSON. Uso isoformat() y fromisoformat() para conversión:
from datetime import datetime
# Create and populate a temp table
cursor.execute("CREATE TABLE #Logs (ID INT, CreatedAt DATETIME2)")
cursor.execute(
"INSERT INTO #Logs (ID, CreatedAt) VALUES (1, %(ts)s)",
{"ts": datetime(2024, 3, 15, 14, 30, 45)}
)
conn.commit()
cursor.execute("SELECT CreatedAt FROM #Logs WHERE ID = 1")
row = cursor.fetchone()
# ISO format for APIs/JSON
iso_string = row.CreatedAt.isoformat()
print(iso_string) # 2024-03-15T14:30:45
# Parse ISO format
dt = datetime.fromisoformat("2024-03-15T14:30:45")
Patrones comunes
Consulta por rango de fechas
Consulta registros dentro de un rango de fechas específico parametrizando las fechas de inicio y fin:
from datetime import date, datetime
# Query by date range
start_date = date(2024, 1, 1)
end_date = date(2024, 12, 31)
cursor.execute("""
SELECT SalesOrderID, OrderDate, TotalDue
FROM Sales.SalesOrderHeader
WHERE OrderDate >= %(start)s AND OrderDate < %(end)s
""", {"start": start_date, "end": end_date})
Consulta los registros de hoy
Registros de consulta creados hoy mediante la conversión de la columna de fecha y hora a una fecha y comparando con la fecha de hoy:
from datetime import date
# Create and populate a temp table with a row logged today
cursor.execute("CREATE TABLE #Logs (LogTime DATETIME2)")
cursor.execute("INSERT INTO #Logs (LogTime) VALUES (GETDATE())")
conn.commit()
cursor.execute("""
SELECT * FROM #Logs
WHERE CAST(LogTime AS DATE) = %(today)s
""", {"today": date.today()})
# Or using SQL Server function
cursor.execute("""
SELECT * FROM #Logs
WHERE CAST(LogTime AS DATE) = CAST(GETDATE() AS DATE)
""")
Gestionar fechas NULL
Comprueba los None valores antes de procesar las columnas de fecha, ya que las fechas NULL aparecen como None en Python:
cursor.execute("SELECT TOP 5 FirstName, ModifiedDate FROM Person.Person")
for row in cursor:
if row.ModifiedDate is None:
print(f"{row.FirstName}: Date not on file")
else:
age = (date.today() - row.ModifiedDate.date()).days // 365
print(f"{row.FirstName}: modified {age} years ago")
Guardar marcas de tiempo de auditoría
Crear columnas de auditoría para registrar cuándo se crean y modifican los registros:
from datetime import datetime
# Create temp table for audit timestamp demo
cursor.execute("""
CREATE TABLE #AuditOrders (
ID INT IDENTITY(1,1) PRIMARY KEY,
CustomerID INT,
Total DECIMAL(10,2),
CreatedAt DATETIME2,
ModifiedAt DATETIME2
)
""")
def create_order(cursor, customer_id: int, total: float) -> int:
now = datetime.now()
cursor.execute("""
INSERT INTO #AuditOrders (CustomerID, Total, CreatedAt, ModifiedAt)
VALUES (%(cust)s, %(total)s, %(created)s, %(modified)s);
SELECT SCOPE_IDENTITY();
""", {
"cust": customer_id,
"total": total,
"created": now,
"modified": now
})
return cursor.fetchval()
def update_order(cursor, order_id: int, total: float):
cursor.execute("""
UPDATE #AuditOrders
SET Total = %(total)s, ModifiedAt = %(modified)s
WHERE ID = %(id)s
""", {
"total": total,
"modified": datetime.now(),
"id": order_id
})
Escenarios específicos
Fechas anteriores a 1753
Uso datetime2 para fechas históricas (el datetime tipo solo admite fechas de 1753). El siguiente ejemplo inserta una fecha histórica:
from datetime import datetime
# Create temp table with a datetime2 column
cursor.execute("CREATE TABLE #HistoricalEvents (EventDate DATETIME2, Description NVARCHAR(200))")
# Historical date (works with datetime2, fails with datetime)
historical = datetime(1500, 1, 1)
cursor.execute(
"INSERT INTO #HistoricalEvents (EventDate, Description) VALUES (%(date)s, %(desc)s)",
{"date": historical, "desc": "Archived historical record"}
)
conn.commit()
Valores solo de tiempo
Almacenar valores de la hora del día usando el objeto de time Python:
from datetime import time
# Create temp table with time columns
cursor.execute("""
CREATE TABLE #BusinessHours (
DayOfWeek NVARCHAR(10),
OpenTime TIME,
CloseTime TIME
)
""")
# Store time of day without date
opening_time = time(9, 0, 0) # 9:00 AM
closing_time = time(17, 30, 0) # 5:30 PM
cursor.execute("""
INSERT INTO #BusinessHours (DayOfWeek, OpenTime, CloseTime)
VALUES (%(day)s, %(open)s, %(close)s)
""", {"day": "Monday", "open": opening_time, "close": closing_time})
conn.commit()
Cálculo de días laborables
Una función auxiliar puede calcular intervalos de cita saltándose fines de semana:
from datetime import date, timedelta
def add_business_days(start: date, days: int) -> date:
"""Add business days (skip weekends)."""
current = start
remaining = days
while remaining > 0:
current += timedelta(days=1)
if current.weekday() < 5: # Monday = 0, Friday = 4
remaining -= 1
return current
order_date = date(2024, 3, 15) # Friday
due_date = add_business_days(order_date, 5) # Skip weekend
print(f"Due date: {due_date}") # 2024-03-22 (next Friday)