<s> """<STR_LIT>""" <EOL> __author__ = '<STR_LIT>' <EOL> import datetime <EOL> import re <EOL> import googlecl . base <EOL> import time <EOL> import logging <EOL> LOG = logging . getLogger ( "<STR_LIT>" ) <EOL> QUERY_DATE_FORMAT = '<STR_LIT>' <EOL> ACCEPTED_DAY_TIME_FORMAT = '<STR_LIT>' <EOL> ACCEPTED_DAY_FORMATS = [ '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' ] <EOL> ACCEPTED_TIME_FORMATS = [ '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' , <EOL> '<STR_LIT>' ] <EOL> AMBIGUOUS_TIME_REGEX = '<STR_LIT>' <EOL> _DAY_TIME_TOKENIZERS = [ '<STR_LIT:@>' , '<STR_LIT>' ] <EOL> _RANGE_TOKENIZERS = [ '<STR_LIT:U+002C>' ] <EOL> class Error ( Exception ) : <EOL> """<STR_LIT>""" <EOL> pass <EOL> class ParsingError ( Error ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , token ) : <EOL> self . token = token <EOL> def __str__ ( self ) : <EOL> return '<STR_LIT>' % self . token <EOL> def datetime_today ( ) : <EOL> """<STR_LIT>""" <EOL> return datetime . datetime . now ( ) . replace ( hour = <NUM_LIT:0> , <EOL> minute = <NUM_LIT:0> , <EOL> second = <NUM_LIT:0> , <EOL> microsecond = <NUM_LIT:0> ) <EOL> def determine_duration ( duration_token ) : <EOL> """<STR_LIT>""" <EOL> hour , minute = parse_ambiguous_time ( duration_token ) <EOL> if not ( hour or minute ) : <EOL> LOG . error ( '<STR_LIT>' ) <EOL> return None <EOL> return datetime . timedelta ( hours = hour , minutes = minute ) <EOL> def get_utc_timedelta ( ) : <EOL> """<STR_LIT>""" <EOL> if time . localtime ( ) . tm_isdst and time . daylight : <EOL> return datetime . timedelta ( hours = time . altzone / <NUM_LIT> ) <EOL> else : <EOL> return datetime . timedelta ( hours = time . timezone / <NUM_LIT> ) <EOL> def parse_ambiguous_time ( time_token ) : <EOL> """<STR_LIT>""" <EOL> ambiguous_time = re . match ( AMBIGUOUS_TIME_REGEX , time_token ) <EOL> if not ambiguous_time : <EOL> return None , None <EOL> hour_text = ambiguous_time . group ( <NUM_LIT:1> ) <EOL> minute_text = ambiguous_time . group ( <NUM_LIT:2> ) <EOL> if hour_text : <EOL> hour = int ( hour_text ) <EOL> else : <EOL> hour = <NUM_LIT:0> <EOL> if minute_text : <EOL> minute = int ( minute_text ) <EOL> else : <EOL> minute = <NUM_LIT:0> <EOL> return hour , minute <EOL> def split_string ( string , tokenizers = None ) : <EOL> """<STR_LIT>""" <EOL> if not string : <EOL> return ( '<STR_LIT>' , False , '<STR_LIT>' ) <EOL> if not tokenizers : <EOL> tokenizers = _RANGE_TOKENIZERS <EOL> for tokenizer in tokenizers : <EOL> if string . find ( tokenizer ) != - <NUM_LIT:1> : <EOL> left_token , _ , right_token = string . partition ( tokenizer ) <EOL> return ( left_token . strip ( ) , True , right_token . strip ( ) ) <EOL> return ( string . strip ( ) , False , '<STR_LIT>' ) <EOL> class Date ( object ) : <EOL> def __init__ ( self , local_datetime = None , utc_datetime = None , all_day = False ) : <EOL> """<STR_LIT>""" <EOL> if not ( local_datetime or utc_datetime ) : <EOL> raise Error ( '<STR_LIT>' ) <EOL> if local_datetime : <EOL> self . local = local_datetime <EOL> if not utc_datetime : <EOL> self . utc = self . local + get_utc_timedelta ( ) <EOL> if utc_datetime : <EOL> self . utc = utc_datetime <EOL> if not local_datetime : <EOL> self . local = self . utc - get_utc_timedelta ( ) <EOL> self . all_day = all_day <EOL> def __add__ ( self , other ) : <EOL> """<STR_LIT>""" <EOL> return Date ( utc_datetime = ( self . utc + other ) , all_day = self . all_day ) <EOL> def __sub__ ( self , other ) : <EOL> """<STR_LIT>""" <EOL> return Date ( utc_datetime = ( self . utc - other ) , all_day = self . all_day ) <EOL> def __str__ ( self ) : <EOL> """<STR_LIT>""" <EOL> basic_string_format = '<STR_LIT>' <EOL> if self . all_day : <EOL> return self . local . strftime ( basic_string_format ) <EOL> else : <EOL> return self . local . strftime ( basic_string_format + '<STR_LIT>' ) <EOL> def to_format ( self , format_string ) : <EOL> """<STR_LIT>""" <EOL> return self . utc . strftime ( format_string ) <EOL> def to_inclusive_query ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . all_day : <EOL> new_datetime = self . utc + datetime . timedelta ( hours = <NUM_LIT> ) <EOL> else : <EOL> new_datetime = self . utc + datetime . timedelta ( minutes = <NUM_LIT:1> ) <EOL> return new_datetime . strftime ( QUERY_DATE_FORMAT ) <EOL> def to_query ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . to_format ( QUERY_DATE_FORMAT ) <EOL> def to_timestamp ( self ) : <EOL> """<STR_LIT>""" <EOL> return time . mktime ( time . strptime ( self . utc . strftime ( format_string ) , <EOL> '<STR_LIT>' ) ) <EOL> def to_when ( self ) : <EOL> """<STR_LIT>""" <EOL> if self . all_day : <EOL> return self . to_format ( '<STR_LIT>' ) <EOL> else : <EOL> return self . to_query ( ) <EOL> class DateParser ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , today = None , now = None ) : <EOL> """<STR_LIT>""" <EOL> if today is None : <EOL> today = datetime_today <EOL> if now is None : <EOL> now = datetime . datetime . now <EOL> self . today = today <EOL> self . now = now <EOL> def parse ( self , text , base = None , shift_dates = True ) : <EOL> """<STR_LIT>""" <EOL> local_datetime = None <EOL> day = None <EOL> all_day = False <EOL> try : <EOL> all_info = datetime . datetime . strptime ( <EOL> text , ACCEPTED_DAY_TIME_FORMAT ) <EOL> except ValueError : <EOL> pass <EOL> else : <EOL> return Date ( local_datetime = all_info , all_day = False ) <EOL> day_token , _ , time_token = split_string ( text , _DAY_TIME_TOKENIZERS ) <EOL> if not ( day_token or time_token ) : <EOL> raise ParsingError ( text ) <EOL> past_time_to_tomorrow = False <EOL> if day_token : <EOL> day = self . determine_day ( day_token , shift_dates ) <EOL> if day is None : <EOL> past_time_to_tomorrow = True <EOL> time_token = day_token <EOL> if base : <EOL> day = base <EOL> else : <EOL> all_day = not bool ( time_token ) <EOL> if time_token : <EOL> if time_token . startswith ( '<STR_LIT:+>' ) : <EOL> delta = determine_duration ( time_token . lstrip ( '<STR_LIT:+>' ) ) <EOL> if delta and not day : <EOL> day = self . now ( ) <EOL> else : <EOL> time_offset = self . determine_time ( time_token ) <EOL> if time_offset is None : <EOL> delta = None <EOL> else : <EOL> if past_time_to_tomorrow and self . _time_has_passed ( time_offset ) : <EOL> delta = datetime . timedelta ( hours = time_offset . hour + <NUM_LIT> , <EOL> minutes = time_offset . minute ) <EOL> else : <EOL> delta = datetime . timedelta ( hours = time_offset . hour , <EOL> minutes = time_offset . minute ) <EOL> if not day : <EOL> day = self . today ( ) <EOL> if delta is not None : <EOL> local_datetime = day + delta <EOL> else : <EOL> local_datetime = day <EOL> if local_datetime : <EOL> return Date ( local_datetime = local_datetime , all_day = all_day ) <EOL> else : <EOL> raise ParsingError ( text ) <EOL> def _day_has_passed ( self , date ) : <EOL> """<STR_LIT>""" <EOL> today = self . today ( ) <EOL> return ( date . month < today . month or <EOL> ( date . month == today . month and date . day < today . day ) ) <EOL> def determine_day ( self , day_token , shift_dates ) : <EOL> """<STR_LIT>""" <EOL> if day_token == '<STR_LIT>' : <EOL> return self . today ( ) + datetime . timedelta ( hours = <NUM_LIT> ) <EOL> elif day_token == '<STR_LIT>' : <EOL> return self . today ( ) <EOL> else : <EOL> date , valid_format = self . _extract_time ( <EOL> day_token , ACCEPTED_DAY_FORMATS ) <EOL> if not date : <EOL> LOG . debug ( '<STR_LIT>' % <EOL> day_token ) <EOL> return None <EOL> if valid_format . lower ( ) . find ( '<STR_LIT>' ) == - <NUM_LIT:1> : <EOL> if self . _day_has_passed ( date ) and shift_dates : <EOL> date = date . replace ( year = self . today ( ) . year + <NUM_LIT:1> ) <EOL> else : <EOL> date = date . replace ( year = self . today ( ) . year ) <EOL> return date <EOL> def determine_time ( self , time_token ) : <EOL> """<STR_LIT>""" <EOL> hour , minute = parse_ambiguous_time ( time_token ) <EOL> if ( hour or minute ) : <EOL> if <NUM_LIT:1> <= hour and hour <= <NUM_LIT:6> : <EOL> hour += <NUM_LIT:12> <EOL> else : <EOL> tmp , _ = self . _extract_time ( time_token , ACCEPTED_TIME_FORMATS ) <EOL> if not tmp : <EOL> LOG . debug ( '<STR_LIT>' ) <EOL> return None <EOL> hour = tmp . hour <EOL> minute = tmp . minute <EOL> return datetime . time ( hour = hour , minute = minute ) <EOL> def _extract_time ( self , time_string , possible_formats ) : <EOL> """<STR_LIT>""" <EOL> for time_format in possible_formats : <EOL> try : <EOL> date = datetime . datetime . strptime ( time_string , time_format ) <EOL> except ValueError , err : <EOL> continue <EOL> else : <EOL> return date , time_format <EOL> return None , None <EOL> def _time_has_passed ( self , time_container ) : <EOL> """<STR_LIT>""" <EOL> now = self . now ( ) <EOL> return ( time_container . hour < now . hour or <EOL> ( time_container . hour == now . hour and <EOL> time_container . minute < now . minute ) ) <EOL> class DateRange ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , start , end , is_range ) : <EOL> """<STR_LIT>""" <EOL> self . start = start <EOL> self . end = end <EOL> self . specified_as_range = is_range <EOL> def to_when ( self ) : <EOL> """<STR_LIT>""" <EOL> if not self . start or not self . end : <EOL> raise Error ( <EOL> '<STR_LIT>' ) <EOL> else : <EOL> start = self . start <EOL> if not self . specified_as_range : <EOL> if self . start . all_day : <EOL> end = self . start + datetime . timedelta ( hours = <NUM_LIT> ) <EOL> else : <EOL> end = self . start + datetime . timedelta ( hours = <NUM_LIT:1> ) <EOL> else : <EOL> end = self . end <EOL> return start . to_when ( ) , end . to_when ( ) <EOL> class DateRangeParser ( object ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , today = None , now = None , range_tokenizers = None ) : <EOL> """<STR_LIT>""" <EOL> self . date_parser = DateParser ( today , now ) <EOL> if range_tokenizers is None : <EOL> range_tokenizers = _RANGE_TOKENIZERS <EOL> self . range_tokenizers = range_tokenizers <EOL> def parse ( self , date_string , shift_dates = False ) : <EOL> """<STR_LIT>""" <EOL> start_date = None <EOL> end_date = None <EOL> start_text , is_range , end_text = split_string ( date_string , <EOL> self . range_tokenizers ) <EOL> if start_text : <EOL> start_date = self . date_parser . parse ( <EOL> start_text , shift_dates = shift_dates ) <EOL> if end_text : <EOL> if start_date : <EOL> base = start_date . local <EOL> else : <EOL> base = None <EOL> end_date = self . date_parser . parse ( end_text , base = base , <EOL> shift_dates = shift_dates ) <EOL> elif not is_range : <EOL> end_date = start_date <EOL> return DateRange ( start_date , end_date , is_range ) </s>
