Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Ovladač mssql-python zpracovává datumové a časové typy SQL Server a mapuje je na objekty datetime modulů Python. SQL Server poskytuje více typů dat a času s různou přesností a schopnostmi:
| Typ SQL | Typ Pythonu | Range | Přesnost |
|---|---|---|---|
| date | datetime.date |
0001-01-01 do 9999-12-31 | Jeden den |
| time | datetime.time |
00:00:00.0000000 až 23:59:59.9999999 | 100 nanosekund |
| datetime | datetime.datetime |
1753-01-01 až 9999-12-31 | 3,33 milisekund |
| datetime2 | datetime.datetime |
0001-01-01 do 9999-12-31 | 100 nanosekund |
| smalldatetime | datetime.datetime |
1900-01-01 až 2079-06-06 | 1 minuta |
| datetimeoffset |
datetime.datetime (s tzinfo) |
0001-01-01 do 9999-12-31 | 100 nanosekund + časové pásmo |
Vložte hodnoty datového času
Používejte Python datetime objekty
Následující příklad vkládá různé typy dat a času do SQL Server pomocí modulu 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()
Vložte aktuální časové razítko
Aktuální datum a čas můžete vložit pomocí datetime.now() nebo funkce GETDATE() serveru 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()
datetime2 s vysokou přesností
Pro časová razítka s vyšší přesností použijte typ, datetime2 který podporuje přesnost 100 nanosekund:
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()
Získat hodnoty datového času
Načíst datum a čas
Při načítání hodnot data a času ze serveru SQL Server jsou tyto hodnoty automaticky převáděny na objekty datetime v Pythonu:
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
Přístup k datetime komponentám
Python datetime objekty poskytují atributy pro přístup k jednotlivým datovým a časovým komponentám:
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)
Časová pásma
Datumy a časy s posunem a bez posunu
Python datetime objekty jsou buď offsetově citlivé (mají tzinfo), nebo offset-naivní (bez informací o časovém pásmu). SQL Server má oba typy sloupců:
| Typ SQL Serveru | Očekává | Ukládá časové pásmo? |
|---|---|---|
| Datetime, datetime2, smalldatetime | Offset-naivní | Ne |
| datetimeoffset | Se zohledněním posunu | Yes |
Odeslání datového času podle časového pásma do sloupce datetime2 funguje, ale informace o časovém pásmu jsou tiše vyhozeny. Odeslání naivního datového času do sloupce datetimeoffset přiřadí UTC (+00:00) jako posun. Buďte jasní ohledně toho, jaký typ posíláte:
Následující příklad ukazuje, jak vytvářet a používat časové časy naivní a offsetově citlivé na posuny:
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()
Pro převod mezi oběma:
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)
Typ datetimeoffset
SQL Server ukládá datetimeoffset informace o časových pásmech. Následující příklad ukazuje vkládání a získávání datových časů podle časových pásem:
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
Převod mezi časovými pásmy
Použijte metody časových pásem v Python pro převod hodnot datetimeoffset mezi různými reprezentacemi časových pásem:
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 v SQL
Klauzule AT TIME ZONE SQL Server převádí hodnoty datetimeoffset mezi časovými pásmy v rámci dotazu:
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}")
Datová aritmetika
Vypočítejte rozdíly v datech
Počet dní mezi dvěma daty vypočítejte odečtením objektů datového času:
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")
Přidávat intervaly
Použijte timedelta k přičtení nebo odečtení dnů, měsíců nebo jiných intervalů od data času:
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 v SQL
Funkce DATEADD SQL Server provádí datovou aritmetiku přímo v dotazech:
# Use SQL Server date functions
cursor.execute("""
SELECT
OrderDate,
DATEADD(day, 30, OrderDate) AS DueDate,
DATEADD(month, 1, OrderDate) AS NextMonth
FROM Sales.SalesOrderHeader
""")
Formátování hodnot
Formát zobrazení
Formátujte hodnoty datového času pro zobrazení pomocí strftime() specifikátorů formátu:
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
Parsování ze řetězců
Převádějte řetězcové reprezentace na objekty datetime v Pythonu pomocí strptime():
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()
Formát ISO 8601
Formát ISO 8601 je užitečný pro API a serializaci JSON. Použití isoformat() a fromisoformat() pro konverzi:
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")
Obvyklé scénáře
Dotaz podle datového rozpětí
Dotazujte záznamy v rámci konkrétního datového rozmezí parametrizací začátku a konce:
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})
Vyhledat dnešní záznamy
Načtěte záznamy vytvořené dnes tak, že sloupec typu datetime převedete na datum a porovnáte ho s dnešním datem:
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)
""")
Řešení NULL dat
Před zpracováním sloupců datetime zkontrolujte hodnotyNone, protože NULL data se objevují jako None v 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")
Uložit časová razítka auditu
Vytvořte auditní sloupce pro sledování, kdy jsou záznamy vytvářeny a upravovány:
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
})
Specifické scénáře
Datování před rokem 1753
Použití datetime2 pro historická data ( datetime typ podporuje pouze data od roku 1753). Následující příklad vkládá historické datum:
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()
Pouze časové hodnoty
Ukládejte hodnoty času dne pomocí objektu 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()
Výpočet pracovních dnů
Pomocná funkce může počítat intervaly dat a přeskočit víkendy:
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)