def onchange_operation_type(self, cr, uid, ids, type, guarantee_limit): if not type: return {'value': {'location_id': False, 'location_dest_id': False}} produc_id = self.pool.get('stock.location').search( cr, uid, [('name', '=', 'Production')])[0] stock_id = self.pool.get('stock.location').search( cr, uid, [('name', '=', 'Stock')])[0] if type == 'add': to_invoice = False if guarantee_limit and today() > mx.DateTime.strptime( guarantee_limit, '%Y-%m-%d'): to_invoice = True return { 'value': { 'to_invoice': to_invoice, 'location_id': stock_id, 'location_dest_id': produc_id } } return { 'value': { 'to_invoice': False, 'location_id': produc_id, 'location_dest_id': stock_id } }
def onchange_operation_type(self, cr, uid, ids, type, guarantee_limit): if not type: return {'value': { 'location_id': False, 'location_dest_id': False } } produc_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Production')])[0] stock_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Stock')])[0] if type == 'add': to_invoice=False if guarantee_limit and today() > mx.DateTime.strptime(guarantee_limit, '%Y-%m-%d'): to_invoice=True return {'value': { 'to_invoice': to_invoice, 'location_id': stock_id, 'location_dest_id' : produc_id } } return {'value': { 'to_invoice': False, 'location_id': produc_id, 'location_dest_id': stock_id } }
def calc_project_length(self): """Computes start_date and max_duration (duration of the project)""" begins, ends = [], [] for leaf in self.project.root_task.leaves(): for c_type, date, priority in leaf.get_date_constraints(): if c_type in (CST.BEGIN_AT_DATE, CST.BEGIN_AFTER_DATE) and \ self.project.priority >= int(priority): begins.append(date) elif c_type in (CST.END_AT_DATE, CST.END_BEFORE_DATE) and \ self.project.priority >= int(priority): ends.append(date) if not self.start_date: # We take the earliest date constraint as a start date if begins: self.start_date = min(begins) elif ends: self.start_date = min(ends) else: self.start_date = today() # find the first working day d = self.start_date self.first_day = 0 # instead of checking all resources, we should look only for resources # working on those task that *could* begin at the start of the project while not any( res.is_available(d) for res in self.project.get_resources()): d += 1 self.first_day += 1 # play it safe and add sum of loads plus time to latest date constraint self.max_duration = self.project.root_task.maximum_duration() if begins or ends: self.max_duration += (max(itertools.chain(begins, ends)) - self.start_date).days
def __init__(self, **kw): super(ReceiptWindow, self).__init__(**kw) self.window.title = "Receipt Generation" self.trans = Transaction() self.target=Receipt(actualDate=today()) self.trans.track(self.target) v = cimarron.skin.VBox(parent=self.window, expand=True, fill=True) h1 = cimarron.skin.HBox(parent=v, expand=False, fill=True) h2 = cimarron.skin.HBox(parent=v, expand=False, fill=False) v1 = cimarron.skin.VBox(parent=v) actionContainer = cimarron.skin.HBox(parent=v, expand=False, fill=True) columns = (cimarron.skin.Column(name="Name", attribute="name"), cimarron.skin.Column(name="Surname", attribute="surname")) self.person = cimarron.skin.SearchEntry(parent=h1, cls=Person, searcher=self.trans, columns=columns, attribute="person") cimarron.skin.Label(parent=h2, text="Date:") self.actualDate = cimarron.skin.Entry(parent=h2, attribute="actualDate") cimarron.skin.Label(parent=h2, text="Amount:") self.amount = cimarron.skin.Entry(parent=h2, attribute="amount") cimarron.skin.Label(parent=v1, text="Concept:", expand=False, fill=False) self.concept = cimarron.skin.MultiLine(parent=v1, attribute="concept") save = cimarron.skin.Button(parent=actionContainer, label="Save", onAction=self.save) discard = cimarron.skin.Button(parent=actionContainer, label="Discard", onAction=self.discard) self.refresh()
def unpackSchedule(self, data): checks = [False] * LASTDAY_MIDNIGHT base = today() + 3 for row in data: start_check = ((row[0].day_of_week - base.day_of_week) % 7) * 48 + row[0].hour * 2 + row[0].minute / 30 end_check = ((row[1].day_of_week - base.day_of_week) % 7) * 48 + row[1].hour * 2 + row[1].minute / 30 if end_check <= start_check: end_check += LASTDAY_MIDNIGHT for hour in range(start_check, end_check): checks[hour % LASTDAY_MIDNIGHT] = True return checks
def _process_node(self, node): # get dates try: begin = self.earliest_begin(node) or today() except ValueError: begin = today() duration = max(0, node.duration - 1) #if begin and not end: # end = begin + duration #elif end and not begin: # begin = end - duration # add activities activities = [] resources = [ (self.project.get_resource(r_id), usage / 100) for r_type, r_id, usage in node.get_resource_constraints() ] if not resources: log.warning("task %s has no resource and will not be scheduled", node.id) return self.date_res = {} for res, usage in resources: self.date_res.setdefault(res.id, begin - 1) load = node.duration * (1 - node.progress) date = begin if load == 0 and begin == today(): log.warning("task %s is complete but was never worked on" % node.id) while load > 0 and resources: for resource, usage in resources: if self.date_res[resource.id] < date and resource.is_available(date) \ and self.project.get_total_usage(resource.id, date) <= 1-usage : activities.append( (date, date, resource.id, node.id, usage)) self.date_res[resource.id] = date load -= usage if load <= 0: break date += 1 self.project.add_schedule(activities)
def _process_node(self, node): # get dates begin, end = None, None for c_type, date, priority in node.get_date_constraints(): if c_type == BEGIN_AFTER_DATE : begin = date # FIXME what if more than one ? elif c_type == END_BEFORE_DATE : end = date # FIXME what if more than one ? if not begin and not end: begin = today() # add activities activities = [] # collect resources if node.TYPE == "milestone": self.project.milestones[node.id] = begin return [] node.compute_resources(self.project) resources = [self.project.resources[r_id] for r_id in node.get_resource_ids()] # if not resources: # print "WARNING: task %s has no resource and will not be scheduled"%node.id days = {} duration = node.duration*(1-node.progress) if begin: for resource in resources: days[resource] = begin while duration > 0 and resources: for resource in resources: date = days[resource] # while not resource.is_available(date): # date += 1 # print date # usage = 1 activities.append( (date, date, resource.id, node.id, 1) ) days[resource] = date + 1 duration -= 1 else: for resource in resources: days[resource] = end while duration > 0 and resources: for resource in resources: date = days[resource] # while not resource.is_available(date): # date -= 1 # print date # usage = 1 activities.append( (date, date, resource.id, node.id, 1) ) days[resource] = date - 1 duration -= 1 return activities
def packSchedule(self, checks): try: # Mapeamos a integer y filtramos valores inadecuados checks = [int(chk) for chk in checks] except ValueError: return [] checks.sort() scheds = [] last_hour = None start_time = None end_time = None for hour in checks: if last_hour is None: start_time = hour elif last_hour < hour - 1: scheds.append((start_time, end_time)) start_time = hour last_hour = hour end_time = hour + 1 # Falta el último span, que lo agregamos ahora: if end_time is not None: if end_time == LASTDAY_MIDNIGHT: if start_time == 0: # Este tipo labura 24/7! scheds.append((0, end_time)) elif len(scheds) > 0 and scheds[0][0] == 0: # El horario abarca las 0 del domingo scheds.append((start_time, end_time + scheds[0][1])) del(scheds[0]) else: scheds.append((start_time, end_time)) else: scheds.append((start_time, end_time)) # Convertimos a DateTime spans = [] base = today() + 3 def mktimestamp(x): day = base + x / 48 #VER #incluir DateTimeDelta del userId return DateTime(day.year, day.month, day.day, (x % 48) / 2, (x % 2) * 30) for sched in scheds: spans.append((mktimestamp(sched[0]), mktimestamp(sched[1]))) return spans
def unpackSchedule(self, data): checks = ['u'] * LASTDAY_MIDNIGHT base = today() + 3 for row in data[1]: start_check = ((row[0].day_of_week - base.day_of_week) % 7) * 48 + row[0].hour * 2 + row[0].minute / 30 end_check = ((row[1].day_of_week - base.day_of_week) % 7) * 48 + row[1].hour * 2 + row[1].minute / 30 if end_check <= start_check: end_check += LASTDAY_MIDNIGHT for hour in range(start_check, end_check): checks[hour % LASTDAY_MIDNIGHT] = '2' for row in data[0]: delta = row[0] - base start_check = delta.day * 48 + delta.hour * 2 + delta.minute / 30 delta = row[1] - base end_check = delta.day * 48 + delta.hour * 2 + delta.minute / 30 if end_check <= start_check: end_check += LASTDAY_MIDNIGHT for hour in range(start_check, end_check): checks[hour % LASTDAY_MIDNIGHT] = 'o' return checks
def __init__(self, **kw): super(ReceiptWindow, self).__init__(**kw) self.window.title = "Receipt Generation" self.trans = Transaction() self.target = Receipt(actualDate=today()) self.trans.track(self.target) v = cimarron.skin.VBox(parent=self.window, expand=True, fill=True) h1 = cimarron.skin.HBox(parent=v, expand=False, fill=True) h2 = cimarron.skin.HBox(parent=v, expand=False, fill=False) v1 = cimarron.skin.VBox(parent=v) actionContainer = cimarron.skin.HBox(parent=v, expand=False, fill=True) columns = (cimarron.skin.Column(name="Name", attribute="name"), cimarron.skin.Column(name="Surname", attribute="surname")) self.person = cimarron.skin.SearchEntry(parent=h1, cls=Person, searcher=self.trans, columns=columns, attribute="person") cimarron.skin.Label(parent=h2, text="Date:") self.actualDate = cimarron.skin.Entry(parent=h2, attribute="actualDate") cimarron.skin.Label(parent=h2, text="Amount:") self.amount = cimarron.skin.Entry(parent=h2, attribute="amount") cimarron.skin.Label(parent=v1, text="Concept:", expand=False, fill=False) self.concept = cimarron.skin.MultiLine(parent=v1, attribute="concept") save = cimarron.skin.Button(parent=actionContainer, label="Save", onAction=self.save) discard = cimarron.skin.Button(parent=actionContainer, label="Discard", onAction=self.discard) self.refresh()
def total(self, date=None): if date is None: date = today() q = Qualifier() this_pos = q.pointOfSale.id == self.id q_date = q.entry.recordDate tr = self.transaction() openings = tr.search('PointOfSaleOpening', this_pos & (q_date <= date)) closures = tr.search('PointOfSaleClosure', this_pos & (q_date >= date)) if not openings: # nothing done return 0.0 openings = [(i.entry.recordDate, i) for i in openings] openings.sort() opening = openings[-1][1] q_movs = q.entry.pointOfSale.id == self.id if closures: closures = [(i.entry.recordDate, i) for i in closures] closures.sort() closure = closures[0][1] q_movs = q_movs & (q.entry.recordDate < closure.entry.recordDate) q_movs = q_movs & (q.entry.recordDate > opening.entry.recordDate) & \ (q.account.code == '1.1.01.01') debit = sum(tr.search('Movement', q_movs & (q.operation == 0))) credit = sum(tr.search('Movement', q_movs & (q.operation == 1))) print '*' * 40 print q_movs.value print debit, credit print '*' * 40 return -1
def total(self, date=None): if date is None: date = today() q = Qualifier() this_pos = q.pointOfSale.id == self.id q_date = q.entry.recordDate tr = self.transaction() openings = tr.search('PointOfSaleOpening', this_pos & (q_date <= date)) closures = tr.search('PointOfSaleClosure', this_pos & (q_date >= date)) if not openings: # nothing done return 0.0 openings = [(i.entry.recordDate, i) for i in openings] openings.sort() opening = openings[-1][1] q_movs = q.entry.pointOfSale.id == self.id if closures: closures = [(i.entry.recordDate, i) for i in closures] closures.sort() closure = closures[0][1] q_movs = q_movs & (q.entry.recordDate < closure.entry.recordDate) q_movs = q_movs & (q.entry.recordDate > opening.entry.recordDate) & \ (q.account.code == '1.1.01.01') debit = sum(tr.search('Movement', q_movs & (q.operation == 0))) credit = sum(tr.search('Movement', q_movs & (q.operation == 1))) print '*'*40 print q_movs.value print debit, credit print '*'*40 return -1
def process_affiliations(employment_file, person_file, use_fok, people_to_ignore=None): """Parse employment_file and determine all affiliations. There are roughly 3 distinct parts: #. Cache all the affiliations in Cerebrum #. Scan the file and compare the file data with the cache. When there is a match, remove the entry from the cache. #. Remove from Cerebrum whatever is left in the cache (once we are done with the file, the cache contains those entries that were in Cerebrum """ expired = load_expired_employees(file(person_file), use_fok, logger) # First we cache all existing affiliations. It's a mapping person-id => # mapping (ou-id, affiliation) => status. affiliation_cache = cache_db_affiliations() person_cache = dict() def person_cacher(empid): ret = person_cache.get(empid, NotSet) if ret is NotSet: ret = person_cache[empid] = get_person(empid) return ret for tpl in make_employment_iterator( file(employment_file), use_fok, logger): if not tpl.valid(): logger.debug("Ignored invalid entry for person while " "processing affiliation: «%s»", tpl.sap_ansattnr) continue if people_to_ignore and tpl.sap_ansattnr in people_to_ignore: logger.debug("Invalid person with sap_id=%s", tpl.sap_ansattnr) continue if tpl.sap_ansattnr in expired: logger.debug("Person sap_id=%s is no longer an employee; " "all employment info will be ignored", tpl.sap_ansattnr) continue # is the entry within a valid time frame? # The shift by 180 days has been requested by UiA around 2007-03-27 if not (tpl.start_date - DateTimeDelta(180) <= today() <= tpl.end_date): logger.debug("Entry %s has wrong timeframe (start: %s, end: %s)", tpl, tpl.start_date, tpl.end_date) continue ou_id = get_ou_id(tpl.sap_ou_id) if ou_id is None: logger.warn("Cannot map SAP OU %s to Cerebrum ou_id (employment " "for person sap_id=%s).", tpl.sap_ou_id, tpl.sap_ansattnr) continue person = person_cacher(tpl.sap_ansattnr) if person is None: logger.warn("Cannot map SAP ansattnr %s to cerebrum person_id", tpl.sap_ansattnr) continue (affiliation, affiliation_status) = sap_employment2affiliation(tpl.lonnstittel) synchronize_affiliations(affiliation_cache, person, ou_id, affiliation, affiliation_status) # We are done with fetching updates from file. # Need to write persons for p in person_cache.values(): if p is None: continue logger.info("Writing cached affs for person id:%s", p.entity_id) p.write_db() # All the affiliations left in the cache exist in Cerebrum, but NOT in the # datafile. Thus delete them! remove_affiliations(affiliation_cache)
# this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """ Abstract classes for Abstract classes for rendering """ from mx.DateTime import now, today, oneDay from projman import ENCODING from projman.lib import date_range from projman.lib._exceptions import ViewException TITLE_COLUMN_WIDTH = 220 FIELD_COLUMN_WIDTH = 40 TIME_COLUMN_WIDTH = 40. LEGEND_COLUMN_WIDTH = 80 ROW_HEIGHT = 20 TODAY = today() DEFAULT_COLORS = { 'HEAD': 'lightgrey', 'CONSTRAINT': 'black', # for odd row 'ODD_SET': { 'TITLE': 'wheat', 'FIELD': 'darkseagreen', 'WEEKDAY': 'wheat', 'WEEKEND': 'cornsilk', 'TODAY': 'salmon', 'RESOURCE_USED': 'darkblue', 'RESOURCE_UNAVAILABLE': 'cornsilk', }, # for even row
value = from_func(super(instance.__class__, instance).to_python(value)) except ValidationError: value = strpdatetime(value) return value.rebuild(hour=12) def strpdatetime(value, frmt='date'): """ Parse the given input text value as a particular format (date/datetime). If the value is identical to today, then InvalidDateError is raised. This is supposed to be used as a last resort after all other validation efforts have failed. """ if frmt == 'date': from_func = DateFrom else: from_func = DateTimeFrom input_value = value try: value = from_func(value) except RangeError, exc: raise InvalidDateError(input_value, exc) except ValueError: raise InvalidDateError(input_value) try: assert value == today() except AssertionError: pass else: raise InvalidDateError(input_value) return value
def pre_save(self, model_instance, add): if self.auto_now or (self.auto_now_add and add): value = today(hour=12) setattr(model_instance, self.attname, value) return value return super(DateField, self).pre_save(model_instance, add)
def printForm(self, data, request, userId, sbj, tutor): _ = request.getSession()._ checks = self.unpackSchedule(data) days = [_('Lunes'), _('Martes'), _('Miercoles'), _('Jueves'), _('Viernes'), _('Sabado'), _('Domingo')] classes={'u': 'sch_unavailable', '1': 'sch_instant', '2': 'sch_precoord', 'o': 'sch_occupied'} titles={'u': _('No disponible'), '1': _('Disponible para acceso instantaneo'), '2': _('Disponible para clases precoordinadas'), 'o': _('Ya esta reservado')} string = """ <script type="text/javascript"> <!-- function validateForm(form) { for (i = 0; i < form.elements.length; i++) { if (form.elements[i].checked) return true; } alert('""" + _('Debes seleccionar al menos un horario') + """'); return false; } function change_cell (tag) { input = tag.getElementsByTagName('input')[0] if (!input) return; input.checked = ! input.checked; if (input.checked) { var style = "sch_arranged"; var tit = '""" + _('Coordinado para este horario') + """'; } else { var style = "sch_precoord"; var tit = '""" + _('Disponible para clases precoordinadas') + """'; } tag.className = style; tag.title = tit; } --> </script> <form action="4" method="get" onsubmit="javascript:return validateForm(this)" > <fieldset> <legend>""" + _('Horarios disponibles') + """</legend> <table id="schedule"> <tr> <th><p/></th> """ for day in [today() + i for i in range(3,10)]: string += '<th class="sch_header">%s %s</th>\n' % (days[day.day_of_week], day.strftime('%d-%m-%Y')) for hour in range(48): string += '</tr><tr>\n<td class="sch_row">%d:%02dhs</td>\n' % (hour / 2, (hour % 2) * 30) for day in enumerate(days): pos = 48 * day[0] + hour val = checks[pos] string += '<td class="%s" title="%s"' % (classes[val], titles[val]) if val in ['', 'o', 'u']: string += '><p/></td>\n' else: string += 'onclick="change_cell(this)"><input type="checkbox" name="sch" value="%d"/></td>\n' % pos string += """ </tr><tr><td class="sch_row">24:00hs</td><td colspan="7" class="sch_invisible"><p/></td>\n</tr></table> <input type="hidden" name="user_id" value="%d"/> <input type="hidden" name="sbj" value="%d"/> <input type="hidden" name="tutor" value="%d"/> <input type="submit" name="submit" value=\"""" % (userId, sbj, tutor) + _('Enviar') + """\" /> </fieldset> </form> """ request.write(string) return
def process_affiliations(employment_file, person_file, use_fok, people_to_ignore=None): """Parse employment_file and determine all affiliations. There are roughly 3 distinct parts: #. Cache all the affiliations in Cerebrum #. Scan the file and compare the file data with the cache. When there is a match, remove the entry from the cache. #. Remove from Cerebrum whatever is left in the cache (once we are done with the file, the cache contains those entries that were in Cerebrum """ expired = load_expired_employees(file(person_file), use_fok, logger) # First we cache all existing affiliations. It's a mapping person-id => # mapping (ou-id, affiliation) => status. affiliation_cache = cache_db_affiliations() person_cache = dict() def person_cacher(empid): ret = person_cache.get(empid, NotSet) if ret is NotSet: ret = person_cache[empid] = get_person(empid) return ret for tpl in make_employment_iterator(file(employment_file), use_fok, logger): if not tpl.valid(): logger.debug( "Ignored invalid entry for person while " "processing affiliation: «%s»", tpl.sap_ansattnr) continue if people_to_ignore and tpl.sap_ansattnr in people_to_ignore: logger.debug("Invalid person with sap_id=%s", tpl.sap_ansattnr) continue if tpl.sap_ansattnr in expired: logger.debug( "Person sap_id=%s is no longer an employee; " "all employment info will be ignored", tpl.sap_ansattnr) continue # is the entry within a valid time frame? # The shift by 180 days has been requested by UiA around 2007-03-27 if not (tpl.start_date - DateTimeDelta(180) <= today() <= tpl.end_date): logger.debug("Entry %s has wrong timeframe (start: %s, end: %s)", tpl, tpl.start_date, tpl.end_date) continue ou_id = get_ou_id(tpl.sap_ou_id) if ou_id is None: logger.warn( "Cannot map SAP OU %s to Cerebrum ou_id (employment " "for person sap_id=%s).", tpl.sap_ou_id, tpl.sap_ansattnr) continue person = person_cacher(tpl.sap_ansattnr) if person is None: logger.warn("Cannot map SAP ansattnr %s to cerebrum person_id", tpl.sap_ansattnr) continue (affiliation, affiliation_status) = sap_employment2affiliation(tpl.lonnstittel) synchronize_affiliations(affiliation_cache, person, ou_id, affiliation, affiliation_status) # We are done with fetching updates from file. # Need to write persons for p in person_cache.values(): if p is None: continue logger.info("Writing cached affs for person id:%s", p.entity_id) p.write_db() # All the affiliations left in the cache exist in Cerebrum, but NOT in the # datafile. Thus delete them! remove_affiliations(affiliation_cache)
def setUp(self): self.today = int(today(12).jdn) for d in self.dates: Model.objects.create(date=d)
def discard(self, *ignore): self.trans.discard() self.newTarget(Receipt(actualDate=today())) self.trans.track(self.target)
def parseDateTime(string, USA=False): '''Tries to parse a string as a valid date and/or time. It recognizes most common formats: @param USA: Disambiguates strings that are valid dates either in (month,day,year) or (day,month,year) order (e.g. 05/03/2002). If True, the first format is assumed; the default is the second. @return: A C{datetime.datetime} instance that represents the parsed string. @rtype: datetime.datetime @raise ValueError: If the string cannot be interpreted successfully. ''' # create the regexps only the first time this function is called if not hasattr(parseDateTime, "regex"): item = lambda groupid: r'(?P<%s>\d+|[a-zA-Z]+)' % groupid delim = r'[\s\\/,-.]+' # negative lookahead/lookbehind assertions on ':' (to prevent mix # with time); also negative lookbehind on \w dateRegex = "(?<!:|\w)%s%s%s(?:%s%s)?(?!:)" % (item('D1'), delim, item('D2'), delim, item('D3')) timeRegex = r'''(?P<hour>\d{1,2}): # hour (?P<minute>\d{1,2}) # minute (?::(?P<second>\d{1,2}(?:\.\d+)?))? # second (?:\ ?(?P<ampm>[ap]m))? # 'am', 'pm' ''' #print r'(?P<date>%s)\s+(?P<time>%s)?' % (dateRegex,timeRegex); #import sys; sys.exit() # date followed (optionally) by time flags = re.VERBOSE | re.IGNORECASE parseDateTime.dt_regex = re.compile( r'(?P<date>%(dateRegex)s)(?:%(delim)s(?P<time>%(timeRegex)s))?' % locals(), flags) # or vice versa parseDateTime.td_regex = re.compile( r'(?P<time>%(timeRegex)s)(?:%(delim)s(?P<date>%(dateRegex)s))?' % locals(), flags) date = time = None match = parseDateTime.dt_regex.match(string.strip()) \ or parseDateTime.td_regex.search(string.strip()) if match: # parse date if match.group("date"): triple = [match.group(i) for i in ('D1','D2','D3')] if triple[-1] is None: # 2 date elements given; # assume that these are day and month, and add current year triple[-1] = str(localtime()[0]) date = _parseDate(triple, USA) else: t = today(); date = (t.year,t.month,t.day) # parse time if match.group("time"): hour,minute = [int(match.group(i)) for i in ("hour","minute")] ampm = match.group("ampm") if ampm is not None and ampm.lower()=='pm': hour += 12 try: second = float(match.group("second")) except: second = 0.0 if 0<=hour<=23 and 0<=minute<=59 and 0.0<=second<60.0: time = (hour,minute,second) else: time = () if date is not None and time is not None: return datetime(*(date+time)) else: raise ValueError("Unrecognized date/time: %r" % string)
def mxToday(): #from mx.DateTime import * #return now() return today()
def LastTodayTime(): return today() + TimeDelta(hours=23, minutes=59, seconds=59)
def parseDateTime(string, USA=False): '''Tries to parse a string as a valid date and/or time. It recognizes most common formats: @param USA: Disambiguates strings that are valid dates either in (month,day,year) or (day,month,year) order (e.g. 05/03/2002). If True, the first format is assumed; the default is the second. @return: A C{datetime.datetime} instance that represents the parsed string. @rtype: datetime.datetime @raise ValueError: If the string cannot be interpreted successfully. ''' # create the regexps only the first time this function is called if not hasattr(parseDateTime, "regex"): item = lambda groupid: r'(?P<%s>\d+|[a-zA-Z]+)' % groupid delim = r'[\s\\/,-.]+' # negative lookahead/lookbehind assertions on ':' (to prevent mix # with time); also negative lookbehind on \w dateRegex = "(?<!:|\w)%s%s%s(?:%s%s)?(?!:)" % ( item('D1'), delim, item('D2'), delim, item('D3')) timeRegex = r'''(?P<hour>\d{1,2}): # hour (?P<minute>\d{1,2}) # minute (?::(?P<second>\d{1,2}(?:\.\d+)?))? # second (?:\ ?(?P<ampm>[ap]m))? # 'am', 'pm' ''' #print r'(?P<date>%s)\s+(?P<time>%s)?' % (dateRegex,timeRegex); #import sys; sys.exit() # date followed (optionally) by time flags = re.VERBOSE | re.IGNORECASE parseDateTime.dt_regex = re.compile( r'(?P<date>%(dateRegex)s)(?:%(delim)s(?P<time>%(timeRegex)s))?' % locals(), flags) # or vice versa parseDateTime.td_regex = re.compile( r'(?P<time>%(timeRegex)s)(?:%(delim)s(?P<date>%(dateRegex)s))?' % locals(), flags) date = time = None match = parseDateTime.dt_regex.match(string.strip()) \ or parseDateTime.td_regex.search(string.strip()) if match: # parse date if match.group("date"): triple = [match.group(i) for i in ('D1', 'D2', 'D3')] if triple[-1] is None: # 2 date elements given; # assume that these are day and month, and add current year triple[-1] = str(localtime()[0]) date = _parseDate(triple, USA) else: t = today() date = (t.year, t.month, t.day) # parse time if match.group("time"): hour, minute = [int(match.group(i)) for i in ("hour", "minute")] ampm = match.group("ampm") if ampm is not None and ampm.lower() == 'pm': hour += 12 try: second = float(match.group("second")) except: second = 0.0 if 0 <= hour <= 23 and 0 <= minute <= 59 and 0.0 <= second < 60.0: time = (hour, minute, second) else: time = () if date is not None and time is not None: return datetime(*(date + time)) else: raise ValueError("Unrecognized date/time: %r" % string)