def adjust(self, to): """ Adjusts the time from kwargs to timedelta **Will change this object** return new copy of self """ if self.date == "infinity": return new = copy(self) if type(to) in (str, unicode): to = to.lower() res = TIMESTRING_RE.search(to) if res: rgroup = res.groupdict() if rgroup.get("delta") or rgroup.get("delta_2"): i = int(text2num(rgroup.get("num", "one"))) * (-1 if to.startswith("-") else 1) delta = (rgroup.get("delta") or rgroup.get("delta_2")).lower() if delta.startswith("y"): try: new.date = new.date.replace(year=(new.date.year + i)) except ValueError: # day is out of range for month new.date = new.date + timedelta(days=(365 * i)) elif delta.startswith("month"): if (new.date.month + i) > 12: new.date = new.date.replace(month=(i - (i / 12)), year=(new.date.year + 1 + (i / 12))) elif (new.date.month + i) < 1: new.date = new.date.replace(month=12, year=(new.date.year - 1)) else: new.date = new.date.replace(month=(new.date.month + i)) elif delta.startswith("q"): # NP pass elif delta.startswith("w"): new.date = new.date + timedelta(days=(7 * i)) elif delta.startswith("s"): new.date = new.date + timedelta(seconds=i) else: new.date = new.date + timedelta( **{ ( "days" if delta.startswith("d") else "hours" if delta.startswith("h") else "minutes" if delta.startswith("m") else "seconds" ): i } ) return new else: new.date = new.date + timedelta(seconds=int(to)) return new raise TimestringInvalid("Invalid addition request")
def adjust(self, to): ''' Adjusts the time from kwargs to timedelta **Will change this object** return new copy of self ''' if self.date == 'infinity': return new = copy(self) if type(to) in (str, unicode): to = to.lower() res = TIMESTRING_RE.search(to) if res: rgroup = res.groupdict() if (rgroup.get('delta') or rgroup.get('delta_2')): i = int(text2num(rgroup.get( 'num', 'one'))) * (-1 if to.startswith('-') else 1) delta = (rgroup.get('delta') or rgroup.get('delta_2')).lower() if delta.startswith('y'): try: new.date = new.date.replace(year=(new.date.year + i)) except ValueError: # day is out of range for month new.date = new.date + timedelta(days=(365 * i)) elif delta.startswith('month'): if (new.date.month + i) > 12: new.date = new.date.replace(month=(i - (i / 12)), year=(new.date.year + 1 + (i / 12))) elif (new.date.month + i) < 1: new.date = new.date.replace(month=12, year=(new.date.year - 1)) else: new.date = new.date.replace(month=(new.date.month + i)) elif delta.startswith('q'): # NP pass elif delta.startswith('w'): new.date = new.date + timedelta(days=(7 * i)) elif delta.startswith('s'): new.date = new.date + timedelta(seconds=i) else: new.date = new.date + timedelta( **{ ('days' if delta.startswith('d') else 'hours' if delta.startswith('h') else 'minutes' if delta.startswith('m') else 'seconds'): i }) return new else: new.date = new.date + timedelta(seconds=int(to)) return new raise TimestringInvalid('Invalid addition request')
def test_word_boundaries(self): res = ts.search('next mon') self.assertNotEqual(res, None) res = ts.search('santa monica') self.assertEqual(res, None) res = ts.search('tuesday two weeks ago') self.assertNotEqual(res, None) res = ts.search('fri') self.assertNotEqual(res, None) res = ts.search('dec') self.assertNotEqual(res, None) res = ts.search('Current weather in East hanover new jersey') self.assertEqual(res, None) res = ts.search('august') self.assertNotEqual(res, None) res = ts.search('23rd feb 9:35pm') self.assertNotEqual(res, None)
def adjust(self, to): ''' Adjusts the time from kwargs to timedelta **Will change this object** return new copy of self ''' if self.date == 'infinity': return new = copy(self) if type(to) in (str, unicode): to = to.lower() res = TIMESTRING_RE.search(to) if res: rgroup = res.groupdict() if (rgroup.get('delta') or rgroup.get('delta_2')): i = int(string_to_number(rgroup.get('num', 1))) * (-1 if to.startswith('-') else 1) delta = (rgroup.get('delta') or rgroup.get('delta_2')).lower() if delta.startswith('y'): try: new.date = new.date.replace(year=(new.date.year + i)) except ValueError: # day is out of range for month new.date = new.date + timedelta(days=(365 * i)) elif delta.startswith('month'): if (new.date.month + i) > 12: new.date = new.date.replace(month=(i - (i / 12)), year=(new.date.year + 1 + (i / 12))) elif (new.date.month + i) < 1: new.date = new.date.replace(month=12, year=(new.date.year - 1)) else: new.date = new.date.replace(month=(new.date.month + i)) elif delta.startswith('q'): # NP pass elif delta.startswith('w'): new.date = new.date + timedelta(days=(7 * i)) else: new.date = new.date + timedelta(**{('days' if delta.startswith('d') else 'hours' if delta.startswith('h') else 'minutes' if delta.startswith('m') else 'seconds'): i}) return new else: new.date = new.date + timedelta(seconds=int(to)) return new raise TimestringInvalid('Invalid addition request')
def __init__(self, date, offset=None, start_of_week=None, tz=None, verbose=False): if isinstance(date, Date): self.date = copy(date.date) return # The original request self._original = date if tz: tz = pytz.timezone(str(tz)) if date == 'infinity': self.date = 'infinity' elif date == 'now': self.date = datetime.now() elif type(date) in (str, unicode) and re.match( r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+-\d{2}", date): self.date = datetime.strptime( date[:-3], "%Y-%m-%d %H:%M:%S.%f") - timedelta(hours=int(date[-3:])) else: # Determinal starting date. if type(date) in (str, unicode): """The date is a string and needs to be converted into a <dict> for processesing """ _date = date.lower() res = TIMESTRING_RE.search(_date.strip()) if res: date = res.groupdict() if verbose: print( "Matches:\n", ''.join([ "\t%s: %s\n" % (k, v) for k, v in date.items() if v ])) else: raise TimestringInvalid('Invalid date string >> %s' % date) date = dict((k, v if type(v) is str else v) for k, v in date.items() if v) #print(_date, dict(map(lambda a: (a, date.get(a)), filter(lambda a: date.get(a), date)))) if isinstance(date, dict): # Initial date. new_date = datetime(*time.localtime()[:3]) if tz and tz.zone != "UTC": # # The purpose here is to adjust what day it is based on the timezeone # ts = datetime.now() # Daylight savings === second Sunday in March and reverts to standard time on the first Sunday in November # Monday is 0 and Sunday is 6. # 14 days - dst_start.weekday() dst_start = datetime( ts.year, 3, 1, 2, 0, 0) + timedelta(13 - datetime(ts.year, 3, 1).weekday()) dst_end = datetime( ts.year, 11, 1, 2, 0, 0) + timedelta(6 - datetime(ts.year, 11, 1).weekday()) ts = ts + tz.utcoffset(new_date, is_dst=(dst_start < ts < dst_end)) new_date = datetime(ts.year, ts.month, ts.day) if date.get('unixtime'): new_date = datetime.fromtimestamp(int( date.get('unixtime'))) # !number of (days|...) (ago)? elif date.get('num') and (date.get('delta') or date.get('delta_2')): if date.get('num', '').find('couple') > -1: i = 2 * int(1 if date.get('ago', True) or date.get('ref') == 'last' else -1) else: i = int(text2num(date.get( 'num', 'one'))) * int(1 if date.get('ago') or ( date.get('ref', '') or '') == 'last' else -1) delta = (date.get('delta') or date.get('delta_2')).lower() if delta.startswith('y'): try: new_date = new_date.replace(year=(new_date.year - i)) # day is out of range for month except ValueError: new_date = new_date - timedelta(days=(365 * i)) elif delta.startswith('month'): try: new_date = new_date.replace(month=(new_date.month - i)) # day is out of range for month except ValueError: new_date = new_date - timedelta(days=(30 * i)) elif delta.startswith('q'): ''' This section is not working... Most likely need a generator that will take me to the right quater. ''' q1, q2, q3, q4 = datetime( new_date.year, 1, 1), datetime(new_date.year, 4, 1), datetime( new_date.year, 7, 1), datetime(new_date.year, 10, 1) if q1 <= new_date < q2: # We are in Q1 if i == -1: new_date = datetime(new_date.year - 1, 10, 1) else: new_date = q2 elif q2 <= new_date < q3: # We are in Q2 pass elif q3 <= new_date < q4: # We are in Q3 pass else: # We are in Q4 pass new_date = new_date - timedelta(days=(91 * i)) elif delta.startswith('w'): new_date = new_date - timedelta(days=(i * 7)) else: new_date = new_date - timedelta( **{ ('days' if delta.startswith('d') else 'hours' if delta.startswith('h') else 'minutes' if delta.startswith('m') else 'seconds'): i }) # !dow if [ date.get(key) for key in ('day', 'day_2', 'day_3') if date.get(key) ]: dow = max([ date.get(key) for key in ('day', 'day_2', 'day_3') if date.get(key) ]) iso = dict(monday=1, tuesday=2, wednesday=3, thursday=4, friday=5, saturday=6, sunday=7, mon=1, tue=2, tues=2, wed=3, wedn=3, thu=4, thur=4, fri=5, sat=6, sun=7).get(dow) if iso: # determin which direction if date.get('ref') not in ('this', 'next'): days = iso - new_date.isoweekday() - ( 7 if iso >= new_date.isoweekday() else 0) else: days = iso - new_date.isoweekday() + ( 7 if iso < new_date.isoweekday() else 0) new_date = new_date + timedelta(days=days) elif dow == 'yesterday': new_date = new_date - timedelta(days=1) elif dow == 'tomorrow': new_date = new_date + timedelta(days=1) # !year year = [ int(CLEAN_NUMBER.sub('', date[key])) for key in ('year', 'year_2', 'year_3', 'year_4', 'year_5', 'year_6') if date.get(key) ] if year: year = max(year) if len(str(year)) != 4: year += 2000 if year <= 40 else 1900 try: new_date = new_date.replace(year=year) except Exception: new_date = new_date.replace(year=year, day=28) # !month month = [ date.get(key) for key in ('month', 'month_1', 'month_2', 'month_3', 'month_4') if date.get(key) ] if month: new_date = new_date.replace(day=1) new_date = new_date.replace( month=int(max(month)) if re.match('^\d+$', max(month)) else dict(january=1, february=2, march=3, april=4, june=6, july=7, august=8, september=9, october=10, november=11, december=12, jan=1, feb=2, mar=3, apr=4, may=5, jun=6, jul=7, aug=8, sep=9, sept=9, oct=10, nov=11, dec=12).get(max(month), new_date.month)) # !day day = [ date.get(key) for key in ('date', 'date_2', 'date_3') if date.get(key) ] if day: new_date = new_date.replace(day=int(max(day))) # !daytime if date.get('daytime'): if date['daytime'].find('this time') >= 1: new_date = new_date.replace( hour=datetime(*time.localtime()[:5]).hour, minute=datetime(*time.localtime()[:5]).minute) else: new_date = new_date.replace(hour=dict( morning=9, noon=12, afternoon=15, evening=18, night=21, nighttime=21, midnight=24).get(date.get('daytime'), 12)) # No offset because the hour was set. offset = False # !hour hour = [ date.get(key) for key in ('hour', 'hour_2', 'hour_3') if date.get(key) ] if hour: new_date = new_date.replace(hour=int(max(hour))) am = [ date.get(key) for key in ('am', 'am_1') if date.get(key) ] if am and max(am) in ('p', 'pm'): h = int(max(hour)) if h < 12: new_date = new_date.replace(hour=h + 12) # No offset because the hour was set. offset = False #minute minute = [ date.get(key) for key in ('minute', 'minute_2') if date.get(key) ] if minute: new_date = new_date.replace(minute=int(max(minute))) #second seconds = date.get('seconds', 0) if seconds: new_date = new_date.replace(second=int(seconds)) self.date = new_date elif type(date) in (int, long, float) and re.match( '^\d{10}$', str(date)): self.date = datetime.fromtimestamp(int(date)) elif isinstance(date, datetime): self.date = date elif date is None: self.date = datetime.now() else: # Set to the current date Y, M, D, H0, M0, S0 self.date = datetime(*time.localtime()[:3]) if tz: self.date = self.date.replace(tzinfo=tz) # end if type(date) is types.DictType: and self.date.hour == 0: if offset and isinstance(offset, dict): self.date = self.date.replace(**offset)
def __init__(self, date, offset=None, start_of_week=None, tz=None, verbose=False): if isinstance(date, Date): self.date = copy(date.date) return # The original request self._original = date if tz: tz = pytz.timezone(str(tz)) if date == 'infinity': self.date = 'infinity' elif date == 'now': self.date = datetime.now() elif type(date) in (str, unicode) and re.match(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+-\d{2}", date): self.date = datetime.strptime(date[:-3], "%Y-%m-%d %H:%M:%S.%f") - timedelta(hours=int(date[-3:])) else: # Determinal starting date. if type(date) in (str, unicode): """The date is a string and needs to be converted into a <dict> for processesing """ _date = date.lower() res = TIMESTRING_RE.search(_date.strip()) if res: date = res.groupdict() if verbose: print("Matches:\n", ''.join(["\t%s: %s\n" % (k, v) for k, v in date.items() if v])) else: raise TimestringInvalid('Invlid date string >> %s' % date) date = dict((k, v if type(v) is str else v) for k, v in date.items() if v) #print(_date, dict(map(lambda a: (a, date.get(a)), filter(lambda a: date.get(a), date)))) if isinstance(date, dict): # Initial date. new_date = datetime(*time.localtime()[:3]) if tz and tz.zone != "UTC": # # The purpose here is to adjust what day it is based on the timezeone # ts = datetime.now() # Daylight savings === second Sunday in March and reverts to standard time on the first Sunday in November # Monday is 0 and Sunday is 6. # 14 days - dst_start.weekday() dst_start = datetime(ts.year, 3, 1, 2, 0, 0) + timedelta(13 - datetime(ts.year, 3, 1).weekday()) dst_end = datetime(ts.year, 11, 1, 2, 0, 0) + timedelta(6 - datetime(ts.year, 11, 1).weekday()) ts = ts + tz.utcoffset(new_date, is_dst=(dst_start < ts < dst_end)) new_date = datetime(ts.year, ts.month, ts.day) if date.get('unixtime'): new_date = datetime.fromtimestamp(int(date.get('unixtime'))) # !number of (days|...) (ago)? elif date.get('num') and (date.get('delta') or date.get('delta_2')): if date.get('num', '').find('couple') > -1: i = 2 * int(1 if date.get('ago', True) or date.get('ref') == 'last' else -1) else: i = int(string_to_number(date.get('num', 1))) * int(1 if date.get('ago') or (date.get('ref', '') or '') == 'last' else -1) delta = (date.get('delta') or date.get('delta_2')).lower() if delta.startswith('y'): try: new_date = new_date.replace(year=(new_date.year - i)) # day is out of range for month except ValueError: new_date = new_date - timedelta(days=(365*i)) elif delta.startswith('month'): try: new_date = new_date.replace(month=(new_date.month - i)) # day is out of range for month except ValueError: new_date = new_date - timedelta(days=(30*i)) elif delta.startswith('q'): ''' This section is not working... Most likely need a generator that will take me to the right quater. ''' q1, q2, q3, q4 = datetime(new_date.year, 1, 1), datetime(new_date.year, 4, 1), datetime(new_date.year, 7, 1), datetime(new_date.year, 10, 1) if q1 <= new_date < q2: # We are in Q1 if i == -1: new_date = datetime(new_date.year-1, 10, 1) else: new_date = q2 elif q2 <= new_date < q3: # We are in Q2 pass elif q3 <= new_date < q4: # We are in Q3 pass else: # We are in Q4 pass new_date = new_date - timedelta(days=(91*i)) elif delta.startswith('w'): new_date = new_date - timedelta(days=(i * 7)) else: new_date = new_date - timedelta(**{('days' if delta.startswith('d') else 'hours' if delta.startswith('h') else 'minutes' if delta.startswith('m') else 'seconds'): i}) # !dow if [date.get(key) for key in ('day', 'day_2', 'day_3') if date.get(key)]: dow = max([date.get(key) for key in ('day', 'day_2', 'day_3') if date.get(key)]) iso = dict(monday=1, tuesday=2, wednesday=3, thursday=4, friday=5, saturday=6, sunday=7, mon=1, tue=2, tues=2, wed=3, wedn=3, thu=4, thur=4, fri=5, sat=6, sun=7).get(dow) if iso: # determin which direction if date.get('ref') not in ('this', 'next'): days = iso - new_date.isoweekday() - (7 if iso >= new_date.isoweekday() else 0) else: days = iso - new_date.isoweekday() + (7 if iso < new_date.isoweekday() else 0) new_date = new_date + timedelta(days=days) elif dow == 'yesterday': new_date = new_date - timedelta(days=1) elif dow == 'tomorrow': new_date = new_date + timedelta(days=1) # !year year = [date.get(key) for key in ('year', 'year_2', 'year_3', 'year_4', 'year_5', 'year_6') if date.get(key)] if year: y = int(max(year)) if len(str(y)) != 4: y += 2000 if y <= 40 else 1900 new_date = new_date.replace(year=y) # !month month = [date.get(key) for key in ('month', 'month_1', 'month_2', 'month_3', 'month_4') if date.get(key)] if month: new_date = new_date.replace(day=1) new_date = new_date.replace(month=int(max(month)) if re.match('^\d+$', max(month)) else dict(january=1, february=2, march=3, april=4, june=6, july=7, august=8, september=9, october=10, november=11, december=12, jan=1, feb=2, mar=3, apr=4, may=5, jun=6, jul=7, aug=8, sep=9, sept=9, oct=10, nov=11, dec=12).get(max(month), new_date.month)) # !day day = [date.get(key) for key in ('date', 'date_2', 'date_3') if date.get(key)] if day: new_date = new_date.replace(day=int(max(day))) # !daytime if date.get('daytime'): if date['daytime'].find('this time') >= 1: new_date = new_date.replace(hour=datetime(*time.localtime()[:5]).hour, minute=datetime(*time.localtime()[:5]).minute) else: new_date = new_date.replace(hour=dict(morning=9, noon=12, afternoon=15, evening=18, night=21, nighttime=21, midnight=24).get(date.get('daytime'), 12)) # No offset because the hour was set. offset = False # !hour hour = [date.get(key) for key in ('hour', 'hour_2', 'hour_3') if date.get(key)] if hour: new_date = new_date.replace(hour=int(max(hour))) am = [date.get(key) for key in ('am', 'am_1') if date.get(key)] if am and max(am) in ('p', 'pm'): new_date = new_date.replace(hour=int(max(hour))+12) # No offset because the hour was set. offset = False #minute minute = [date.get(key) for key in ('minute', 'minute_2') if date.get(key)] if minute: new_date = new_date.replace(minute=int(max(minute))) #second seconds = date.get('seconds', 0) if seconds: new_date = new_date.replace(second=int(seconds)) self.date = new_date elif type(date) in (int, long, float) and re.match('^\d{10}$', str(date)): self.date = datetime.fromtimestamp(int(date)) elif isinstance(date, datetime): self.date = date elif date is None: self.date = datetime.now() else: # Set to the current date Y, M, D, H0, M0, S0 self.date = datetime(*time.localtime()[:3]) if tz: self.date = self.date.replace(tzinfo=tz) # end if type(date) is types.DictType: and self.date.hour == 0: if offset and isinstance(offset, dict): self.date = self.date.replace(**offset)
def __init__(self, start, end=None, offset=None, start_of_week=0, tz=None, verbose=False): """`start` can be type <class timestring.Date> or <type str> """ self._dates = [] pgoffset = None if start is None: raise TimestringInvalid("Range object requires a start valie") if not isinstance(start, (Date, datetime)): start = str(start) if end and not isinstance(end, (Date, datetime)): end = str(end) if start and end: """start and end provided """ self._dates = (Date(start, tz=tz), Date(end, tz=tz)) elif start == 'infinity': # end was not provided self._dates = (Date('infinity'), Date('infinity')) elif re.search(r'(\s(and|to)\s)', start): """Both sides where provided in the start """ start = re.sub('^(between|from)\s', '', start.lower()) # Both arguments found in start variable r = tuple(re.split(r'(\s(and|to)\s)', start.strip())) self._dates = (Date(r[0], tz=tz), Date(r[-1], tz=tz)) elif re.match( r"(\[|\()((\"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?(\+|\-)\d{2}\")|infinity),((\"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?(\+|\-)\d{2}\")|infinity)(\]|\))", start): """postgresql tsrange and tstzranges support """ start, end = tuple( re.sub('[^\w\s\-\:\.\+\,]', '', start).split(',')) self._dates = (Date(start), Date(end)) else: now = datetime.now() # no tz info but offset provided, we are UTC so convert if re.search(r"(\+|\-)\d{2}$", start): # postgresql tsrange and tstzranges pgoffset = re.search(r"(\+|\-)\d{2}$", start).group() + " hours" # tz info provided if tz: now = now.replace(tzinfo=pytz.timezone(str(tz))) # Parse res = TIMESTRING_RE.search(start) if res: group = res.groupdict() if verbose: print( dict( map(lambda a: (a, group.get(a)), filter(lambda a: group.get(a), group)))) if (group.get('delta') or group.get('delta_2')) is not None: delta = (group.get('delta') or group.get('delta_2')).lower() # always start w/ today start = Date("today", offset=offset, tz=tz) # make delta di = "%s %s" % (str(int(group['num'] or 1)), delta) # this [ x ] if group['ref'] == 'this': if delta.startswith('y'): start = Date(datetime(now.year, 1, 1), offset=offset, tz=tz) # month elif delta.startswith('month'): start = Date(datetime(now.year, now.month, 1), offset=offset, tz=tz) # week elif delta.startswith('w'): start = Date("today", offset=offset, tz=tz) - (str( Date("today", tz=tz).date.weekday()) + ' days') # day elif delta.startswith('d'): start = Date("today", offset=offset, tz=tz) # hour elif delta.startswith('h'): start = Date("today", offset=dict(hour=now.hour + 1), tz=tz) # minute, second elif delta.startswith('m') or delta.startswith('s'): start = Date("now", tz=tz) else: raise TimestringInvalid( "Not a valid time reference") end = start + di #next x [ ] elif group['ref'] == 'next': if int(group['num'] or 1) > 1: di = "%s %s" % (str(int(group['num'] or 1) - 1), delta) end = start + di # ago [ ] x elif group.get('ago') or group['ref'] == 'last' and int( group['num'] or 1) == 1: #if group['ref'] == 'last' and int(group['num'] or 1) == 1: # start = start - ('1 ' + delta) end = start - di # last & no ref [ x] else: # need to include today with this reference if not (delta.startswith('h') or delta.startswith('m') or delta.startswith('s')): start = Range('today', offset=offset, tz=tz).end end = start - di elif group.get('month_1'): # a single month of this yeear start = Date(start, offset=offset, tz=tz) start = start.replace(day=1) end = start + '1 month' elif group.get('year_5'): # a whole year start = Date(start, offset=offset, tz=tz) start = start.replace(day=1, month=1) end = start + '1 year' else: # after all else, we set the end to + 1 day start = Date(start, offset=offset, tz=tz) end = start + '1 day' else: raise TimestringInvalid("Invalid timestring request") if end is None: # no end provided, so assume 24 hours end = start + '24 hours' if start > end: # flip them if this is so start, end = copy(end), copy(start) if pgoffset: start = start - pgoffset if end != 'infinity': end = end - pgoffset self._dates = (start, end) if self._dates[0] > self._dates[1]: self._dates = (self._dates[0], self._dates[1] + '1 day')
def __init__(self, start, end=None, offset=None, start_of_week=0, tz=None, verbose=False): """`start` can be type <class timestring.Date> or <type str> """ self._dates = [] pgoffset = None if start is None: raise TimestringInvalid("Range object requires a start valie") if not isinstance(start, (Date, datetime)): start = str(start) if end and not isinstance(end, (Date, datetime)): end = str(end) if start and end: """start and end provided """ self._dates = (Date(start, tz=tz), Date(end, tz=tz)) elif start == 'infinity': # end was not provided self._dates = (Date('infinity'), Date('infinity')) elif re.search(r'(\s(and|to)\s)', start): """Both sides where provided in the start """ start = re.sub('^(between|from)\s', '', start.lower()) # Both arguments found in start variable r = tuple(re.split(r'(\s(and|to)\s)', start.strip())) self._dates = (Date(r[0], tz=tz), Date(r[-1], tz=tz)) elif re.match(r"(\[|\()((\"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?(\+|\-)\d{2}\")|infinity),((\"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?(\+|\-)\d{2}\")|infinity)(\]|\))", start): """postgresql tsrange and tstzranges support """ start, end = tuple(re.sub('[^\w\s\-\:\.\+\,]', '', start).split(',')) self._dates = (Date(start), Date(end)) else: now = datetime.now() # no tz info but offset provided, we are UTC so convert if re.search(r"(\+|\-)\d{2}$", start): # postgresql tsrange and tstzranges pgoffset = re.search(r"(\+|\-)\d{2}$", start).group() + " hours" # tz info provided if tz: now = now.replace(tzinfo=pytz.timezone(str(tz))) # Parse res = TIMESTRING_RE.search(start) if res: group = res.groupdict() if verbose: print(dict(map(lambda a: (a, group.get(a)), filter(lambda a: group.get(a), group)))) if (group.get('delta') or group.get('delta_2')) is not None: delta = (group.get('delta') or group.get('delta_2')).lower() # always start w/ today start = Date("today", offset=offset, tz=tz) # make delta di = "%s %s" % (str(int(group['num'] or 1)), delta) # this [ x ] if group['ref'] == 'this': if delta.startswith('y'): start = Date(datetime(now.year, 1, 1), offset=offset, tz=tz) # month elif delta.startswith('month'): start = Date(datetime(now.year, now.month, 1), offset=offset, tz=tz) # week elif delta.startswith('w'): start = Date("today", offset=offset, tz=tz) - (str(Date("today", tz=tz).date.weekday())+' days') # day elif delta.startswith('d'): start = Date("today", offset=offset, tz=tz) # hour elif delta.startswith('h'): start = Date("today", offset=dict(hour=now.hour+1), tz=tz) # minute, second elif delta.startswith('m') or delta.startswith('s'): start = Date("now", tz=tz) else: raise TimestringInvalid("Not a valid time reference") end = start + di #next x [ ] elif group['ref'] == 'next': if int(group['num'] or 1) > 1: di = "%s %s" % (str(int(group['num'] or 1) - 1), delta) end = start + di # ago [ ] x elif group.get('ago') or group['ref'] == 'last' and int(group['num'] or 1) == 1: #if group['ref'] == 'last' and int(group['num'] or 1) == 1: # start = start - ('1 ' + delta) end = start - di # last & no ref [ x] else: # need to include today with this reference if not (delta.startswith('h') or delta.startswith('m') or delta.startswith('s')): start = Range('today', offset=offset, tz=tz).end end = start - di elif group.get('month_1'): # a single month of this yeear start = Date(start, offset=offset, tz=tz) start = start.replace(day=1) end = start + '1 month' elif group.get('year_5'): # a whole year start = Date(start, offset=offset, tz=tz) start = start.replace(day=1, month=1) end = start + '1 year' else: # after all else, we set the end to + 1 day start = Date(start, offset=offset, tz=tz) end = start + '1 day' else: raise TimestringInvalid("Invalid timestring request") if end is None: # no end provided, so assume 24 hours end = start + '24 hours' if start > end: # flip them if this is so start, end = copy(end), copy(start) if pgoffset: start = start - pgoffset if end != 'infinity': end = end - pgoffset self._dates = (start, end) if self._dates[0] > self._dates[1]: self._dates = (self._dates[0], self._dates[1] + '1 day')
def __init__(self, date, offset=None, start_of_week=None, tz=None, verbose=False): if isinstance(date, Date): self.date = copy(date.date) return # The original request self._original = date if tz: tz = pytz.timezone(str(tz)) if date == "infinity": self.date = "infinity" elif date == "now": self.date = datetime.now() elif type(date) in (str, unicode) and re.match(r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+-\d{2}", date): self.date = datetime.strptime(date[:-3], "%Y-%m-%d %H:%M:%S.%f") - timedelta(hours=int(date[-3:])) else: # Determinal starting date. if type(date) in (str, unicode): """The date is a string and needs to be converted into a <dict> for processesing """ _date = date.lower() res = TIMESTRING_RE.search(_date.strip()) if res: date = res.groupdict() if verbose: print("Matches:\n", "".join(["\t%s: %s\n" % (k, v) for k, v in date.items() if v])) else: raise TimestringInvalid("Invalid date string >> %s" % date) date = dict((k, v if type(v) is str else v) for k, v in date.items() if v) # print(_date, dict(map(lambda a: (a, date.get(a)), filter(lambda a: date.get(a), date)))) if isinstance(date, dict): # Initial date. new_date = datetime(*time.localtime()[:3]) if tz and tz.zone != "UTC": # # The purpose here is to adjust what day it is based on the timezeone # ts = datetime.now() # Daylight savings === second Sunday in March and reverts to standard time on the first Sunday in November # Monday is 0 and Sunday is 6. # 14 days - dst_start.weekday() dst_start = datetime(ts.year, 3, 1, 2, 0, 0) + timedelta(13 - datetime(ts.year, 3, 1).weekday()) dst_end = datetime(ts.year, 11, 1, 2, 0, 0) + timedelta(6 - datetime(ts.year, 11, 1).weekday()) ts = ts + tz.utcoffset(new_date, is_dst=(dst_start < ts < dst_end)) new_date = datetime(ts.year, ts.month, ts.day) if date.get("unixtime"): new_date = datetime.fromtimestamp(int(date.get("unixtime"))) # !number of (days|...) (ago)? elif date.get("num") and (date.get("delta") or date.get("delta_2")): if date.get("num", "").find("couple") > -1: i = 2 * int(1 if date.get("ago", True) or date.get("ref") == "last" else -1) else: i = int(text2num(date.get("num", "one"))) * int( 1 if date.get("ago") or (date.get("ref", "") or "") == "last" else -1 ) delta = (date.get("delta") or date.get("delta_2")).lower() if delta.startswith("y"): try: new_date = new_date.replace(year=(new_date.year - i)) # day is out of range for month except ValueError: new_date = new_date - timedelta(days=(365 * i)) elif delta.startswith("month"): try: new_date = new_date.replace(month=(new_date.month - i)) # day is out of range for month except ValueError: new_date = new_date - timedelta(days=(30 * i)) elif delta.startswith("q"): """ This section is not working... Most likely need a generator that will take me to the right quater. """ q1, q2, q3, q4 = ( datetime(new_date.year, 1, 1), datetime(new_date.year, 4, 1), datetime(new_date.year, 7, 1), datetime(new_date.year, 10, 1), ) if q1 <= new_date < q2: # We are in Q1 if i == -1: new_date = datetime(new_date.year - 1, 10, 1) else: new_date = q2 elif q2 <= new_date < q3: # We are in Q2 pass elif q3 <= new_date < q4: # We are in Q3 pass else: # We are in Q4 pass new_date = new_date - timedelta(days=(91 * i)) elif delta.startswith("w"): new_date = new_date - timedelta(days=(i * 7)) else: new_date = new_date - timedelta( **{ ( "days" if delta.startswith("d") else "hours" if delta.startswith("h") else "minutes" if delta.startswith("m") else "seconds" ): i } ) # !dow if [date.get(key) for key in ("day", "day_2", "day_3") if date.get(key)]: dow = max([date.get(key) for key in ("day", "day_2", "day_3") if date.get(key)]) iso = dict( monday=1, tuesday=2, wednesday=3, thursday=4, friday=5, saturday=6, sunday=7, mon=1, tue=2, tues=2, wed=3, wedn=3, thu=4, thur=4, fri=5, sat=6, sun=7, ).get(dow) if iso: # determin which direction if date.get("ref") not in ("this", "next"): days = iso - new_date.isoweekday() - (7 if iso >= new_date.isoweekday() else 0) else: days = iso - new_date.isoweekday() + (7 if iso < new_date.isoweekday() else 0) new_date = new_date + timedelta(days=days) elif dow == "yesterday": new_date = new_date - timedelta(days=1) elif dow == "tomorrow": new_date = new_date + timedelta(days=1) # !year year = [ int(CLEAN_NUMBER.sub("", date[key])) for key in ("year", "year_2", "year_3", "year_4", "year_5", "year_6") if date.get(key) ] if year: year = max(year) if len(str(year)) != 4: year += 2000 if year <= 40 else 1900 new_date = new_date.replace(year=year) # !month month = [ date.get(key) for key in ("month", "month_1", "month_2", "month_3", "month_4") if date.get(key) ] if month: new_date = new_date.replace(day=1) new_date = new_date.replace( month=int(max(month)) if re.match("^\d+$", max(month)) else dict( january=1, february=2, march=3, april=4, june=6, july=7, august=8, september=9, october=10, november=11, december=12, jan=1, feb=2, mar=3, apr=4, may=5, jun=6, jul=7, aug=8, sep=9, sept=9, oct=10, nov=11, dec=12, ).get(max(month), new_date.month) ) # !day day = [date.get(key) for key in ("date", "date_2", "date_3") if date.get(key)] if day: new_date = new_date.replace(day=int(max(day))) # !daytime if date.get("daytime"): if date["daytime"].find("this time") >= 1: new_date = new_date.replace( hour=datetime(*time.localtime()[:5]).hour, minute=datetime(*time.localtime()[:5]).minute ) else: new_date = new_date.replace( hour=dict( morning=9, noon=12, afternoon=15, evening=18, night=21, nighttime=21, midnight=24 ).get(date.get("daytime"), 12) ) # No offset because the hour was set. offset = False # !hour hour = [date.get(key) for key in ("hour", "hour_2", "hour_3") if date.get(key)] if hour: new_date = new_date.replace(hour=int(max(hour))) am = [date.get(key) for key in ("am", "am_1") if date.get(key)] if am and max(am) in ("p", "pm"): h = int(max(hour)) if h < 12: new_date = new_date.replace(hour=h + 12) # No offset because the hour was set. offset = False # minute minute = [date.get(key) for key in ("minute", "minute_2") if date.get(key)] if minute: new_date = new_date.replace(minute=int(max(minute))) # second seconds = date.get("seconds", 0) if seconds: new_date = new_date.replace(second=int(seconds)) self.date = new_date elif type(date) in (int, long, float) and re.match("^\d{10}$", str(date)): self.date = datetime.fromtimestamp(int(date)) elif isinstance(date, datetime): self.date = date elif date is None: self.date = datetime.now() else: # Set to the current date Y, M, D, H0, M0, S0 self.date = datetime(*time.localtime()[:3]) if tz: self.date = self.date.replace(tzinfo=tz) # end if type(date) is types.DictType: and self.date.hour == 0: if offset and isinstance(offset, dict): self.date = self.date.replace(**offset)