【问题标题】:How do I handle "Object of type 'Timestamp' is not JSON serializable" in Python / Pandas?如何在 Python / Pandas 中处理“'Timestamp' 类型的对象不是 JSON 可序列化的”?
【发布时间】:2018-03-12 20:16:11
【问题描述】:

前言:Python 新手,感谢 SO 的帮助!

下面是一个代码 sn-p,我在其中尝试对 MSSQL 服务器表执行 SQL 查询,并将其发布回 Google 表格。我能够检索数据和标题,我想我几乎已经弄清楚了。但是,我在某些列的日期时间格式上遇到了一些问题。我收到的错误是:

Traceback (most recent call last):
  File "modelhome.py", line 153, in <module>
    valueInputOption=value_input_option, insertDataOption=insert_data_option, body=value_range_body)
  File "C:\ProgramData\Anaconda3\lib\site-packages\googleapiclient\discovery.py", line 785, in method
    actual_path_params, actual_query_params, body_value)
  File "C:\ProgramData\Anaconda3\lib\site-packages\googleapiclient\model.py", line 151, in request
    body_value = self.serialize(body_value)
  File "C:\ProgramData\Anaconda3\lib\site-packages\googleapiclient\model.py", line 260, in serialize
    return json.dumps(body_value)
  File "C:\ProgramData\Anaconda3\lib\json\__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "C:\ProgramData\Anaconda3\lib\json\encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "C:\ProgramData\Anaconda3\lib\json\encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "C:\ProgramData\Anaconda3\lib\json\encoder.py", line 180, in default
    o.__class__.__name__)
TypeError: Object of type 'Timestamp' is not JSON serializable

代码片段

"""Execute SQL Statement, create table, and append back to Google Sheet"""
# SQL Server Connection
server = '[SQLServerIP]'
database = '[SQLServerDatabase]'
username = '[SQLServerUsername]'
password = '[SQLServerPassword]'
cnxn = pyodbc.connect('Driver={ODBC Driver 13 for SQL Server};SERVER=' +
                      server+';DATABASE='+database+';UID='+username+';PWD='+password)

# Sample SQL Query to get Data
sql = 'select * from tblName'
cursor = cnxn.cursor()
cursor.execute(sql)
list(cursor.fetchall())

# Pandas reading values from SQL query, and building table
sqlData = pandas.read_sql_query(sql, cnxn)

# Pandas building dataframe, and exporting .xlsx copy of table
df = DataFrame(data=sqlData)

df.to_excel('tblName.xlsx',
            header=True, index=False)
dfHeaders = df.columns.values.tolist()
dfHeadersArray = [dfHeaders]
dfData = df.values.tolist()
dfDataFormatted = [dfData]
"""Writing to Google Sheet Range"""
print(dfHeaders)
print(dfData)

# How the input data should be interpreted.
value_input_option = 'USER_ENTERED'  # TODO: Update placeholder value.

# How the input data should be inserted.
insert_data_option = 'OVERWRITE'  # TODO: Update placeholder value.

value_range_body = {
    "majorDimension": "ROWS",
    "values":
    dfHeadersArray + dfDataFormatted
}

request = service.spreadsheets().values().append(spreadsheetId=spreadsheetId, range=SQLRangeName,
                                                 valueInputOption=value_input_option, insertDataOption=insert_data_option, body=value_range_body)
response = request.execute()

dfData 内,普通字符串如下所示:

datettime 条目如下所示:

我的理解是 JSON 没有原生的方式来处理这种数据类型,它必须作为一个异常来处理。有没有一种方法可以序列化数据集的所有时间戳部分,而无需指定哪些列是日期时间?

如果您能提供任何帮助/建议,我们将不胜感激。

谢谢!

最终解决方案更新 - 图片来源:@chrisheinze

为 datettime 标头添加以下数据框建模效果很好。

# Pandas reading values from SQL query, and building table
sqlData = pandas.read_sql_query(sql, cnxn)

# Pandas building dataframe, and exporting .xlsx copy of table
df = DataFrame(data=sqlData)

# Google Sheets API can't handle date/time. Below converts certain headers to formatted text strings.
df['Date'] = df['Date'].dt.strftime('%m/%d/%Y')
df['DateTime'] = df['DateTime'].dt.strftime('%m/%d/%Y %H:%M:%S')
df['RDD'] = df['RDD'].dt.strftime('%m/%d/%Y')
df['DateTimeErrorTable'] = df['DateTimeErrorTable'].dt.strftime('%m/%d/%Y %H:%M:%S')
df['DateTimeSuccessTable'] = df['DateTimeSuccessTable'].dt.strftime('%m/%d/%Y %H:%M:%S')
df['WorkedOn'] = df['WorkedOn'].dt.strftime('%m/%d/%Y %H:%M:%S')
df['EmailSentOn'] = df['EmailSentOn'].dt.strftime('%m/%d/%Y %H:%M:%S')

希望对其他人有所帮助!

【问题讨论】:

    标签: python pandas pyodbc google-sheets-api google-api-python-client


    【解决方案1】:

    Sheets API 不知道如何处理 Python 日期时间/时间戳。您需要将其转换 - 最有可能转换为 str。

    要转换熊猫系列,请使用pd.Series.dt.strftime()

    如果只是需要转换的单个值,则使用日期时间的strftime()

    编辑以在 cmets 中回答您的问题:

    # To convert a datetime column to a str. 
    
    df['date_column'] = df['date_column'].dt.strftime('%Y%m%d%H%M%S')
    

    为了提供更多信息,strftime 表示“字符串格式日期时间”。这允许您将日期时间/时间戳值格式化为 str。 '%Y%m%d%H%M%S' 是您想要的输出。在我的示例中,您的日期的结果将是“20180309152303”。另一个例子是'%m/%d/%Y %H:%M:%S',它会给你“03/09/2018 15:23:03”。因此,将我示例中的“date_column”替换为您的日期列的名称,它将被转换为与 API 兼容并且在 Google 表格中以格式理解的 str。

    【讨论】:

    • 嘿@Chrisheinze,感谢您的回复!我想我明白你在说什么,但我不确定如何将dfDatadfsqlData 传递到其中?变量会去哪里?
    • @swolfe2 我更新了我的答案以更深入地了解。如果还不完全清楚,请告诉我!
    • 嘿@Chrisheinze,抱歉耽搁了;你回复的时候我已经下班了。我是否需要为日期时间的每一列做一个单独的行,或者有没有办法在其中放置多个?再次感谢!
    • 我明白了!我已经用我的代码中的最终解决方案更新了 OP,以防有人遇到同样的问题。谢谢!
    • 我正在尝试将我的熊猫框架的日期/时间列添加到谷歌表格。但它不喜欢它以任何方式、形状或形式。我序列化了,它仍然不接受它。它说它已更新,但谷歌表上仍然没有任何内容。有什么建议吗?我直接从 json 数据、列表和熊猫框架中尝试过,但它不工作
    【解决方案2】:

    如果您无法分辨哪一列是日期,请使用此功能:

    import numpy as np
    
    def cast_for_gsheets(df):
        # casting as string if not serializable
        for column, dt in zip(df.columns, df.dtypes):
            if dt.type not in [
                np.int64,
                np.float_,
                np.bool_,
            ]:
                df.loc[:, column] = df[column].astype(str)
        return df
    
    df = cast_for_gsheets(DataFrame(data=sqlData))
    

    【讨论】:

      猜你喜欢
      • 2018-10-28
      • 2021-01-31
      • 1970-01-01
      • 2021-11-05
      • 2021-04-29
      • 2018-11-27
      • 2019-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多