def __init__(self, start, end, absolute=False): super(Period, self).__init__() if not isinstance(start, pendulum.Date): if isinstance(start, datetime): start = pendulum.instance(start) else: start = pendulum.date(start.year, start.month, start.day) _start = start else: if isinstance(start, pendulum.DateTime): _start = datetime( start.year, start.month, start.day, start.hour, start.minute, start.second, start.microsecond, tzinfo=start.tzinfo, ) else: _start = date(start.year, start.month, start.day) if not isinstance(end, pendulum.Date): if isinstance(end, datetime): end = pendulum.instance(end) else: end = pendulum.date(end.year, end.month, end.day) _end = end else: if isinstance(end, pendulum.DateTime): _end = datetime( end.year, end.month, end.day, end.hour, end.minute, end.second, end.microsecond, tzinfo=end.tzinfo, ) else: _end = date(end.year, end.month, end.day) self._invert = False if start > end: self._invert = True if absolute: end, start = start, end _end, _start = _start, _end self._absolute = absolute self._start = start self._end = end self._delta = precise_diff(_start, _end)
def test_subtract_timedelta(): delta = timedelta(days=18) d = pendulum.date(2015, 3, 14) new = d - delta assert isinstance(new, pendulum.Date) assert_date(new, 2015, 2, 24)
def test_add_timedelta(): delta = timedelta(days=18) d = pendulum.date(2015, 3, 14) new = d + delta assert isinstance(new, pendulum.Date) assert_date(new, 2015, 4, 1)
def holiday_cmd(self, mask, target, args): """ Show the upcoming non-weekend holidays for all countries in config. %%holiday """ country_codes = self.config.get("holiday_countries") if not country_codes: return now = pendulum.now(tz=self.config.get("default_timezone")) for country_code in country_codes.split(","): date, name = get_next_non_weekend_holiday(now, country_code) remaining_days = ( pendulum.date(date.year, date.month, date.day) - now ).in_days() plural = "" if remaining_days == 1 else "s" yield ( f"Next holiday for {country_code}:" f" {date.isoformat()} ({name}" f", in {remaining_days} day{plural})" )
def test_addition_invalid_type(): d = pendulum.date(2015, 3, 14) with pytest.raises(TypeError): d + 3 with pytest.raises(TypeError): 3 + d
def test_subtract_months_positive(): assert pendulum.date(1975, 1, 1).subtract(months=1).month == 12
def test_subtract_months_negative(): assert pendulum.date(1975, 11, 1).subtract(months=-1).month == 12
def Message(self, event): user_id = event.obj.message['peer_id'] message = event.obj.message['text'] self.Vk.SetActivity(user_id) if message == 'raise': raise ValueError if message == 'beginning': self.Users.SetUserParameters(user_id, state=0) self.Vk.MessageSend(user_id, 'Главное меню', keyboard=Keyboard.StayHomeKeyboard()) if (not self.Users.CheckUserInBase(user_id)) or ( self.Users.GetUserState(user_id) in [1, 2]): self.UserRegister(event) elif self.Users.GetUserState(user_id) == 3: self.UserSettings(user_id, message) elif self.Users.GetUserState(user_id) == 4: user_info = self.Users.GetUserInfo(user_id) if message.lower() == 'показать дз': self.hwc = True self.UserLogger.info(f'Запрос на ДЗ') user_class = user_info["cls"] homework_date = user_info["homework_date"].replace( "today", GetTodayDate()) homework = HomeworkBase().GetHomework(homework_date, user_class) self.Vk.MessageSend( user_id, f'Домашнее задание {user_class} класса на {homework_date}:\n' + homework) elif message.lower() == 'добавить дз': self.UserLogger.info(f'Режим добавления ДЗ') self.Vk.MessageSend( user_id, 'Введи домашнее задание или нажми кнопку "Отмена"\nВнимание! Рядом с домашним заданием будет отображаться ссылка на твой профиль!', keyboard=Keyboard.DenyKeyboard()) self.Users.SetUserParameters(user_id, state=6) elif message.lower() == 'указать дату': self.UserLogger.info(f'Режим выбора даты ДЗ') self.Vk.MessageSend( user_id, 'Введи дату, чтобы посмотреть домашнее задание') self.Users.SetUserParameters(user_id, state=5) elif message.lower() == 'пожаловаться': self.UserLogger.info(f'Отправлена жалоба на расписание') user_class = user_info["cls"] homework_date = user_info["homework_date"].replace( "today", GetTodayDate()) homework = HomeworkBase().GetHomework(homework_date, user_class) self.Vk.ConsoleMessage( f'Жалоба от @id{user_id}({user_info["name"]} {user_info["last"]}) на ДЗ {user_class} класса на {homework_date}:\n{homework}' ) self.Vk.MessageSend(user_id, 'Жалоба отправлена!') else: self.Users.SetUserParameters(user_id, state=0, hw_date='today') self.Vk.MessageSend(user_id, 'Главное меню', keyboard=Keyboard.MenuKeyboard()) elif self.Users.GetUserState(user_id) == 5: date = DialogFlow().SendRequest(message) if 'system' in date: y, m, d = list( map(int, date.lstrip('system user_class').split('-'))) hw_date = pendulum.date(y, m, d).__format__(Utilities.FORMAT) self.Users.SetUserParameters(user_id, state=4, hw_date=hw_date) self.Vk.MessageSend(user_id, f'Установлена дата {hw_date}') else: self.Users.SetUserParameters(user_id, state=4) self.Vk.MessageSend(user_id, 'Дата указана неверно!') elif self.Users.GetUserState(user_id) == 6: user_info = self.Users.GetUserInfo(user_id) lexics = DialogFlow().SendRequest(message) if lexics.lower() == 'мат': self.Vk.ConsoleMessage( f'@id{user_id}({user_info["name"]}) пытается добавить ДЗ:\n{message}' ) self.Vk.MessageSend( user_id, 'Возможно, домашнее задание содержит ненормативную лексику! Я не могу его добавить', keyboard=Keyboard.HomeworkKeyboard()) else: if message.lower() != 'отмена': self.hwa = True self.UserLogger.info( f'Добавлено домашнее задание на {user_info["homework_date"].replace("today", GetTodayDate())}' ) HomeworkBase().AddHomework( user_info["homework_date"].replace( "today", GetTodayDate()), user_info["cls"], message + f' - (@id{user_id}({user_info["name"][0]}{user_info["last"][0]}))\n' ) self.Vk.MessageSend(user_id, 'Домашнее задание добавлено!', keyboard=Keyboard.HomeworkKeyboard()) self.Vk.ConsoleMessage( f'@id{user_id}({user_info["name"]}) добавил ДЗ:\n{message}' ) else: self.Vk.MessageSend(user_id, 'Окей, отмена', keyboard=Keyboard.HomeworkKeyboard()) self.Users.SetUserParameters(user_id, state=4) elif self.Users.GetUserState(user_id) == 0: self.MainMenu(event)
def test_subtract_years_zero(): assert pendulum.date(1975, 1, 1).subtract(years=0).year == 1975
def test_add_months_negative(): assert pendulum.date(1975, 12, 1).add(months=-1).month == 11
def test_sequence(): d = date(2000, 1, 1) assert serialize([d]) == ["2000-01-01"] assert serialize((d, )) == ["2000-01-01"]
def test_subtract_months_zero(): assert pendulum.date(1975, 12, 1).subtract(months=0).month == 12
def test_add_years_zero(): assert pendulum.date(1975, 1, 1).add(years=0).year == 1975
def test_subtract_years_negative(): assert pendulum.date(1975, 1, 1).subtract(years=-1).year == 1976
def test_subtract_years_positive(): assert pendulum.date(1975, 1, 1).subtract(years=1).year == 1974
def _parse(text, **options): """ Parses a string with the given options. :param text: The string to parse. :type text: str :rtype: mixed """ # Handling special cases if text == "now": return pendulum.now() parsed = base_parse(text, **options) if isinstance(parsed, datetime.datetime): return pendulum.datetime( parsed.year, parsed.month, parsed.day, parsed.hour, parsed.minute, parsed.second, parsed.microsecond, tz=parsed.tzinfo or options.get("tz", UTC), ) if isinstance(parsed, datetime.date): return pendulum.date(parsed.year, parsed.month, parsed.day) if isinstance(parsed, datetime.time): return pendulum.time( parsed.hour, parsed.minute, parsed.second, parsed.microsecond ) if isinstance(parsed, _Interval): if parsed.duration is not None: duration = parsed.duration if parsed.start is not None: dt = pendulum.instance(parsed.start, tz=options.get("tz", UTC)) return pendulum.period( dt, dt.add( years=duration.years, months=duration.months, weeks=duration.weeks, days=duration.remaining_days, hours=duration.hours, minutes=duration.minutes, seconds=duration.remaining_seconds, microseconds=duration.microseconds, ), ) dt = pendulum.instance(parsed.end, tz=options.get("tz", UTC)) return pendulum.period( dt.subtract( years=duration.years, months=duration.months, weeks=duration.weeks, days=duration.remaining_days, hours=duration.hours, minutes=duration.minutes, seconds=duration.remaining_seconds, microseconds=duration.microseconds, ), dt, ) return pendulum.period( pendulum.instance(parsed.start, tz=options.get("tz", UTC)), pendulum.instance(parsed.end, tz=options.get("tz", UTC)), ) if CDuration and isinstance(parsed, CDuration): return pendulum.duration( years=parsed.years, months=parsed.months, weeks=parsed.weeks, days=parsed.days, hours=parsed.hours, minutes=parsed.minutes, seconds=parsed.seconds, microseconds=parsed.microseconds, ) return parsed
def test_previous_invalid(self): dt = pendulum.date(1975, 5, 21) with pytest.raises(ValueError): dt.previous(7)
def test_start_of(): d = pendulum.date(2013, 3, 31) with pytest.raises(ValueError): d.start_of("invalid")
def deal_month_plan_data(self, plan_data, result): ''' 处理月计划数据, 只是调整计划时间 :return: ''' if result['status'] != 200: raise exceptions.ValidationError("计算错错,未能找正确解") result = result['datas'] plan_result = result["plan_result"] year = plan_data["year"] month = plan_data["month"] month_start = pendulum.date(year, month, 1) plan_id = self.id kt_rule_id = self.env.ref("metro_park_base_data_10.repair_rule_kt").id vals = [] attach_result = result['attach_result'] tasks = plan_data['tasks'] for task in tasks: info_id = task["id"] index = task["index"] value = plan_result[index] # value是从1开始 plan_date = month_start.add(days=value - 1) record = self.env["metro_park_maintenance.rule_info"].browse( info_id) if not task["is_extra"]: record.write({ "date": plan_date.format("YYYY-MM-DD"), "year": plan_date.year, "month": plan_date.month, "day": plan_date.day_of_year }) else: # 下月放在本月的情况,创建本月数据 self.env["metro_park_maintenance.rule_info"].create([{ "date": plan_date.format("YYYY-MM-DD"), "dev": task['dev'], "year": plan_date.year, "month": plan_date.month, "day": plan_date.day, "plan_id": "metro_park_maintenance.month_plan, {plan_id}".format( plan_id=plan_id), "rule": task["rule_id"], 'data_source': 'month' }]) attach_index = task["attach_index"] if attach_index != -1 and attach_result[attach_index] == 1: plan_date = plan_date.subtract(days=1) vals.append({ "date": plan_date.format("YYYY-MM-DD"), "dev": task['dev'], "year": plan_date.year, "month": plan_date.month, "day": plan_date.day, "plan_id": "metro_park_maintenance.month_plan, {plan_id}".format( plan_id=plan_id), "rule": kt_rule_id, 'data_source': 'month' }) self.env["metro_park_maintenance.rule_info"].create(vals)
def test_add_months_positive(): assert pendulum.date(1975, 12, 1).add(months=1).month == 1
def test_diff_in_days_negative_with_sign(): dt = pendulum.date(2000, 1, 1) assert -365 == dt.diff(dt.subtract(years=1), False).in_days()
def test_subtract_duration(): delta = pendulum.duration(years=2, months=3, days=18) d = pendulum.date(2015, 3, 14) new = d - delta assert_date(new, 2012, 11, 26)
def test_date(): d = date(2000, 1, 1) assert serialize(d) == "2000-01-01"
def test_diff_in_days_positive(): dt = pendulum.date(2000, 1, 1) assert 366 == dt.diff(dt.add(years=1)).in_days()
def test_diff_in_days_negative_no_sign(): dt = pendulum.date(2000, 1, 1) assert 365 == dt.diff(dt.subtract(years=1)).in_days()
def test_add_years_negative(): assert pendulum.date(1975, 1, 1).add(years=-1).year == 1974
def test_add_months_zero(): assert pendulum.date(1975, 12, 1).add(months=0).month == 12
def test_average_from_same(): d1 = pendulum.date(2000, 1, 31) d2 = pendulum.date(2000, 1, 31).average(d1) assert_date(d2, 2000, 1, 31)
def test_next_invalid(self): dt = pendulum.date(1975, 5, 21) with pytest.raises(ValueError): dt.next(7)
def test_add_years_positive(): assert pendulum.date(1975, 1, 1).add(years=1).year == 1976
def test_average_from_lower(): d1 = pendulum.date(2009, 12, 31) d2 = pendulum.date(2000, 1, 1).average(d1) assert_date(d2, 2004, 12, 31)
def test_diff_in_weeks_positive(): dt = pendulum.date(2000, 1, 1) assert 52 == dt.diff(dt.add(years=1)).in_weeks()
def test_end_of_invalid_unit(): d = pendulum.date(2013, 3, 31) with pytest.raises(ValueError): d.end_of("invalid")
def test_diff_in_weeks_ensure_is_truncated(): dt = pendulum.date(2000, 1, 1) assert 0 == dt.diff(dt.add(weeks=1).subtract(days=1)).in_weeks()
def test_diff_in_years_ensure_is_truncated(): dt = pendulum.date(2000, 1, 1) assert 1 == dt.diff(dt.add(years=1).add(months=7)).in_years()
def test_diff_in_months_positive(): dt = pendulum.date(2000, 1, 1) assert 13 == dt.diff(dt.add(years=1).add(months=1)).in_months()
def test_diff_in_months_negative_no_sign(): dt = pendulum.date(2000, 1, 1) assert 11 == dt.diff(dt.subtract(years=1).add(months=1)).in_months()
def test_diff_in_months_ensure_is_truncated(): dt = pendulum.date(2000, 1, 1) assert 1 == dt.diff(dt.add(months=1).add(days=16)).in_months()
def get_month_plan_data(self, wizard_id): ''' 计算月计划,本月原来安排的只能优选选择 :return: ''' wizard_info = \ self.env["metro_park_maintenance.month_plan_compute_wizard"].browse(wizard_id) # 当月的计划, 有可能是扣车移动过来的,同时可能有月计划的内容 real_infos = self.env["metro_park_maintenance.rule_info"]\ .search([('plan_id', '=', 'metro_park_maintenance.month_plan, {plan_id}'.format( plan_id=self.id)), ('rule.target_plan_type', '=', 'year')], order="date asc") # 年计划就要求均衡 dev_tasks_cache = dict() for info in real_infos: dev_tasks_cache.setdefault(info.dev.id, []).append(info) # 暂时没有考虑跨月的项,跨月的项要要作预先安排 # for key in dev_tasks_cache: # infos = dev_tasks_cache[key] # if len(infos) > 0 and infos[0].repair_num != 1: # while len(infos) > 0 and infos[0].repair_num != 1: # infos = infos[1:] # dev_tasks_cache[key] = infos month_start = pendulum.date(self.year, self.month, 1) month_days = month_start.days_in_month # 白名单 month_end = month_start.add(days=month_days) white_list = self.env["metro_park_maintenance.white_list"]\ .search([("date", ">=", month_start.format('YYYY-MM-DD')), ('date', '<=', month_end.format('YYYY-MM-DD'))]) white_dates = [] for record in white_list: white_dates.append( pendulum.parse(str(record.date)).format("YYYY-MM-DD")) # 查询特殊日期配置, 黑名单 special_days = \ self.env['metro_park_maintenance.holidays'].search([]) special_days_cache = { str(record.date): True for record in special_days } # 节假日 holidays = [] for tmp_index in range(1, month_days + 1): tmp_date = pendulum.date(self.year, self.month, tmp_index) tmp_date_str = tmp_date.format('YYYY-MM-DD') if (tmp_date.day_of_week == 6 or tmp_date.day_of_week == 0) \ and tmp_date_str not in white_dates: holidays.append(tmp_index) if tmp_date_str in special_days_cache and tmp_date_str not in white_dates: holidays.append(tmp_index) # 取得缓存信息, 扣车等会自动挪动,或是用户手动移动 month_start_date = pendulum.date(self.year, self.month, 1) history_plans = self.env["metro_park_maintenance.rule_info"]\ .get_year_plan_history_info(month_start_date, False) history_plan_cache = {plan.dev.id: plan for plan in history_plans} tasks = [] for dev_id in dev_tasks_cache: dev_tasks = [] infos = dev_tasks_cache[dev_id] pre_info = None for tmp_index, info in enumerate(infos): # 过滤掉复复的情况 if pre_info and pre_info.rule.id == info.rule.id: pre_info = info continue else: pre_info = info rule = info.rule task = { "index": len(tasks), "id": info.id, "rule_id": info.rule.id, "dev": dev_id, # 同一设备不限定 "pre_index": len(tasks) - 1 if tmp_index != 0 else -1, "period": info.rule.period, "positive_offset": info.rule.positive_offset, "negative_offset": info.rule.negative_offset, "repeat_index": -1, # 检修第一天 "repair_day": 1, "repair_days": info.rule.repair_days, "left_days": info.rule.period, "info_count": len(infos), "month_start_val": 1, "month_end_val": month_days, "repeat": False, "repair_num": info.repair_num, "attach_index": -1, "is_extra": False } # 第一个月需要考虑历史信息, 但是这个不考虑修次,决定了最终的位置 if tmp_index == 0: history_repair_info = history_plan_cache.get(dev_id, False) if history_repair_info: # 最后一个计划开始的日期 tmp_date = pendulum.parse( str(history_repair_info["date"])) tmp_delta = month_start_date - tmp_date # 已经使用了的天数 offset_days = tmp_delta.days - 1 # 已经超超期,需要直接安排 if offset_days > rule['period'] + rule[ 'positive_offset']: task['left_days'] = 0 task['positive_offset'] = 0 task['negative_offset'] = 0 # 在负区间内 elif rule['period'] - rule[ 'negative_offset'] <= offset_days < rule[ 'period']: task['left_days'] = rule['period'] - offset_days task['negative_offset'] = rule[ 'period'] - offset_days # 在正区间内, 这个有可能刚好剩下的就是星期六和星期天,这个就有点尴尬了 elif rule['period'] <= offset_days <= rule[ 'period'] + rule['positive_offset']: task['left_days'] = 0 task['negative_offset'] = 0 task['positive_offset'] = \ rule['period'] + rule['positive_offset'] - offset_days else: # 还没有到达检修周期, 肯定是在上个月进行的,所以无论如何都可以排 task['left_days'] = rule['period'] - offset_days tasks.append(task) dev_tasks.append(task) # 时于按时间排序,均衡修不可能同一天进行多个,所以,后面的几个正好是重复的 repair_days = rule.repair_days is_extra = False for day in range(1, repair_days): tmp_task = copy.copy(task) # 跨月的情况, 从下月找到相应的数据 if tmp_index + day > len(infos) - 1: is_extra = True tmp_year = self.year next_month = self.month + 1 if next_month > 12: next_month = 1 tmp_year += 1 left_rule_infos = \ self.env["metro_park_maintenance.rule_info"].search( [('year', '=', tmp_year), ('month', "=", next_month), ('dev', '=', dev_id), ('rule', '=', rule.id)], order="date asc") for tmp_info in left_rule_infos: infos.append(tmp_info) # assert infos[tmp_index + day].rule.id == info.rule.id # assert infos[tmp_index + day].id != info.id tmp_info = infos[tmp_index + day] tmp_task["id"] = tmp_info.id tmp_task["repeat_index"] = len(tasks) - 1 tmp_task["pre_index"] = len(tasks) - 1 tmp_task["repair_day"] = day + 1 tmp_task["index"] = len(tasks) tmp_task["repeat"] = True tmp_task["is_extra"] = is_extra tasks.append(tmp_task) # 取得计算服务器 config = self.env['metro_park_base.system_config'].get_configs() calc_host = config.get('calc_host', False) attach_tasks = [] # 附加空调专检的task 如果是第一月份的话, 第一个月尽量安排 plan_kt_month_1 = self.env.ref("metro_park_base.plan_kt_month_1").id plan_kt_month_2 = self.env.ref("metro_park_base.plan_kt_month_2").id if wizard_info.plan_kt \ and wizard_info.plan_kt_month == plan_kt_month_1: attach_tasks = [] for task in tasks: # 只按排修程只有一天的 if task["repair_days"] == 1 and task["repair_day"] == 1: attach_task = { "index": len(attach_tasks), "attach_index": task["index"], "force": False, "dev_id": task['dev'] } # 相互关联 task["attach_index"] = attach_task["index"] repair_num = task["repair_num"] # 下一次没法进行的情况 next_repair_info = \ self.env['metro_park_maintenance.plan_config_data'].get_next_repair_info(repair_num) if next_repair_info.repair_days > 1: attach_task["force"] = True attach_tasks.append(attach_task) elif wizard_info.plan_kt \ and wizard_info.plan_kt_month.id == plan_kt_month_2: # 如果上一个月没有安排空调专检的话这个月就必需要安排 kt_rule_id = self.env.ref( "metro_park_base_data_10.repair_rule_kt").id prev_month = self.month - 1 prev_year = self.year if prev_month <= 0: prev_month = 12 prev_year = prev_year - 1 his_kt_infos = self.env["metro_park_maintenance.rule_info"].search( [("rule", '=', kt_rule_id), ("month", "=", prev_month), ("year", '=', prev_year)]) his_kt_info_cache = dict() for tmp_info in his_kt_infos: his_kt_info_cache[tmp_info.dev.id] = tmp_info black_dev = [] for task in tasks: if task["dev"] not in his_kt_info_cache \ and task['repair_day'] == 1 and task["dev"] not in black_dev: black_dev.append(task['dev']) attach_task = { "index": len(attach_tasks), "attach_index": task["index"], "force": False, "dev_id": task['dev'] } # 相互关联 task["attach_index"] = len(attach_tasks) attach_tasks.append(attach_task) return { "tasks": tasks, "month": self.month, "year": self.year, "month_days": month_days, "holidays": holidays, "calc_host": calc_host, "max_plan_per_day": wizard_info.max_plan_per_day, "attach_tasks": attach_tasks or [], "plan_kt": True if wizard_info.plan_kt.value == 'yes' else False, "plan_kt_month": 1 if wizard_info.plan_kt_month.id == plan_kt_month_1 else 2 }