2012-09-24 30 views
8

Tôi có chuỗi hiển thị một ngày trong các định dạng sau:python 'x days ago' để datetime

x minutes/hours/days/months/years ago 

tôi cần phải phân tích đó để một datetime sử dụng python.

Có vẻ như dateutil không thể thực hiện được.

Có cách nào để làm điều đó không?

+1

Có vẻ như 'dateutil' thể xử lý nó theo định dạng mà Lattyware và tôi đã quy định, chỉ thay thế 'dateutil.relativedelta' cho' datetime.timedelta'. (xem cập nhật và liên kết của tôi). – mgilson

Trả lời

7

Chắc chắn bạn có thể làm điều đó. Bạn chỉ cần 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 

Là một sang một bên, nó trông giống như dateutilrelativedelta mà hoạt động như một timedelta, nhưng các nhà xây dựng cũng chấp nhận monthsyears trong các đối số (và dường như các đối số cần phải được số nguyên).

+0

relativedelta hoạt động tốt hơn, nó không hoạt động với một phao mặc dù, nó cần 'số tiền' là một int. – applechief

+0

@chaft - Cảm ơn. Tôi cho rằng nó có ý nghĩa. Mặc dù nó có thể tin được rằng bạn có thể đưa ra định nghĩa cho 3 tháng trước, nhưng có lẽ không thể nói được cách đây 3,5 tháng và có một ngày duy nhất. – mgilson

6

Điều này có thể được thực hiện dễ dàng với timedelta s:

import datetime 

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

Sản xuất:

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

Mặc dù điều này sẽ đòi hỏi một số công việc phụ để đối phó với tháng/năm - như thêm một tháng để hẹn hò là một hoạt động mơ hồ, nhưng nó phải là một bổ sung đơn giản nếu bạn biết những gì bạn muốn nó có nghĩa là.

Để nhận thời gian thực tế, chỉ cần lấy đồng bằng cách xa datetime.datetime.now().

+0

Việc chia nhỏ của bạn tao nhã hơn tôi một chút. +1. (mặc dù tôi sẽ sử dụng 'float (n)' - timedelta dường như xử lý nó OK và nó sẽ cho phép sử dụng '3.5 ngày trước'.). – mgilson

+0

@mgilson: Cảm ơn đề xuất này - không biết các phao xử lý của timedelta'. –

+0

Tôi phải thử nó để xem - Khá thú vị :). – mgilson

0

giải pháp hoàn toàn phóng đại nhưng tôi cần một cái gì đó linh hoạt hơn:

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)) 

này có thể phân tích những thứ như:

  • 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

Một khổng lồ nhưng: Nó đơn giản hoá tháng, năm lên 30 và 365 ngày tương ứng. Không phải lúc nào bạn muốn, mặc dù nó đủ cho một số trường hợp.

1

Vì đối số của bạn giống như 2 ngày trước, cách đây 3 tháng, 2 năm trước. Hàm bên dưới có thể trợ giúp trong việc lấy ngày chính xác cho các đối số.Trước tiên, bạn cần phải nhập khẩu các utils ngày sau

import datetime 
from dateutil.relativedelta import relativedelta 

Sau đó, thực hiện các chức năng dưới đây

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" 

Sau đó bạn có thể gọi hàm như thế này:

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') 
Các vấn đề liên quan