【问题标题】:Adding time/duration from CSV file从 CSV 文件添加时间/持续时间
【发布时间】:2015-08-31 09:06:24
【问题描述】:

我正在尝试从我拥有的 CSV 文件中添加时间/持续时间值,但到目前为止我失败了。这是我要添加的示例 csv。

可以得到这个输出吗?

输出:

我一直在尝试添加日期时间,但总是失败:

finput = open("./Test.csv", "r")
while 1:
  line = finput.readline()
  if not line:
    break
  else:
    user = line.split(delim)[0]
    direction = line.split(delim)[1]
    duration = line.split(delim)[2]

    durationz = 0:00:00
    for k in duration:
      durationz += k

还有: 有没有特定的方法来声明时间值?

【问题讨论】:

  • 那不是真正的日期时间;这些是持续时间
  • 澄清一下:您使用的是表示时间的字符串,而不是 datetime 对象。但是,datetime 对象在这里会很好。
  • @MartijnPieters 哦,对了。我将编辑标题。对不起
  • “方向”是什么意思?看起来您只是将数字相加,与考勤卡上的“进/出”时间无关(这是模糊的样子)。
  • @TigerhawkT3 我正在尝试模拟呼叫中心类型的日志,其中的方向是拨出或拨入电话。

标签: python python-2.7 csv datetime


【解决方案1】:

您可以解决一些问题。

首先,您可以通过 for line in file 读取文件中的每一行。

您不能将变量 durationz 声明为 0:00:00。它在 python 中根本不起作用。

您可以做的一件事是将 durationz 设为 0,然后通过将其转换为秒数来解析时间。一些伪代码:

split duration string by ":"
add 60 * 60 * hours to duration
add 60 * minutes to duration
add seconds to duration

【讨论】:

    【解决方案2】:

    使用datetime.timedelta() 对象对持续时间进行建模,并以秒、分钟和小时的形式传入 3 个组件。

    使用csv module 解析您的文件;在这里重新发明字符分隔值解析轮没有意义。

    使用字典跟踪每个用户的 InOut 值;使用collections.defaultdict() object 可以更轻松地添加新用户:

    from collections import defaultdict
    from datetime import timedelta
    import csv
    
    durations = defaultdict(lambda: {'In': timedelta(), 'Out': timedelta()})
    
    with open("./Test.csv", "rb") as inf:
        reader = csv.reader(inf, delimiter=delim)
        for name, direction, duration in reader:
            hours, minutes, seconds = map(int, duration.split(':'))
            duration = timedelta(hours=hours, minutes=minutes, seconds=seconds)
            durations[name][direction] += duration
    
    for name, directions in durations.items():
        print '{:10} In    {}'.format(name, directions['In'])
        print '           Out   {}'.format(directions['Out'])
        print '           Total {}'.format(
            directions['In'] + directions['Out'])
    

    timedelta() 对象,在转换回字符串时(例如在打印或使用str.format() 格式化时再次转换为h:mm:ss 格式。

    演示:

    >>> import csv
    >>> from collections import defaultdict
    >>> from datetime import timedelta
    >>> sample = '''\
    ... Johnny,In,0:02:36
    ... Kate,Out,0:02:15
    ... Paul,In,0:03:57
    ... Chris,In,0:01:26
    ... Jonathan,In,0:00:37
    ... Kyle,In,0:06:46
    ... Armand,Out,0:00:22
    ... Ryan,In,0:00:51
    ... Jonathan,Out,0:12:19
    ... '''.splitlines()
    >>> durations = defaultdict(lambda: {'In': timedelta(), 'Out': timedelta()})
    >>> reader = csv.reader(sample)
    >>> for name, direction, duration in reader:
    ...     hours, minutes, seconds = map(int, duration.split(':'))
    ...     duration = timedelta(hours=hours, minutes=minutes, seconds=seconds)
    ...     durations[name][direction] += duration
    ... 
    >>> for name, directions in durations.items():
    ...     print '{:10} In    {}'.format(name, directions['In'])
    ...     print '           Out   {}'.format(directions['Out'])
    ...     print '           Total {}'.format(
    ...         directions['In'] + directions['Out'])
    ... 
    Johnny     In    0:02:36
               Out   0:00:00
               Total 0:02:36
    Kyle       In    0:06:46
               Out   0:00:00
               Total 0:06:46
    Ryan       In    0:00:51
               Out   0:00:00
               Total 0:00:51
    Chris      In    0:01:26
               Out   0:00:00
               Total 0:01:26
    Paul       In    0:03:57
               Out   0:00:00
               Total 0:03:57
    Jonathan   In    0:00:37
               Out   0:12:19
               Total 0:12:56
    Kate       In    0:00:00
               Out   0:02:15
               Total 0:02:15
    Armand     In    0:00:00
               Out   0:00:22
               Total 0:00:22
    

    【讨论】:

    • 谢谢您,先生!这非常有效!现在我正在为每个用户添加一个进出计数。再次感谢!这帮了大忙!
    【解决方案3】:

    首先,您可能会发现 python 的内置 csv 模块很有帮助。无需手动拆分行和分配数据,您只需执行以下操作:

    import csv
    with open("test.csv", mode="r") as f:
        reader = csv.reader(f)
        for row in reader:
            user, direction, duration = row  # this is equivalent to your own variable assignment code, 
                                             # using a cool feature of python called tuple unpacking
    

    字典是按用户对数据进行分组的好方法。这可能是这样的:

    ...
    user_dict = {}
    for row in reader:
        user, direction, duration = row
        user_dict[user] = user_dict.get(user, default={"in": "0:00:00", "out": "0:00:00"})
        user_dict[user][direction] = duration
    

    一旦遍历整个输入 csv,您应该有一个字典,其中包含每个用户的条目,每个用户条目都包含各自的“输入”和“输出”值。如果它们在 csv 中缺少输入或输出值,则已使用 dictionary.get() 语句的“默认”参数将其设置为“0:00:00”。

    我们可以手动解析时间,但自己处理时间加法将是一个巨大的痛苦。幸运的是,python 有一个用于处理时间的内置模块,称为 datetime。

    import csv
    import datetime
    
    user_dict = {}
    with open("test.csv", mode="r") as f:
        reader = csv.reader(f)
        for row in reader:
            user, direction, duration = row
            hour, minute, second = duration.split(":")
    
            # since the split left us with strings, and datetime needs integers, we'll need to cast everything to an int.
            hour = int(hour)
            minute = int(minute)
            second = int(second)
    
            # (we could have done the above more concisely using a list comprehension, which would look like this:
            # hour, minute, second = [int(time) for time in duration.split(":")]
    
            # to add time values we'll use the timedelta function in datetime, which takes days then seconds as its arguments. 
            # We'll just use seconds, so we'll need to convert the hours and minutes first.
            seconds = second + minute*60 + hour*60*60
    
            duration = datetime.timedelta(0, seconds)
    
            user_dict[user] = user_dict.get(user, default={"in": datetime.timedelta(0,0), "out": datetime.timedelta(0,0)})
            user_dict[user][direction] = duration
    

    查看您的示例,我们只是将输入时间添加到输出时间(尽管如果我们想要时钟上的总时间,我们希望从输出时间中减去输入时间)。我们可以通过以下方式进行加法部分:

    output = []
    for user, time_dict in user_dict.items():
        total = time_dict["in"] + time_dict["out"]
        output.append([user, time_dict["in"], time_dict["out"], total])
    
    with open("output.csv", mode="w") as f:
        writer = csv.writer(f)
        writer.writerows(output)
    

    这应该可以满足您的需求,尽管每个用户的输出将是一行 - 数据将水平显示而不是垂直显示。

    所有代码放在一起:

    import csv
    import datetime
    
    user_dict = {}
    with open("test.csv", mode="r") as f:
        reader = csv.reader(f)
        for row in reader:
            user, direction, duration = row
            hour, minute, second = [int(time) for time in duration.split(":")]
            seconds = second + minute*60 + hour*60*60
            duration = datetime.timedelta(0, seconds)
    
            user_dict[user] = user_dict.get(user, default={"in": datetime.timedelta(0,0), "out": datetime.timedelta(0,0)})
            user_dict[user][direction] = duration
    
    output = []
    for user, time_dict in user_dict.items():
        total = time_dict["in"] + time_dict["out"]
        output.append([user, time_dict["in"], time_dict["out"], total])
    
    with open("output.csv", mode="w") as f:
        writer = csv.writer(f)
        header = ["name", "time in", "time out", "total time"]
        writer.writerow(header)
        writer.writerows(output)
    

    【讨论】:

    • 我很抱歉超级迟回复。我收到此错误:TypeError:+:'datetime.time' 和'datetime.time' 不支持的操作数类型。我不认为time 支持减法。
    • 该死,你是对的!我只是假设它确实如此。您必须改用 datetime.timedelta 。输入需要几天然后几秒,因此您必须将小时和分钟转换为秒,但这应该是可行的。我可能会编辑主要帖子以反映这一点。
    • 谢谢您,先生!我现在正在尝试计算 csv 中名称的出现次数。再次感谢!
    猜你喜欢
    • 2019-10-24
    • 2015-12-25
    • 2021-05-28
    • 2021-06-21
    • 2016-02-23
    • 2011-01-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多