in hgext/pushlog/parsedatetime/__init__.py [0:0]
def _evalModifier(self, modifier, chunk1, chunk2, sourceTime):
"""
Evaluate the C{modifier} string and following text (passed in
as C{chunk1} and C{chunk2}) and if they match any known modifiers
calculate the delta and apply it to C{sourceTime}.
@type modifier: string
@param modifier: modifier text to apply to sourceTime
@type chunk1: string
@param chunk1: text chunk that preceded modifier (if any)
@type chunk2: string
@param chunk2: text chunk that followed modifier (if any)
@type sourceTime: struct_time
@param sourceTime: C{struct_time} value to use as the base
@rtype: tuple
@return: tuple of: remaining text and the modified sourceTime
"""
ctx = self.currentContext
offset = self.ptc.Modifiers[modifier]
if sourceTime is not None:
(yr, mth, dy, hr, mn, sec, wd, yd, isdst) = sourceTime
else:
(yr, mth, dy, hr, mn, sec, wd, yd, isdst) = time.localtime()
if self.ptc.StartTimeFromSourceTime:
startHour = hr
startMinute = mn
startSecond = sec
else:
startHour = 9
startMinute = 0
startSecond = 0
# capture the units after the modifier and the remaining
# string after the unit
m = self.ptc.CRE_REMAINING.search(chunk2)
if m is not None:
index = m.start() + 1
unit = chunk2[:m.start()]
chunk2 = chunk2[index:]
else:
unit = chunk2
chunk2 = ''
debug and log.debug("modifier [%s] chunk1 [%s] "
"chunk2 [%s] unit [%s]",
modifier, chunk1, chunk2, unit)
if unit in self.ptc.units['months']:
currentDaysInMonth = self.ptc.daysInMonth(mth, yr)
if offset == 0:
dy = currentDaysInMonth
sourceTime = (yr, mth, dy, startHour, startMinute,
startSecond, wd, yd, isdst)
elif offset == 2:
# if day is the last day of the month, calculate the last day
# of the next month
if dy == currentDaysInMonth:
dy = self.ptc.daysInMonth(mth + 1, yr)
start = datetime.datetime(yr, mth, dy, startHour,
startMinute, startSecond)
target = self.inc(start, month=1)
sourceTime = target.timetuple()
else:
start = datetime.datetime(yr, mth, 1, startHour,
startMinute, startSecond)
target = self.inc(start, month=offset)
sourceTime = target.timetuple()
ctx.updateAccuracy(ctx.ACU_MONTH)
elif unit in self.ptc.units['weeks']:
if offset == 0:
start = datetime.datetime(yr, mth, dy, 17, 0, 0)
target = start + datetime.timedelta(days=(4 - wd))
sourceTime = target.timetuple()
elif offset == 2:
start = datetime.datetime(yr, mth, dy, startHour,
startMinute, startSecond)
target = start + datetime.timedelta(days=7)
sourceTime = target.timetuple()
else:
start = datetime.datetime(yr, mth, dy, startHour,
startMinute, startSecond)
target = start + offset * datetime.timedelta(weeks=1)
sourceTime = target.timetuple()
ctx.updateAccuracy(ctx.ACU_WEEK)
elif unit in self.ptc.units['days']:
if offset == 0:
sourceTime = (yr, mth, dy, 17, 0, 0, wd, yd, isdst)
ctx.updateAccuracy(ctx.ACU_HALFDAY)
elif offset == 2:
start = datetime.datetime(yr, mth, dy, hr, mn, sec)
target = start + datetime.timedelta(days=1)
sourceTime = target.timetuple()
else:
start = datetime.datetime(yr, mth, dy, startHour,
startMinute, startSecond)
target = start + datetime.timedelta(days=offset)
sourceTime = target.timetuple()
ctx.updateAccuracy(ctx.ACU_DAY)
elif unit in self.ptc.units['hours']:
if offset == 0:
sourceTime = (yr, mth, dy, hr, 0, 0, wd, yd, isdst)
else:
start = datetime.datetime(yr, mth, dy, hr, 0, 0)
target = start + datetime.timedelta(hours=offset)
sourceTime = target.timetuple()
ctx.updateAccuracy(ctx.ACU_HOUR)
elif unit in self.ptc.units['years']:
if offset == 0:
sourceTime = (yr, 12, 31, hr, mn, sec, wd, yd, isdst)
elif offset == 2:
sourceTime = (yr + 1, mth, dy, hr, mn, sec, wd, yd, isdst)
else:
sourceTime = (yr + offset, 1, 1, startHour, startMinute,
startSecond, wd, yd, isdst)
ctx.updateAccuracy(ctx.ACU_YEAR)
elif modifier == 'eom':
dy = self.ptc.daysInMonth(mth, yr)
sourceTime = (yr, mth, dy, startHour, startMinute,
startSecond, wd, yd, isdst)
ctx.updateAccuracy(ctx.ACU_DAY)
elif modifier == 'eoy':
mth = 12
dy = self.ptc.daysInMonth(mth, yr)
sourceTime = (yr, mth, dy, startHour, startMinute,
startSecond, wd, yd, isdst)
ctx.updateAccuracy(ctx.ACU_MONTH)
elif self.ptc.CRE_WEEKDAY.match(unit):
m = self.ptc.CRE_WEEKDAY.match(unit)
debug and log.debug('CRE_WEEKDAY matched')
wkdy = m.group()
if modifier == 'eod':
ctx.updateAccuracy(ctx.ACU_HOUR)
# Calculate the upcoming weekday
sourceTime, subctx = self.parse(wkdy, sourceTime,
VERSION_CONTEXT_STYLE)
sTime = self.ptc.getSource(modifier, sourceTime)
if sTime is not None:
sourceTime = sTime
ctx.updateAccuracy(ctx.ACU_HALFDAY)
else:
# unless one of these modifiers is being applied to the
# day-of-week, we want to start with target as the day
# in the current week.
dowOffset = offset
relativeModifier = modifier not in ['this', 'next', 'last', 'prior', 'previous']
if relativeModifier:
dowOffset = 0
wkdy = self.ptc.WeekdayOffsets[wkdy]
diff = self._CalculateDOWDelta(
wd, wkdy, dowOffset, self.ptc.DOWParseStyle,
self.ptc.CurrentDOWParseStyle)
start = datetime.datetime(yr, mth, dy, startHour,
startMinute, startSecond)
target = start + datetime.timedelta(days=diff)
if chunk1 != '' and relativeModifier:
# consider "one day before thursday": we need to parse chunk1 ("one day")
# and apply according to the offset ("before"), rather than allowing the
# remaining parse step to apply "one day" without the offset direction.
t, subctx = self.parse(chunk1, sourceTime, VERSION_CONTEXT_STYLE)
if subctx.hasDateOrTime:
delta = time.mktime(t) - time.mktime(sourceTime)
target = start + datetime.timedelta(days=diff) + datetime.timedelta(seconds=delta * offset)
chunk1 = ''
sourceTime = target.timetuple()
ctx.updateAccuracy(ctx.ACU_DAY)
elif chunk1 == '' and chunk2 == '' and self.ptc.CRE_TIME.match(unit):
m = self.ptc.CRE_TIME.match(unit)
debug and log.debug('CRE_TIME matched')
(yr, mth, dy, hr, mn, sec, wd, yd, isdst), subctx = \
self.parse(unit, None, VERSION_CONTEXT_STYLE)
start = datetime.datetime(yr, mth, dy, hr, mn, sec)
target = start + datetime.timedelta(days=offset)
sourceTime = target.timetuple()
else:
# check if the remaining text is parsable and if so,
# use it as the base time for the modifier source time
debug and log.debug('check for modifications '
'to source time [%s] [%s]',
chunk1, unit)
unit = unit.strip()
if unit:
s = '%s %s' % (unit, chunk2)
t, subctx = self.parse(s, sourceTime, VERSION_CONTEXT_STYLE)
if subctx.hasDate: # working with dates
u = unit.lower()
if u in self.ptc.Months or \
u in self.ptc.shortMonths:
yr, mth, dy, hr, mn, sec, wd, yd, isdst = t
start = datetime.datetime(
yr, mth, dy, hr, mn, sec)
t = self.inc(start, year=offset).timetuple()
elif u in self.ptc.Weekdays:
t = t + datetime.timedelta(weeks=offset)
if subctx.hasDateOrTime:
sourceTime = t
chunk2 = ''
chunk1 = chunk1.strip()
# if the word after next is a number, the string is more than
# likely to be "next 4 hrs" which we will have to combine the
# units with the rest of the string
if chunk1:
try:
m = list(self.ptc.CRE_NUMBER.finditer(chunk1))[-1]
except IndexError:
pass
else:
qty = None
debug and log.debug('CRE_NUMBER matched')
qty = self._quantityToReal(m.group()) * offset
chunk1 = '%s%s%s' % (chunk1[:m.start()],
qty, chunk1[m.end():])
t, subctx = self.parse(chunk1, sourceTime,
VERSION_CONTEXT_STYLE)
chunk1 = ''
if subctx.hasDateOrTime:
sourceTime = t
debug and log.debug('looking for modifier %s', modifier)
sTime = self.ptc.getSource(modifier, sourceTime)
if sTime is not None:
debug and log.debug('modifier found in sources')
sourceTime = sTime
ctx.updateAccuracy(ctx.ACU_HALFDAY)
debug and log.debug('returning chunk = "%s %s" and sourceTime = %s',
chunk1, chunk2, sourceTime)
return '%s %s' % (chunk1, chunk2), sourceTime