如何通过Python API将Pandas日期时间值传入Smartsheet新行
问题:Pandas写入Smartsheet日期列无法参与公式计算
问题复现步骤
- 读取CSV数据到Pandas DataFrame,空值填充为空字符串:
data_frame = pd.read_csv(EXCEL_FILE) data_frame = data_frame.fillna('')
- CSV中
Created字段原始格式为3/17/2022 10:59:00 AM,读入后显示为3/17/2022 10:59,尝试转换为ISO格式字符串:
data_frame['Created'] = pd.to_datetime(data_frame['Created']).dt.strftime("%Y-%m-%dT%H:00:00Z")
转换后得到值类似2022-03-17T10:00:00Z。
- 循环构造Smartsheet行批量写入:
data_dict = data_frame.to_dict('index') rowsToAdd = [] for i, i in data_dict.items(): new_row = smartsheet_client.models.Row() new_row.to_top = True for k, v in i.items(): new_cell = smartsheet_client.models.Cell() new_cell.column_id = column_map[k] new_cell.object_value = v new_row.cells.append(new_cell) rowsToAdd.append(new_row) result = smartsheet_client.Sheets.add_rows(SHEET_TO_MODIFY, rowsToAdd)
异常表现
- 写入后日期单元格显示为原始ISO字符串
2022-03-17T10:00:00Z,使用公式=TODAY() - [Created Date]@row返回#INVALID OPERATION错误。 - 尝试转换为
%Y-%m-%d格式字符串写入,公式依然报错。 - 手动传入字典格式单元格、指定
strict=False和美式日期字符串时写入正常,但会增加循环逻辑复杂度:
new_row.cells.append({'column_id':7150106886596484,'value':"6/7/2022",'strict':False})
- 已确认目标列为日期类型,原有日期值可正常参与计算;开启列“仅允许输入日期值”限制时脚本直接抛错,新写入单元格旁显示蓝色日历图标,但本质无法参与日期计算。
- 硬编码ISO日期字符串、转换列类型为string、转数组写入、新建空白日期列测试均无法解决问题。
临时解决方案
写入完成后,手动将目标日期列类型从「日期」改为「文本/数字」,再改回「日期」,所有日期会被自动解析为正确格式,公式可正常计算,但需要额外手动操作。
根本原因
- 代码逻辑错误:原代码存在两个低级问题:一是循环变量重名(内外层都用
i做变量名);二是缩进错误,rowsToAdd.append(new_row)和接口调用add_rows写在了单元格遍历的内层循环中,会导致每填充一个单元格就提交一次请求,造成行重复、数据残缺。 - 数据类型不匹配:Smartsheet Python SDK的
object_value参数接收日期类型值时,需要传入原生Python datetime对象,如果传入字符串——哪怕是符合ISO格式的日期字符串——SDK也不会自动做类型解析,会直接以文本格式存储到单元格中。这也是单元格显示日期图标、但无法参与日期公式计算的核心原因。手动切换列类型时Smartsheet会强制批量解析文本为日期,所以临时方案能生效。 - 参数认知偏差:SDK不是不支持
value参数,而是用模型类实例化Cell对象时默认校验属性名,直接传字典格式的单元格配置时,value+strict=False的写法可以正常生效。
修复方案
无需拆分现有循环逻辑,按以下步骤修改即可:
- 修正循环结构:修复变量重名问题,将行追加、批量提交的逻辑移到内层循环外,整行单元格填充完成后再加入待提交列表,所有行构造完成后统一调用接口提交,减少请求次数、避免重复行。
- 日期列禁止转字符串:
pd.to_datetime转换后保留Timestamp类型,写入时转为Python原生datetime对象传给object_value,SDK会自动识别为Smartsheet日期类型,无需手动格式化为ISO或其他格式字符串。 - 若需使用字符串日期自动解析能力,仅需在循环内增加列判断:日期列传入字典格式单元格配置,通过
value传日期字符串、strict=False关闭类型严格校验,其余列保持原有赋值逻辑即可,不会增加过多代码复杂度。
修改后的可运行代码示例:
import pandas as pd # 读取数据,日期列转datetime后禁止转字符串 data_frame = pd.read_csv(EXCEL_FILE) data_frame = data_frame.fillna('') # 转换Created列为datetime类型,保留Timestamp,不要调用strftime data_frame['Created'] = pd.to_datetime(data_frame['Created']) data_dict = data_frame.to_dict('index') rowsToAdd = [] # 修复循环变量重名问题 for idx, row_data in data_dict.items(): new_row = smartsheet_client.models.Row() new_row.to_top = True for col_name, val in row_data.items(): # 日期列转python原生datetime对象 if col_name == 'Created': val = val.to_pydatetime() new_cell = smartsheet_client.models.Cell() new_cell.column_id = column_map[col_name] new_cell.object_value = val new_row.cells.append(new_cell) # 整行填充完成后再加入待提交列表,移至内层循环外 rowsToAdd.append(new_row) # 所有行构造完成后统一提交,移至循环外 result = smartsheet_client.Sheets.add_rows(SHEET_TO_MODIFY, rowsToAdd)
如果倾向于用strict=False的自动解析逻辑,可替换单元格构造部分的代码:
for col_name, val in row_data.items(): if col_name == 'Created': # 日期列传字典配置,开启自动解析 new_cell = { 'column_id': column_map[col_name], 'value': val.strftime("%m/%d/%Y"), # 支持ISO、美式日期等多种格式 'strict': False } else: new_cell = smartsheet_client.models.Cell() new_cell.column_id = column_map[col_name] new_cell.object_value = val new_row.cells.append(new_cell)
内容的提问来源于stack exchange,提问作者jzinna
相关产品推荐
相关产品推荐

