python UTC日期和sqlalchemy

Posted

技术标签:

【中文标题】python UTC日期和sqlalchemy【英文标题】:python utc dates and sqlalchemy 【发布时间】:2021-10-08 16:56:35 【问题描述】:

我的目标是从 pandas 数据框中获取数据并插入 SQL 数据库。但是,我在时间和 UTC 方面遇到了一些问题。我将其分解为 3 个场景,从下面的代码中只需取消注释为每个场景标记的相关代码行。

场景 1,在 pandas 中将日期转换为日期/时间(非 UTC),然后插入到 sql 中,我收到以下错误消息:

"发生异常:ValueError Tz-aware datetime.datetime 不能 转换为 datetime64 除非 utc=True 文件 “/home/tbgiot04/OEE_forge/OEE_module/test_sql.py”,第 34 行,在 df.to_sql("test_table", engn, if_exists='replace')"

utc=True 的场景 2 我收到以下错误,导致未插入数据。

发生异常:ProgrammingError (pyodbc.ProgrammingError) ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]一张表只能有一个时间戳列。因为表 'test_table' 已经有一个,不能添加列 'end_date'。 (2738)(SQLExecDirectW)“)[SQL:创建表test_table([索引] BIGINT NULL,employee_no BIGINT NULL,start_date TIMESTAMP NULL, end_date TIMESTAMP NULL )

](此错误的背景:http://sqlalche.me/e/13/f405)文件 “/home/tbgiot04/OEE_forge/OEE_module/test_sql.py”,第 37 行,在 df.to_sql("test_table", engn, if_exists='replace')

场景 3,我有 utc = True 行和 dt.tz_localize 行。 pandas/SQL alchemy 发送数据但时间不正确。 pandas DataFrame 和 SQL 数据显示相同,但​​与源代码中的代码不匹配。如何正确地将这些数据插入 SQL 数据库?

   employee_no          start_date            end_date
0            1 2019-12-05 15:55:47 2019-12-05 15:55:47
1            2 2021-07-13 21:38:39 2021-07-13 21:38:39

.

import pandas as pd
from sqlalchemy import create_engine


AZUREUID = 'tb-test'                                    # Azure SQL database userid
AZUREPWD = 'test'                                # Azure SQL database password
AZURESRV = 'tb-sql01.database.windows.net'   # Azure SQL database server name (fully qualified)
AZUREDB = 'TB-test'                                      # Azure SQL database name (if it does not exit, pandas will create it)
TABLE = 'DataTable'                                      # Azure SQL database table name
#DRIVER = 'ODBC Driver 13 for SQL Server'                 # ODBC Driver
#DRIVER = 'SQL Server Native Client 11.0'                 # ODBC Driver
#DRIVER=/opt/microsoft/msodbcsql17/lib64/libmsodbcsql-17.0.so.1.1

   
connectionstring = 'mssql+pyodbc://uid:password@server:1433/database?driver=driver'.format(
    uid=AZUREUID,
    password=AZUREPWD,
    server=AZURESRV,
    database=AZUREDB,
    driver=DRIVER.replace(' ', '+'))

engn = create_engine(connectionstring)

d = "employee_no" : [1,2], "start_date" : ["2019-12-05 15:55:47 +00:00","2021-07-13 22:38:39 +01:00"] , "end_date" : ["2019-12-05 15:55:47 +00:00","2021-07-13 22:38:39 +01:00"] 
df = pd.DataFrame(data=d)

df["start_date"] = pd.to_datetime(df["start_date"]) # senario 1 
df["end_date"] = pd.to_datetime(df["end_date"])  # senario 1 

#df["start_date"] = pd.to_datetime(df["start_date"], utc=True) # senario 2 and 3 
#df["end_date"] = pd.to_datetime(df["end_date"], utc=True) # senario 2 and 3 

# df["start_date"] = df["start_date"].dt.tz_localize(None)  # senario 3 
# df["end_date"] = df["end_date"].dt.tz_localize(None) # senario 3 

print(df)
df.to_sql("test_table", engn, if_exists='replace')

【问题讨论】:

SQL Server(我怀疑还有 Azure SQL)接受 properly-formatted string literals 的 datetimeoffset 列。虽然通常建议在这种情况下对日期/时间值使用“正确的”日期时间对象,但最好尝试转换字符串,特别是因为它们看起来已经采用格式T-SQL 需要的。 非常感谢您的快速回答。如果我将它们保留为对象,它们将作为 varchar 导入。在 SQL 中使用日期时间功能的最佳方式是什么。我有很多带有日期的列,我只是拿出 2 个作为示例。 在 pandas 中是否可以将 utc 时间转换为 uk 时间? 【参考方案1】:

如果我将它们保留为 [string] 对象,它们将导入为 varchar。

是的,if_exists="replace" 会发生这种情况。但是,我们可以使用dtype= 来指定所需的列类型:

df1 = pd.DataFrame([(1, "2021-07-13 22:38:39 +01:00")], columns=["id", "dto"])
df1.to_sql(
    "dto_test",
    engine,
    index=False,
    if_exists="replace",
    dtype="dto": sqlalchemy.DateTime(timezone=True),
)
df2 = pd.read_sql_table("dto_test", engine)
print(df2)
"""
   id                       dto
0   1 2021-07-13 21:38:39+00:00
"""
dto_value = df2.iloc[0, 1]
print(type(dto_value))  # <class 'pandas._libs.tslibs.timestamps.Timestamp'>
print(repr(dto_value))  # Timestamp('2021-07-13 21:38:39+0000', tz='UTC')

所以看起来 pandas 正在将 datetimeoffset 值标准化为 UTC,但至少它是一个时区感知值。

在 pandas 中是否可以将 utc 时间转换为 uk 时间?

我不确定是否要在 pandas 本身中执行此操作,但 pytz 似乎通常用于那种“本地日期/时间”转换,在这种转换中,标准/夏令时/夏令时转换会变得很奇怪所讨论的具体日期(包括时间“变化”的规则的变化,就像最近在 2007 年在美国发生的那样)。

【讨论】:

再次感谢,当我运行相同的代码时,我得到“pyodbc.DataError: ('22007', '[22007] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]转换失败从字符串转换日期和/或时间时。(241) (SQLExecDirectW)')"。我认为你的工作没有错误? 是的,这是从我的 PyCharm 代码窗口直接复制/粘贴的。 FWIW,我正在使用 pandas 1.3.1、SQLAlchemy 1.4.22、pyodbc 4.0.31、msodbcsql 17.7.2,并访问 SQL Server 2017 Express 实例。

以上是关于python UTC日期和sqlalchemy的主要内容,如果未能解决你的问题,请参考以下文章

在python中获取给定日期和UTC偏移量的GMT时间

Python - 在特定时区设置日期时间(没有 UTC 转换)

Python将字符串转换为本地日期时间到UTC日期时间

在 Python 中使用 tz.localize 将 UTC 日期时间转换为英国日期时间

在python中将日期时间从PDT转换为UTC

Python - 给定一个时区感知的日期时间对象,我如何获得一个时区朴素的 UTC 日期时间对象?