def decodeOneDate(datestr, workdate=None, months=None, days=None, quarters=None, locale=None, isEndPeriod=False): """Parse a string representing a date or a period. Return ``datetime.date`` or ``tuple(year,month)`` or ``None`` :param datestr: the string to be interpreted :param workdate: the :ref:`workdate` :param months: names of months according to locale (just for caching) :param days: names of weekdays according to locale (just for caching) :param quarters: names of quarters according to locale (just for caching) :param locale: the current locale (e.g: en, en_us, it) :param isEndPeriod: if the string represents a period, return the end date (default return the start date) Special keywords like ``today`` or the name of a month can be translated in all languages and support synonimous. (e.g: this month; e.g: month) The input string can be: * a year: e.g. 2007 or 07 * today, yesterday, tomorrow (can be translated in all languages) * you can specify a number of days to add to today: e.g. 'today + 3' or 'today - 15' * this week, next week, last week (can be translated in all languages) * this month, next month, last month (can be translated in all languages ) * can be specified a number of months to add to current month: e.g. 'this month + 3' or 'this month - 24' * the name of a quarter: e.g. Q1 or 1st quarter * the name of a month: e.g. april or apr * can be specified a year after the month: e.g. apr 07 or april 2007 * returns a tuple (year, month): if year is not specified in datestr, year is returned None * the name of a weekday: e.g. monday or mon * the date returned is the date of the given weekday in this week (relative to workdate) * an iso date: e.g. 2008-04-28 * a date formatted according to locale (see babel doc): e.g. 4 28, 2008 (en_us) or 28-4-08 (it) various separators are admitted: 28-4-08, 28/4/08, 28 4 08""" def addToDay(datestr, date): if '+' in datestr: days = int(datestr.split('+')[1].strip()) return date + datetime.timedelta(days) if '-' in datestr: days = int(datestr.split('-')[1].strip()) return date - datetime.timedelta(days) return date def addToMonth(datestr, date, addmonth=0):#l'errore è nel chiamate che passa addmonth sbagliato delta=0 if '+' in datestr: delta = int(datestr.split('+')[1].strip()) if '-' in datestr: delta = -int(datestr.split('-')[1].strip()) month = date.month + addmonth+ delta year = date.year while month <= 0: month = month + 12 year = year - 1 while month > 12: month = month - 12 year = year + 1 return datetime.date(year, month, 1) datestr = datestr or '' datestr = datestr.strip() if datestr: months = months or gnrlocale.getMonthNames(locale) def_months = gnrlocale.getMonthNames(DEFAULT_LOCALE) days = days or gnrlocale.getDayNames(locale) def_days = gnrlocale.getDayNames(DEFAULT_LOCALE) quarters = quarters or gnrlocale.getQuarterNames(locale) def_quarters = gnrlocale.getQuarterNames(DEFAULT_LOCALE) dateStart = None dateEnd = None workdate = workdate or datetime.date.today() if datestr.isdigit() and len(datestr) in (2, 4): # a full year year = yearDecode(datestr) dateStart = datetime.date(year, 1, 1) if isEndPeriod: dateEnd = datetime.date(year, 12, 31) elif checkDateKeywords('today', datestr, locale): # today dateStart = addToDay(datestr, workdate) elif checkDateKeywords('yesterday', datestr, locale): # yesterday dateStart = addToDay(datestr, workdate - datetime.timedelta(1)) elif checkDateKeywords('tomorrow', datestr, locale): # tomorrow dateStart = addToDay(datestr, workdate + datetime.timedelta(1)) elif checkDateKeywords(('this week', 'next week', 'last week'), datestr, locale): # relative week j = workdate.weekday() dateStart = workdate - datetime.timedelta(j) if checkDateKeywords('last week', datestr, locale): dateStart = dateStart - datetime.timedelta(7) elif checkDateKeywords('next week', datestr, locale): dateStart = dateStart + datetime.timedelta(7) if '+' in datestr: dateStart = dateStart + datetime.timedelta(7*int(datestr.split('+')[1])) if '-' in datestr: dateStart = dateStart - datetime.timedelta(7*int(datestr.split('-')[1])) if isEndPeriod: dateEnd = dateStart + datetime.timedelta(6) elif checkDateKeywords(('this month', 'next month', 'last month'), datestr, locale): # relative month if checkDateKeywords('last month', datestr, locale): dateStart = addToMonth(datestr, workdate, -1) elif checkDateKeywords('next month', datestr, locale): dateStart = addToMonth(datestr, workdate, 1) else: dateStart = addToMonth(datestr, workdate) if isEndPeriod: dateEnd = monthEnd(date=dateStart) elif anyWordIn(quarters.keys(), datestr): # quarter qt, year = splitAndStrip(datestr, sep=' ', n=1, fixed=2) year = yearDecode(year) qt = quarters[datestr] dateStart = (year, qt * 3 - 2) if isEndPeriod: dateEnd = (year, qt * 3) elif anyWordIn(def_quarters.keys(), datestr): # quarter qt, year = splitAndStrip(datestr, sep=' ', n=1, fixed=2) year = yearDecode(year) qt = def_quarters[datestr] dateStart = (year, qt * 3 - 2) if isEndPeriod: dateEnd = (year, qt * 3) elif anyWordIn(months.keys(), datestr): # month name month, year = splitAndStrip(datestr, sep=' ', n=1, fixed=2) year = yearDecode(year) month = months[month] dateStart = (year, month) elif anyWordIn(def_months.keys(), datestr): # month name month, year = splitAndStrip(datestr, sep=' ', n=1, fixed=2) year = yearDecode(year) month = def_months[month] dateStart = (year, month) elif datestr in days: # weekday name dateStart = workdate + datetime.timedelta(days[datestr] - workdate.weekday()) elif datestr in def_days: # weekday name dateStart = workdate + datetime.timedelta(def_days[datestr] - workdate.weekday()) elif re.match('\d{4}-\d{2}-\d{2}', datestr): # ISO date date_items = [int(el) for el in wordSplit(datestr)[0:3]] dateStart = datetime.date(*[int(el) for el in wordSplit(datestr)[0:3]]) else: # a date in local format dateStart = gnrlocale.parselocal(datestr, datetime.date, locale) if isEndPeriod and dateEnd: return dateEnd else: return dateStart
def decodeOneDate(datestr, workdate=None, months=None, days=None, quarters=None, locale=None, isEndPeriod=False): """Parse a string representing a date or a period. Return ``datetime.date`` or ``tuple(year,month)`` or ``None`` :param datestr: the string to be interpreted :param workdate: the :ref:`workdate` :param months: names of months according to locale (just for caching) :param days: names of weekdays according to locale (just for caching) :param quarters: names of quarters according to locale (just for caching) :param locale: the current locale (e.g: en, en_us, it) :param isEndPeriod: if the string represents a period, return the end date (default return the start date) Special keywords like ``today`` or the name of a month can be translated in all languages and support synonimous. (e.g: this month; e.g: month) The input string can be: * a year: e.g. 2007 or 07 * today, yesterday, tomorrow (can be translated in all languages) * you can specify a number of days to add to today: e.g. 'today + 3' or 'today - 15' * this week, next week, last week (can be translated in all languages) * this month, next month, last month (can be translated in all languages ) * can be specified a number of months to add to current month: e.g. 'this month + 3' or 'this month - 24' * the name of a quarter: e.g. Q1 or 1st quarter * the name of a month: e.g. april or apr * can be specified a year after the month: e.g. apr 07 or april 2007 * returns a tuple (year, month): if year is not specified in datestr, year is returned None * the name of a weekday: e.g. monday or mon * the date returned is the date of the given weekday in this week (relative to workdate) * an iso date: e.g. 2008-04-28 * a date formatted according to locale (see babel doc): e.g. 4 28, 2008 (en_us) or 28-4-08 (it) various separators are admitted: 28-4-08, 28/4/08, 28 4 08""" def addToDay(datestr, date): if '+' in datestr: days = int(datestr.split('+')[1].strip()) return date + datetime.timedelta(days) if '-' in datestr: days = int(datestr.split('-')[1].strip()) return date - datetime.timedelta(days) return date def addToMonth(datestr, date, addmonth=0):#l'errore è nel chiamate che passa addmonth sbagliato delta=0 if '+' in datestr: delta = int(datestr.split('+')[1].strip()) if '-' in datestr: delta = -int(datestr.split('-')[1].strip()) month = date.month + addmonth+ delta year = date.year while month <= 0: month = month + 12 year = year - 1 while month > 12: month = month - 12 year = year + 1 return datetime.date(year, month, 1) datestr = datestr or '' datestr = datestr.strip() if datestr: months = months or gnrlocale.getMonthNames(locale) def_months = gnrlocale.getMonthNames(DEFAULT_LOCALE) days = days or gnrlocale.getDayNames(locale) def_days = gnrlocale.getDayNames(DEFAULT_LOCALE) quarters = quarters or gnrlocale.getQuarterNames(locale) def_quarters = gnrlocale.getQuarterNames(DEFAULT_LOCALE) dateStart = None dateEnd = None workdate = workdate or datetime.date.today() if datestr.isdigit() and len(datestr) in (2, 4): # a full year year = yearDecode(datestr) dateStart = datetime.date(year, 1, 1) if isEndPeriod: dateEnd = datetime.date(year, 12, 31) elif checkDateKeywords('today', datestr, locale): # today dateStart = addToDay(datestr, workdate) elif checkDateKeywords('yesterday', datestr, locale): # yesterday dateStart = addToDay(datestr, workdate - datetime.timedelta(1)) elif checkDateKeywords('tomorrow', datestr, locale): # tomorrow dateStart = addToDay(datestr, workdate + datetime.timedelta(1)) elif checkDateKeywords(('this week', 'next week', 'last week'), datestr, locale): # relative week j = workdate.weekday() dateStart = workdate - datetime.timedelta(j) if checkDateKeywords('last week', datestr, locale): dateStart = dateStart - datetime.timedelta(7) elif checkDateKeywords('next week', datestr, locale): dateStart = dateStart + datetime.timedelta(7) if '+' in datestr: dateStart = dateStart + datetime.timedelta(7*int(datestr.split('+')[1])) if '-' in datestr: dateStart = dateStart - datetime.timedelta(7*int(datestr.split('-')[1])) if isEndPeriod: dateEnd = dateStart + datetime.timedelta(6) elif checkDateKeywords(('this month', 'next month', 'last month'), datestr, locale): # relative month if checkDateKeywords('last month', datestr, locale): dateStart = addToMonth(datestr, workdate, -1) elif checkDateKeywords('next month', datestr, locale): dateStart = addToMonth(datestr, workdate, 1) else: dateStart = addToMonth(datestr, workdate) if isEndPeriod: dateEnd = monthEnd(date=dateStart) elif anyWordIn(quarters.keys(), datestr): # quarter qt, year = splitAndStrip(datestr, sep=' ', n=1, fixed=2) year = yearDecode(year) qt = quarters[qt] dateStart = (year, qt * 3 - 2) if isEndPeriod: dateEnd = (year, qt * 3) elif anyWordIn(def_quarters.keys(), datestr): # quarter qt, year = splitAndStrip(datestr, sep=' ', n=1, fixed=2) year = yearDecode(year) qt = def_quarters[datestr] dateStart = (year, qt * 3 - 2) if isEndPeriod: dateEnd = (year, qt * 3) elif anyWordIn(months.keys(), datestr): # month name month, year = splitAndStrip(datestr, sep=' ', n=1, fixed=2) year = yearDecode(year) month = months[month] dateStart = (year, month) elif anyWordIn(def_months.keys(), datestr): # month name month, year = splitAndStrip(datestr, sep=' ', n=1, fixed=2) year = yearDecode(year) month = def_months[month] dateStart = (year, month) elif datestr in days: # weekday name dateStart = workdate + datetime.timedelta(days[datestr] - workdate.weekday()) elif datestr in def_days: # weekday name dateStart = workdate + datetime.timedelta(def_days[datestr] - workdate.weekday()) elif re.match('\d{4}-\d{2}-\d{2}', datestr): # ISO date date_items = [int(el) for el in wordSplit(datestr)[0:3]] dateStart = datetime.date(*[int(el) for el in wordSplit(datestr)[0:3]]) else: # a date in local format dateStart = gnrlocale.parselocal(datestr, datetime.date, locale) if isEndPeriod and dateEnd: return dateEnd else: return dateStart
def checkDateKeywords(keywords,datestr,locale): return anyWordIn(gnrlocale.getDateKeywords(keywords, locale), datestr) or anyWordIn( gnrlocale.getDateKeywords(keywords, DEFAULT_LOCALE), datestr)