mssql-pythonドライバはSQL Serverの日付と時刻型を処理し、それらをPythonのdatetimeモジュールオブジェクトにマッピングします。 SQL Serverは、精度や機能に異なる複数の日付と時刻タイプを提供します:
| SQL 型 | Python 型 | 範囲 | 精度 |
|---|---|---|---|
| date | datetime.date |
0001-01-01から9999-12-31まで | 1 日 |
| time | datetime.time |
00:00:00.0000000 から 23:59:59.9999999 | 100 ナノ秒 |
| datetime | datetime.datetime |
1753年1月1日から9999年12月31日まで | 3.33ミリ秒 |
| datetime2 | datetime.datetime |
0001-01-01から9999-12-31まで | 100 ナノ秒 |
| smalldatetime | datetime.datetime |
1900年1月1日から2079年6月6日まで | 1 分 |
| datetimeoffset |
datetime.datetime(tzinfo付き) |
0001-01-01から9999-12-31まで | 100ナノ秒+タイムゾーン |
datetimeの値を挿入してください
Pythonのdatetimeオブジェクトを使います
以下の例は、Pythonのdatetimeモジュールを使って異なる日付と時刻タイプをSQL Serverに挿入します。
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()
現在のタイムスタンプを挿入してください
現在の日付と時間をdatetime.now()またはSQL ServerのGETDATE()関数で入力できます:
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()
高精度日付時間2
高精度のタイムスタンプには、100ナノ秒の精度をサポートする datetime2 タイプを使用してください。
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()
datetimeの値を取得する
日付と時刻を取得する
SQL Serverからdatetimeの値を取得すると、それらは自動的にPython datetimeオブジェクトに変換されます:
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
datetimeコンポーネントへのアクセス
Pythonのdatetimeオブジェクトは、個々の日付と時刻コンポーネントにアクセスするための属性を提供します:
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)
タイム ゾーン
オフセット対応日時とオフセットなし日時
Python datetimeオブジェクトはオフセット認識(tzinfoを持つ)かオフセット未認識(タイムゾーン情報なし)のいずれかです。 SQL Serverには両方の種類の列があります:
| SQL Server の種類 | 予期する | 店舗のタイムゾーンは? |
|---|---|---|
| デートタイム、 デートタイム2、 スモールデイトタイム | オフセット・ナイーブ | いいえ |
| datetimeoffset | オフセット認識 | イエス |
タイムゾーン認識の日付時刻を datetime2 列に送信することは可能ですが、タイムゾーン情報は静かにドロップされます。
datetimeoffset列にナイーブな日付時刻を送ると、UTC(+00:00)がオフセットとして割り当てられます。 どの種類を送るかを明確にしましょう:
以下の例は、オフセット未認識かつオフセット認識のdatetimeの作成方法と使用方法を示しています:
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()
両者間の変換方法:
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)
DateTimeOffsetタイプ
SQL Serverdatetimeoffsetタイムゾーン情報を保存しています。 以下の例は、タイムゾーン認識の日付時間の挿入と取得を示しています:
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
タイムゾーン間の変換
Pythonのタイムゾーンメソッドを使って、異なるタイムゾーン表現間でdatetimeoffsetの値を変換してください:
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)
SQLにおけるAT TIME ZONE
SQL ServerのAT TIME ZONE節は、クエリ内のタイムゾーン間でdatetimeoffsetの値を変換します:
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}")
日付演算
日付の違いを計算する
2つの日付間の日数を、datetimeオブジェクトを差し引いて計算します:
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")
区間を足す
timedeltaを使って日付の日、月、その他の区間を追加・減算します:
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()
SQLにおけるDATEADD
SQL Serverの DATEADD 関数はクエリで日付演算を直接行います:
# Use SQL Server date functions
cursor.execute("""
SELECT
OrderDate,
DATEADD(day, 30, OrderDate) AS DueDate,
DATEADD(month, 1, OrderDate) AS NextMonth
FROM Sales.SalesOrderHeader
""")
値の書式設定
表示フォーマット
strftime() を使用して、書式指定子で表示用の日時値を書式設定します:
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
文字列からの解析
文字列表現をPython datetimeオブジェクトに変換するには、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()
ISO 8601 形式です。
ISO 8601形式はAPIやJSONのシリアライズに有用です。 変換には isoformat() と fromisoformat() を使います:
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")
一般的なパターン
日付範囲によるクエリ
開始日と終了日をパラメータ化して特定の日付範囲内のレコードを照会します:
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})
本日の記録を検索
datetime列を日付にキャストし、今日の日付と比較して今日作成したクエリ記録:
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)
""")
NULL日付の処理
NULL日付はPythonNoneとして表示されるため、datetime列を処理する前に値Noneを確認してください。
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")
監査タイムスタンプを保存
レコードの作成および変更を追跡するための監査列を作成する:
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
})
具体的なシナリオ
1753年以前の日付
歴史的な日付には datetime2 を使いましょう( datetime タイプは1753年以降のみ対応しています)。 以下の例では歴史的な日付が挿入されています。
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()
時間のみの価値
Pythonのtimeオブジェクトを使って時間帯の値を保存します:
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()
営業日の計算
ヘルパー機能により、週末をスキップしながら日付間隔を計算できます:
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)