slatenf slatenf - 3 months ago 15
Python Question

How do I get a datetime object out of a YYYY-Q string?

The datetime.strptime reference does not provide an option for the YYYY-Qx (with x = {1,...,4}) date format. Do I need the dateutil.parser for that?

For my implementation, I chose the 15th of the second month as the representative date. That means, if this function receives "2016-Q3" as date, it will be resolved to "2016-08-15".

def df_quarter(self, date):
ypart = datetime.datetime.strptime(date.split('-')[0], '%Y')
qpart = re.sub('Q', '', date.split('-')[1])
qmid = 2+3*(int(qpart)-1)
if qmid < 10:
qmid = "0" + str(qmid)
date = str(ypart.year) + '-' + qmid + '-15'

Answer

You could simply hard-code the relationship between quarters and dates, and use re.sub to replace Q(\d) with the appropriate value:

import re
def df_quarter(date):
    q = {'1':'02-15', '2':'05-15', '3':'08-15', '4':'11-15'}
    return re.sub('Q(\d)', lambda match, q=q: q[match.group(1)], date)

In [36]: df_quarter('2016-Q1')
Out[36]: '2016-02-15'

In [35]: df_quarter('2016-Q2')
Out[35]: '2016-05-15'

In [34]: df_quarter('2016-Q3')
Out[34]: '2016-08-15'

In [37]: df_quarter('2016-Q4')
Out[37]: '2016-11-15'

Or, if you want df_quarter to return a datetime.datetime object:

import re
import datetime as DT
def df_quarter(date):
    q = {'1':'02-15', '2':'05-15', '3':'08-15', '4':'11-15'}
    date = re.sub('Q(\d)', lambda match, q=q: q[match.group(1)], date)
    return DT.datetime.strptime(date, '%Y-%m-%d')

If you would rather compute the month based on a formula, you could instead use

def df_quarter(date):
    date = re.sub('Q(\d)', lambda match: '{:02d}-15'.format(int(match.group(1))*3-1), date)
    return DT.datetime.strptime(date, '%Y-%m-%d')

Notice that the format specifier 02d replaces the integer, int(match.group(1))*3-1 with a 2-digit string padded with a zero on the left if necessary.