16

我有以以下格式显示日期的字符串:

x minutes/hours/days/months/years ago

我需要使用 python 将其解析为日期时间。

看来 dateutil 做不到。

有没有办法做到这一点?

4

9 回答 9

13

当然你可以做到。你只需要一个timedelta.

s = "3 days ago"
parsed_s = [s.split()[:2]]
time_dict = dict((fmt,float(amount)) for amount,fmt in parsed_s)
dt = datetime.timedelta(**time_dict)
past_time = datetime.datetime.now() - dt

顺便说一句,它看起来像dateutil一个relativedelta时间增量,但构造函数也接受monthsyears在参数中(显然参数需要是整数)。

于 2012-09-24T13:38:35.200 回答
10

Since your arguments are something like 2 days ago, 3 months ago, 2 years ago. The function below could be of help in getting the exact date for the arguments. You first need to import the following date utils

import datetime
from dateutil.relativedelta import relativedelta

Then implement the function below

def get_past_date(str_days_ago):
    TODAY = datetime.date.today()
    splitted = str_days_ago.split()
    if len(splitted) == 1 and splitted[0].lower() == 'today':
        return str(TODAY.isoformat())
    elif len(splitted) == 1 and splitted[0].lower() == 'yesterday':
        date = TODAY - relativedelta(days=1)
        return str(date.isoformat())
    elif splitted[1].lower() in ['hour', 'hours', 'hr', 'hrs', 'h']:
        date = datetime.datetime.now() - relativedelta(hours=int(splitted[0]))
        return str(date.date().isoformat())
    elif splitted[1].lower() in ['day', 'days', 'd']:
        date = TODAY - relativedelta(days=int(splitted[0]))
        return str(date.isoformat())
    elif splitted[1].lower() in ['wk', 'wks', 'week', 'weeks', 'w']:
        date = TODAY - relativedelta(weeks=int(splitted[0]))
        return str(date.isoformat())
    elif splitted[1].lower() in ['mon', 'mons', 'month', 'months', 'm']:
        date = TODAY - relativedelta(months=int(splitted[0]))
        return str(date.isoformat())
    elif splitted[1].lower() in ['yrs', 'yr', 'years', 'year', 'y']:
        date = TODAY - relativedelta(years=int(splitted[0]))
        return str(date.isoformat())
    else:
        return "Wrong Argument format"

You can then call the function like this:

print get_past_date('5 hours ago')
print get_past_date('yesterday')
print get_past_date('3 days ago')
print get_past_date('4 months ago')
print get_past_date('2 years ago')
print get_past_date('today')
于 2017-03-31T11:39:18.670 回答
8

这可以通过timedeltas 轻松完成:

import datetime

def string_to_delta(string_delta):
    value, unit, _ = string_delta.split()
    return datetime.timedelta(**{unit: float(value)})

生产:

>>> string_to_delta("20 hours ago")
datetime.timedelta(0, 72000)

虽然这将需要一些额外的工作来处理月/年 - 因为将一个月添加到日期是一个模棱两可的操作,但如果您知道您想要它的含义,它应该是一个简单的添加。

To get an actual time, simply take the delta away from datetime.datetime.now().

于 2012-09-24T13:39:17.607 回答
3

Easiest way is to use dateparser:

import dateparser
date_ago="4 months ago" 
date=dateparser.parse(date).strftime("%Y-%m-%d")
date

Output:

'2020-01-08'
于 2020-06-08T15:27:44.043 回答
2

@mgilson answer didn't work for me where dateutil.relativedelta did the job:

Edited following @mosc9575 advise

import datetime
from dateutil.relativedelta import relativedelta

time_ago = "1 month ago"
val, unit = time_ago.split()[:2]
past_time = datetime.datetime.now() - relativedelta(**{unit:int(val)})
于 2021-01-22T16:13:18.083 回答
1

completely exaggerated solution but I needed something more flexible:

def string_to_delta(relative):
    #using simplistic year (no leap months are 30 days long.
    #WARNING: 12 months != 1 year
    unit_mapping = [('mic', 'microseconds', 1),
                    ('millis', 'microseconds', 1000),
                    ('sec', 'seconds', 1),
                    ('day', 'days', 1),
                    ('week', 'days', 7),
                    ('mon', 'days', 30),
                    ('year', 'days', 365)]
    try:
        tokens = relative.lower().split(' ')
        past = False
        if tokens[-1] == 'ago':
            past = True
            tokens =  tokens[:-1]
        elif tokens[0] == 'in':
            tokens = tokens[1:]


        units = dict(days = 0, seconds = 0, microseconds = 0)
        #we should always get pairs, if not we let this die and throw an exception
        while len(tokens) > 0:
            value = tokens.pop(0)
            if value == 'and':    #just skip this token
                continue
            else:
                value = float(value)

            unit = tokens.pop(0)
            for match, time_unit, time_constant in unit_mapping:
                if unit.startswith(match):
                    units[time_unit] += value * time_constant
        return datetime.timedelta(**units), past

    except Exception as e:
        raise ValueError("Don't know how to parse %s: %s" % (relative, e))

This can parse things like:

  • 2 days ago
  • in 60 seconds
  • 2 DAY and 4 Secs
  • in 1 year, 1 Month, 2 days and 4 MICRO
  • 2 Weeks 4 secs ago
  • 7 millis ago

A huge but: It simplifies month and year to 30 and 365 days respectively. Not always what you want, though it's enough for some cases.

于 2013-11-07T11:45:08.157 回答
0

Custom function to convert x hours ago to datetime, x hour, y mins ago to datetime, etc in Python.

Function takes single parameter of type string which is parsed using RegExp. RegExp can be customized to match function input.

For usage see examples below.

import re
from datetime import datetime, timedelta


def convert_datetime(datetime_ago):
    matches = re.search(r"(\d+ weeks?,? )?(\d+ days?,? )?(\d+ hours?,? )?(\d+ mins?,? )?(\d+ secs? )?ago", datetime_ago)

    if not matches:
        return None

    date_pieces = {'week': 0, 'day': 0, 'hour': 0, 'min': 0, 'sec': 0}

    for i in range(1, len(date_pieces) + 1):
        if matches.group(i):
            value_unit = matches.group(i).rstrip(', ')
            if len(value_unit.split()) == 2:
                value, unit = value_unit.split()
                date_pieces[unit.rstrip('s')] = int(value)

    d = datetime.today() - timedelta(
        weeks=date_pieces['week'],
        days=date_pieces['day'],
        hours=date_pieces['hour'],
        minutes=date_pieces['min'],
        seconds=date_pieces['sec']
    )

    return d

Example usage:

dates = [
    '1 week, 6 days, 11 hours, 20 mins, 13 secs ago',
    '1 week, 10 hours ago',
    '1 week, 1 day ago',
    '6 days, 11 hours, 20 mins ago',
    '1 hour ago',
    '11 hours, 20 mins ago',
    '20 mins 10 secs ago',
    '10 secs ago',
    '1 sec ago',
]    

for date in dates:
    print(convert_datetime(date))

Output:

2019-05-10 06:26:40.937027
2019-05-16 07:46:53.937027
2019-05-15 17:46:53.937027
2019-05-17 06:26:53.937027
2019-05-23 16:46:53.937027
2019-05-23 06:26:53.937027
2019-05-23 17:26:43.937027
2019-05-23 17:46:43.937027
2019-05-23 17:46:52.937027
于 2019-05-23T12:29:42.107 回答
0

make sure to install dependencies using pip3

from datetime import date
from dateutil.relativedelta import relativedelta
import re

baseDate = date.today() #date(2020, 4, 29)

hoursPattern = re.compile(r'(\d\d?\d?) hours? ago')
daysPattern = re.compile(r'(\d\d?\d?) days? ago')
weeksPattern = re.compile(r'(\d\d?\d?) weeks? ago')
monthsPattern = re.compile(r'(\d\d?\d?) months? ago')
yearsPattern = re.compile(r'(\d\d?\d?) years? ago')


days = 0
daysMatch = daysPattern.search(ago)
if daysMatch:
    days += int(daysMatch.group(1))

hours = 0
hoursMatch = hoursPattern.search(ago)
if hoursMatch:
    hours += int(hoursMatch.group(1))

weeks = 0
weeksMatch = weeksPattern.search(ago)
if weeksMatch:
    weeks += int(weeksMatch.group(1))

months = 0
monthsMatch = monthsPattern.search(ago)
if monthsMatch:
    months += int(monthsMatch.group(1))

years = 0
yearsMatch = yearsPattern.search(ago)
if yearsMatch:
    years += int(yearsMatch.group(1))

yourDate = baseDate - relativedelta(hours=hours, days=days, weeks=weeks, months=months, years=years)
于 2020-04-30T20:11:44.300 回答
0

Any chance for datetime to work with other languages (italian) 'x-days ago to date'?

import locale\
locale.setlocale(locale.LC_ALL,'it_IT.UTF-8') 

doesn't make any difference.

于 2021-03-24T08:01:18.830 回答