简体   繁体   中英

parsing month year pairs into datetime

Let's say i have 2 strings 'Jan-2010' and 'Mar-2010' and i want to parse it such that it returns 2 datetime objects: 1-Jan-2010 and 31-Mar-2010 (ie the last day).

What would be the best strategy in python? Should i just split the string into tokens or use regular expressions and then use the calendar functions to get say the last day of the month for 'Mar-2010' (getting the first day is trivial, its always 1 in this case unless i wanted the first working day of the month).

Any suggestions? Thanks in advance.

strptime does the string parsing into dates on your behalf:

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

much better than messing around with tokenization, regexp, &c!-).

To get the date of the last day of the month, you can indeed use the calendar module:

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

You could ALMOST do it neatly with datetime alone, eg, an ALMOST working approach:

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

but, alas!, this breaks for December, and the code needed to specialcase December makes the overall approach goofier than calendar affords;-).

I highly recommend using the python timeseries module, which you can download and read about here:

http://pytseries.sourceforge.net/

You should also use the dateutil package for parsing the date string, which you can find here:

http://labix.org/python-dateutil

Then you can do something like this

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

This solution is dependent out outside modules, but they're very powerful and well written.

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

That prints:

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

i know it's long time gone, but if someone needs:

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

Riffing on Alex Martelli's:

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

You don't have to use the first day of the month, BTW. I would have put this in a comment but we all know how the formatting would have turned out. Feel free to upvote Alex.

If you call with the result of a firstofmonth() call, you get the desired result:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM