【问题标题】:datetime.strptime issues in working with csv.DictReader使用 csv.DictReader 时的 datetime.strptime 问题
【发布时间】:2020-12-19 21:21:45
【问题描述】:

我有一个 CSV 文件,其中显示了一些获救狗的基本情况,包括它们何时进入救援以及何时被收养。我试图最终在地图上进行可视化,以显示狗从一个区域移动到其他区域的位置。我正在研究的元素之一是特定狗在被收养之前与寄养的时间长度。

这是 CSV 文件的开头。

Name,Status,Sex,Animal_ID,Birthdate,Adopter_City,Adopter_State,Adopter_Zip,Foster_City,Foster_State,Foster_Zip,Created_Date,Adopted_Date,Length
Marnie,Adopted,Female,15598143,2019-03-24,Port Orchard,Wa,98367,Auburn,WA,98002,2020-04-22,2020-07-08
Kendra,Adopted,Female,15598254,2019-12-31,Austin,Tx,78731,Austin ,Tx,78723,2020-04-22,2020-05-01
Hope,Adopted,Female,15598264,2019-10-25,Springfield ,OR,97477,Austin,TX,78737,2020-04-22,2020-05-02
...

我使用 datetime.strptime 来格式化摄入(寄养)和取出(收养)。然后我计算了停留时间=摄入量-摄入量。代码正确计算了长度。

import csv
from datetime import datetime


with open('animals_20200826_12p46.csv', newline = '') as csvfile:
    data = csv.DictReader(csvfile)
   
    for row in data:
        if len(row['Adopted_Date']) < 1 :
            continue
        intake = datetime.strptime(row['Created_Date'], '%Y-%m-%d')
        outtake = datetime.strptime(row['Adopted_Date'], '%Y-%m-%d')
        length = outtake - intake
        row['Length'] = length
        
        print('In:', intake, 'Out:', outtake, 'In foster:', length)

返回结果为:

In: 2020-04-22 00:00:00 Out: 2020-07-08 00:00:00 In foster: 77 days, 0:00:00
In: 2020-04-22 00:00:00 Out: 2020-05-01 00:00:00 In foster: 9 days, 0:00:00
In: 2020-04-22 00:00:00 Out: 2020-05-02 00:00:00 In foster: 10 days, 0:00:00
In: 2020-04-22 00:00:00 Out: 2020-06-01 00:00:00 In foster: 40 days, 0:00:00
...

然后我按照How to update rows in a CSV file 中建议的步骤更新我的 CSV 文件。

import csv
from datetime import datetime
from tempfile import NamedTemporaryFile
import shutil

filename = 'animals_20200826_12p46.csv'
tempfile = NamedTemporaryFile(mode='w', delete=False)

fields = ['Name','Status','Sex','Animal_ID','Birthdate','Adopter_City','Adopter_State','Adopter_Zip','Foster_City','Foster_State','Foster_Zip','Created_Date','Adopted_Date','Length']

with open(filename, 'r') as csvfile, tempfile:
    reader = csv.DictReader(csvfile, fieldnames= fields)
    writer = csv.DictWriter(tempfile, fieldnames=fields)
    for row in reader:
        if len(row['Adopted_Date']) < 1 :  
            continue
        intake = datetime.strptime(row['Created_Date'], '%Y-%m-%d')
        outtake = datetime.strptime(row['Adopted_Date'], '%Y-%m-%d')
        row['Length'] = outtake - intake
        writer.writerow(row)

shutil.move(tempfile.name, filename)

for循环的主要部分是相同的,但现在我遇到了如下回溯错误。

Traceback (most recent call last):
  File "CSV.py", line 18, in <module>
    intake = datetime.strptime(row['Created_Date'], '%Y-%m-%d')
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/_strptime.py", line 568, in _strptime_datetime
    tt, fraction, gmtoff_fraction = _strptime(data_string, format)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/_strptime.py", line 349, in _strptime
    raise ValueError("time data %r does not match format %r" %
ValueError: time data 'Created_Date' does not match format '%Y-%m-%d'

我哪里做错了?有什么比我目前的方法更好的方法呢?

【问题讨论】:

  • 您确定要传递给 strptime 的数据吗?您的第一个示例与第二个示例的主要区别是字段数组。 data['Created_Date'] 实际上不能是具有正确格式的日期。也许您的字段顺序不正确。尝试打印 row['Created_Date'] 以查看 strptime 尝试解析的内容。

标签: python csv datetime


【解决方案1】:

改变这一行:

reader = csv.DictReader(csvfile)

它会正常工作

正如official document 所说:

fieldnames 是一个可选参数。如果 它被省略,文件第一行中的值将用作 字段名。

当您手动确定 fieldnames 每一行时,包括预期为数据行的第一行。

【讨论】:

    【解决方案2】:

    不同之处在于您正在使用的工作示例中

    DictReader(csvfile)
    

    而在您使用的非工作示例中

    DictReader(csvfile, fieldnames=fields)
    

    documentation 说:

    如果省略fieldnames,则文件f的第一行的值将用作fieldnames。

    换句话说,如果fieldnames 被省略,则消耗第一行以确定字段名,否则不会消耗第一行,而是像迭代中的所有其他行一样发出。

    这会将包含列标题的初始行传递给strptime

    我建议您再次为阅读器省略fieldnames 参数。

    【讨论】:

    • 哇,这是一些不那么明显的行为。花了很长时间不明白为什么我的 csv 中的某些日期被解析为“yyyy-mm-dd”以及为什么某些其他日期被完全按原样解析。
    【解决方案3】:

    使用 dateparser.parse 代替 datetime.strptime。

    代码:

    import dateparser
    
    intake = dateparser.parse(row['Created_Date'])
    outtake = dateparser.parse(row['Adopted_Date'])
    

    【讨论】:

    • 谢谢你的提示,我也试试。
    猜你喜欢
    • 1970-01-01
    • 2019-04-01
    • 2013-12-09
    • 2022-06-21
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多