Python使用pymssql读取SQL Server日期列返回十六进制值问题
问题根因
你库中trnDate列是SQL Server的datetimeoffset类型(从存储值带+04:00时区偏移就能判断),低版本pymssql没有内置对该类型的自动转换逻辑,会直接返回数据库传输的原始二进制字节串。
你之前尝试的加charset参数、pandas端设置parse_dates都没用:前者只解决字符编码问题,和二进制日期类型无关;后者拿到的已经是字节串,根本匹配不到日期字符串格式,自然解析失败。其余列读取正常,是因为那些列的类型都在pymssql默认支持的转换范围内。
可行解决方案
按操作成本从低到高排序:
- 方案一:查询时显式转换列类型(无需升级、无需额外写转换逻辑,推荐优先用)
不要直接用select *,在SQL语句里把datetimeoffset类型的trnDate转成pymssql能识别的datetime2类型即可,示例代码:
如果需要保留原列的时区信息,可以把列转成ISO格式字符串再交给pandas解析,把上面SQL里的CAST部分换成import pymssql import pandas as pd conn = pymssql.connect(server, user, password, "HecPoll5") query_sql = """ SELECT TID, Number, CAST(trnDate AS datetime2) AS trnDate, LiveMandatorID, Quantity, CustomerID FROM dbo.v_beeah_data WHERE customerid=379691 """ df = pd.read_sql_query(query_sql, conn)CONVERT(VARCHAR, trnDate, 127) AS trnDate,再给read_sql_query加parse_dates=['trnDate']参数即可。 - 方案二:升级pymssql到最新版本
新版pymssql已经补上了datetimeoffset类型的自动解析支持,升级后原代码不用任何修改就能正常读取日期。升级命令:pip install --upgrade pymssql - 方案三:读取后手动转换二进制值
既不想改SQL也不想升级驱动的话,可以拿到DataFrame后按SQL Serverdatetimeoffset的二进制存储结构手动解析,代码如下:from datetime import datetime, timedelta, timezone def parse_datetimeoffset(raw_bytes): time_ticks = int.from_bytes(raw_bytes[:8], byteorder="little") offset_min = int.from_bytes(raw_bytes[8:10], byteorder="little", signed=True) dt = datetime(1, 1, 1) + timedelta(microseconds=time_ticks // 10) return dt.replace(tzinfo=timezone(timedelta(minutes=offset_min))) df["trnDate"] = df["trnDate"].apply(parse_datetimeoffset)
内容的提问来源于stack exchange,提问作者ALIHABIB.IN
相关产品推荐
相关产品推荐

