【问题标题】:Get date 'hours ago' from now从现在开始获取“几小时前”的日期
【发布时间】:2021-07-31 11:54:55
【问题描述】:

我想知道从现在开始的确切日期。我有一个如下所示的输入数据框。年龄列是日期的差异。

我想获得显示的输出数据框。它是按日期 = 当前日期 - 差异(AGE 数据)计算的日期。

有什么办法吗?

输入:

          AGE
0 '1 years 2 days ago'
1 '3 hours 4 mins ago'
2 '5 mins 6 secs ago'
     ...

输出:

        DATE
0 2020-07-29 20:00
1 2021-07-31 16:57
2 2021-07-31 19:55

【问题讨论】:

  • 尝试将您的输入转换为timedelta 实例,然后从 datetime.now() 对象中减去 timedelta。

标签: python date


【解决方案1】:

由于您的字符串非常简单,您可以使用dateparser 而不是实现自己的解析器。它会自动将您的字符串转换为日期时间对象。

然后您可以使用strftime 以您选择的格式打印日期时间对象。

例如:

import dateparser
timestrings = ['1 years 2 days ago' ,'3 hours 4 mins ago','5 mins 6 secs ago']

for timestring in timestrings:
    dt = dateparser.parse(timestring)
    print(dt.strftime("%Y-%m-%d %H:%M"))

输出:

2020-07-29 22:33
2021-07-31 19:29
2021-07-31 22:28

【讨论】:

  • 这是一个聪明的解决方案!但它有一个问题:如果您设置df = pd.DataFrame({'AGE': ["59 secs ago"] * 100}),然后查看df.AGE.map(dateparser.parse),您会注意到您得到的日期略有不同。这是由于基准日期(在这种情况下为时间)的变化。我浏览了 dateparser 文档,但找不到配置基础的方法。你知道修复吗? (也许在 op 感兴趣的用例中并不重要。)
  • @Timus 我认为这是一个功能:如果您正在处理相对时间,通常它是相对于现在的。无论如何,在docs 中有一个标志可以做到这一点。只需传递一个 datetime 对象作为基准时间,问题就解决了。试试df.AGE.apply(dateparser.parse, settings={"RELATIVE_BASE" : reference}),其中引用是一个日期时间对象。
  • 我知道它主要是一个功能,但在这种情况下可能不是 :)) (dateparser 相当慢 - 可以理解,因为它检查的可能性比这里的要多得多 - 所以根据数据的大小,这确实可能是一个问题。)很高兴知道可以修改行为。
【解决方案2】:

我能想到的最简单的方法是使用时间增量从当前时间中减去您的时间(如 here 所述)。

这是一个简单的例子:

from datetime import timedelta, datetime
t1 = timedelta(days = 1, hours=7, minutes=36, seconds=20)
print(datetime.now()-t1)

不幸的是,由于闰年之类的因素,当您添加年份时,事情会变得更加复杂。

Tom Scott 的This computerphile video 详细解释了您在处理时间时可能遇到的问题。

This 堆栈溢出问题解释了如何仍然可以实现。

【讨论】:

    【解决方案3】:

    编辑:另一个包含月份的版本:

    import re
    import pandas as pd
    
    units = ("sec", "min", "hour", "day", "week", "month", "year")
    re_offset = re.compile("|".join(r"\d+\s*" + f"{unit}s?" for unit in units))
    re_num_unit = re.compile(r"(\d+)\s*(\w+)")
    
    def offset(s):
        keys = {
            "sec": "seconds", "secs": "seconds",
            "min": "minutes", "mins": "minutes",
            "hour": "hours", "day": "days", "week": "weeks",
            "month": "months", "year": "years"
        }
    
        values = {}
        for num_unit in re_offset.findall(s):
            num_str, unit = re_num_unit.match(num_unit).groups()
            unit = keys.get(unit, unit)
            values[unit] = int(num_str)
    
        return pd.DateOffset(**values)
    
    df["DATE"] = (dt.datetime.now() - df.AGE.apply(offset)).dt.strftime("%Y-%m-%d %H:%M")
    

    如果字符串表现得非常好,则更短:

    def offset(lst):
        keys = {
            "sec": "seconds", "secs": "seconds",
            "min": "minutes", "mins": "minutes",
            "hour": "hours", "day": "days", "week": "weeks",
            "month": "months", "year": "years"
        }
        return pd.DateOffset(
            **{keys.get(unit, unit): int(num_str) for num_str, unit in lst}
        )
    
    df["DATE"] = (dt.datetime.now()
                  - df.AGE.str.findall(r"(\d+)\s*(\w+)")
                          .map(offset)).dt.strftime("%Y-%m-%d %H:%M")
    

    旧版本:

    import re
    import datetime as dt
    
    units = ("sec", "min", "hour", "day", "week", "year")
    re_timedelta = re.compile("|".join(r"\d+\s*" + f"{unit}s?" for unit in units))
    re_num_unit = re.compile(r"(\d+)\s*(\w+)")
    
    def ago(s, now):
        keys = {
            "sec": "seconds", "secs": "seconds",
            "min": "minutes", "mins": "minutes",
            "hour": "hours", "day": "days", "week": "weeks", "year": "years"
        }
        values = {"seconds": 0, "minutes": 0, "hours": 0, "days": 0, "weeks": 0}
        
        for num_unit in re_timedelta.findall(s):
            num_str, unit = re_num_unit.match(num_unit).groups()
            unit = keys.get(unit, unit)
            if unit == "years":
                years = int(num_str)
                if now.month == 2 and now.day == 29 and years%4:
                    ago_date = dt.date(now.year - years, 3, 1)
                else:
                    ago_date = dt.date(now.year - years, now.month, now.day)
                values["days"] += (now.date() - ago_date).days
            else:
                values[unit] += int(num_str)
        
        return (now - dt.timedelta(**values)).strftime("%Y-%m-%d %H:%M")
    

    有了这些准备,你可以做(​​df你的数据框):

    now = dt.datetime.now()
    df["DATE"] = df.AGE.apply(ago, args=[now])
    

    结果:

                      AGE              DATE
    0  1 years 2 days ago  2020-07-29 17:51
    1  3 hours 4 mins ago  2021-07-31 14:47
    2   5 mins 6 secs ago  2021-07-31 17:46
    

    【讨论】:

      【解决方案4】:

      可以做类似的事情,我们可以使用 date 模块来获取确切的日期和时间并将其与输入进行比较。代码如下:

      from datetime import datetime
      
      #Get the current year (I will make a simpler version, only with the year, it will be the same idea for days, months, etc.)
      currentYear = datetime.now().strftime("%Y")
      
      #Input the year to be substracted
      secondYear = int(input("What is the year to be substracted?"))
      
      #We will use the int() function on the currentYear variable because normally it is a string type var
      #Substract the two years
      print(int(currentYear) - secondYear)
      

      我希望您能理解我的意思,我使用了一个更简单的示例来向您展示它是如何完成的。您可以在其他日期使用相同的技巧。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 2016-10-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多