2009-08-13 2 views
4

Предположим, у меня есть 2 строки «январь-2010» и «март-2010», и я хочу разобрать его так, чтобы он возвращал два объекта datetime: 1 января 2010 года и 31 марта - 2010 (т. Е. В последний день).парсинг месяц год пары в datetime

Что было бы лучшей стратегией в python? Должен ли я просто разделить строку на токены или использовать регулярные выражения, а затем использовать функции календаря, чтобы сказать, что последний день месяца для «Мар-2010» (получение первого дня тривиально, его всегда 1 в этом случае, если я не хочу первый рабочий день месяца).

Любые предложения? Заранее спасибо.

ответ

2
from datetime import datetime, timedelta 

def first_day(some_date): 
    return some_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0) 

def next_month(some_date): 
    return first_day(first_day(some_date) + timedelta(days=31)) 

def last_day(some_date): 
    return next_month(some_date) - timedelta(days=1) 

# testing: 

months = [('Jan-2010', 'Mar-2010'), # your example 
      ('Apr-2009', 'Apr-2009'), # same month, 30 days 
      ('Jan-2008', 'Dec-2008'), # whole year 
      ('Jan-2007', 'Feb-2007')] # february involved 

for date1, date2 in months: 
    print first_day(datetime.strptime(date1, '%b-%Y')), 
    print '-', 
    print last_day(datetime.strptime(date2, '%b-%Y')) 

Это печатает:

2010-01-01 00:00:00 - 2010-03-31 00:00:00 
2009-04-01 00:00:00 - 2009-04-30 00:00:00 
2008-01-01 00:00:00 - 2008-12-31 00:00:00 
2007-01-01 00:00:00 - 2007-02-28 00:00:00 
5

strptime делает строку разбора в даты от вашего имени:

def firstofmonth(MmmYyyy): 
    return datetime.datetime.strptime(MmmYyyy, '%b-%Y').date() 

гораздо лучше, чем возиться с лексическим, RegExp & с -) ,

Чтобы получить дату последнего дня месяца, вы действительно можете использовать календарь модуль:

def lastofmonth(MmmYyyy): 
    first = firstofmonth(MmmYyyy) 
    _, lastday = calendar.monthrange(first.year, first.month) 
    return datetime.date(first.year, first.month, lastday) 

Вы можете ПОЧТИ сделать это аккуратно с DateTime в одиночку, например, почти рабочий подход:

def lastofmonth(MmmYyyy): 
    first = firstofmonth(MmmYyyy) 
    return first.replace(month=first.month+1, day=1 
      ) - datetime.timedelta(days=1) 

но, увы !, это перерывы на декабрь, а код, необходимый для случая в декабре, делает общий подход более густым, чем календарь ;-).

+0

@Alex: Для того, чтобы сделать его работу по декабрю один должен добавить дни (не месяцы), так как нет месяца относительной timedelta , – nosklo

+0

@nosko, yep, я видел твой трюк (добавление 31 дня, а затем возврат к 1-му из этого месяца), хотя мне не нравится бросать datetime вокруг, когда даты все, что необходимо, и .date() делает извлечение дата от даты и времени просто отлично ;-) –

+0

@Alex: Да, но ... Я не понимаю, как то, что вы сказали, связано с тем, о чем мы говорили раньше. – nosklo

0

риффов на Алекс Мартелли-х:

import datetime 
def lastofmonthHelper(MmmYyyy): # Takes a date 
    return MmmYyyy.replace(year=MmmYyyy.year+(MmmYyyy.month==12), month=MmmYyyy.month%12 + 1, day=1) - datetime.timedelta(days=1) 

>>> for month in range(1,13): 
...  t = datetime.date(2009,month,1) 
...  print t, lastofmonthHelper(t) 
... 
2009-01-01 2009-01-31 
2009-02-01 2009-02-28 
2009-03-01 2009-03-31 
2009-04-01 2009-04-30 
2009-05-01 2009-05-31 
2009-06-01 2009-06-30 
2009-07-01 2009-07-31 
2009-08-01 2009-08-31 
2009-09-01 2009-09-30 
2009-10-01 2009-10-31 
2009-11-01 2009-11-30 
2009-12-01 2009-12-31 

Вы не должны использовать в первый день месяца, BTW. Я бы поставил это в комментарии, но мы все знаем, как получилось бы форматирование. Не стесняйтесь повышать Алекс.

Если вы звоните с результатом вызова firstofmonth(), вы получите желаемый результат:

>>> lastofmonthHelper(firstofmonth('Apr-2009')) 
datetime.date(2009, 4, 30) 
3

Я настоятельно рекомендую использовать модуль питона TimeSeries, который вы можете скачать и прочитать о здесь:

http://pytseries.sourceforge.net/

вы должны также использовать пакет dateutil для разбора строки даты, которую вы можете найти здесь:

http://labix.org/python-dateutil

Затем вы можете сделать что-то вроде этого

import datetime 
import dateutil.parser 
import scikits.timeseries as TS 
m1 = TS.Date('M', datetime=dateutil.parser.parse('Jan-2010')) 
m2 = TS.Date('M', datetime=dateutil.parser.parse('Mar-2010')) 
d1 = m1.asfreq('D', relation='START') # returns a TS.Date object 
d2 = m2.asfreq('D', relation='END') 

firstDay = d1.datetime 
lastDay = d2.datetime 

Это решение Зависимые из внешних модулей, но они очень мощные и хорошо написано.

1

я знаю, что это давно уже нет, но если кому-то нужно:

from dateutil import rrule 
from dateutil import parser 
from datetime import datetime 

first_day = parser.parse('Jan-2010',default=datetime(1,1,1)) 
last_day = rrule.rrule(rrule.MONTHLY,count=1,bymonthday=-1, bysetpos=1,dtstart=parser.parse('Mar-2010')) 
Смежные вопросы