import re import pendulum class NumListHelper(object): @classmethod def parse_num_list(cls, string): """ parse num list like: '1-6' or '2'. # NOTE: DO NOT use string like '1 -6' or '1 - 6', it will raise an exception. """ m = re.match(r'(\d+)(?:-(\d+))?$', string) start = m.group(1) end = m.group(2) or start return list(range(int(start, 10), int(end, 10) + 1)) @classmethod def parse_comma_delimited_num(cls, string): """ parse comma delimited num list like: '1,3-8,10-15'. # NOTE: the return list is NOT sorted. """ num_str_l = [i.strip() for i in string.split(',')] num_str_l = filter(lambda x: x != '', num_str_l) n_list = [] # final format like: [1,2,3,4,9,10,11,12] for n_str in num_str_l: n_list.extend(cls.parse_num_list(n_str)) n_list = list(set(n_list)) # revmove duplicated items return n_list class PricePolicyHelper(object): @classmethod def map_price_policy(cls, pp_obj, inline_vc, ts): """ get responding price policy through inline_vc and ts. :param pp_obj: a dict like following: {inline_vc1: {start_month1: {time_range1: v, time_range2: v }, start_month2: {...} }, inline_vc2: {...} } :param inline_vc: the inline_vc of the data belonged to :param ts: the timestamp of the data, always the small timestamp of a time range. :return: v in the pp_obj format # NOTE: if no related price policy, return None """ if len(pp_obj) == 0: return None # select by inline_vc key_vc = str(inline_vc) val_vc = pp_obj.get(key_vc) if val_vc is None: return None # select by start_month months = [int(i) for i in val_vc.keys()] months.sort(reverse=True) target_month = months[-1] for item in months: if ts > item: target_month = item break key_sm = str(target_month) val_sm = val_vc[key_sm] # select by time_range tr_dict = {} for item in val_sm.keys(): month_str_l = [i.strip() for i in item.split(',')] m_list = [] # final format like: [1,2,3,4,9,10,11,12] for m_str in month_str_l: # get all month in m_list m_list.extend(NumListHelper.parse_num_list(m_str)) for month in m_list: tr_dict[month] = item dt = pendulum.from_timestamp(ts, tz='Asia/Shanghai') key_tr = tr_dict[dt.month] pp_info_d = val_sm[key_tr] return pp_info_d @classmethod def quarter_chars_2_time_str(cls, quarters): """ convert quarter chars to time_str. quarter chars like: ("vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvfffffffffffff" "fffffffffffppppppppppppffffffffppppppppppppffffffff") time_str like: {'s': [], 'p': ['14:00-17:00', '19:00-22:00'], 'f': ['08:00-14:00', '17:00-19:00', '22:00-24:00'], 'v': ['00:00-08:00']} # NOTE: 22:00-24:00, the result has 24:00 that represents the last second of the day. """ rlt = {'s': [], 'p': [], 'f': [], 'v': []} now = pendulum.now(tz='Asia/Shanghai') stime = pendulum.datetime(now.year, now.month, now.day, tz='Asia/Shanghai') etime = stime pre_char = quarters[0] quarters = quarters + 'x' # add 'x' to trigger last chars saving for item in quarters: # char changing triggers saving previous chars if item != pre_char: st_str = stime.format("HH:mm") et_str = etime.format("HH:mm") if etime.hour == 0 and etime.minute == 0: et_str = '24:00' rlt[pre_char].append(st_str + '-' + et_str) stime = etime pre_char = item etime = etime.add(minutes=15) return rlt