diff options
Diffstat (limited to 'date_calculator.py')
| -rw-r--r-- | date_calculator.py | 306 |
1 files changed, 153 insertions, 153 deletions
diff --git a/date_calculator.py b/date_calculator.py index e6c20fc..402a58c 100644 --- a/date_calculator.py +++ b/date_calculator.py @@ -1,154 +1,154 @@ -# date_calculator.py -from datetime import datetime, timedelta -from dateutil.relativedelta import relativedelta -import math - -class DateCalculator: - @staticmethod - def truncate_periods(periods, launch, prediction): - considered_periods = [] - for start, end, id in periods: - # print(start) - # print(launch) - truncated_start = max(start, launch) - truncated_end = min(end, prediction) - if truncated_start <= end and truncated_start <= prediction: - considered_periods.append((truncated_start, truncated_end, id)) - return considered_periods - - @staticmethod - def round_periods(periods): - rounded_periods = [] - total_months = 0 - - for start, end, id in periods: - year_diff = end.year - start.year - month_diff = end.month - start.month - months = year_diff * 12 + month_diff - if end.day >= start.day: - months += 1 - rounded_end = start + relativedelta(months=months) - timedelta(days=1) - - rounded_periods.append((start, rounded_end, id)) - total_months += months - - return rounded_periods, total_months - - @staticmethod - def merge_periods(periods): - if not periods: - return [] - - periods.sort() - merged_periods = [] - - current_start, current_end, current_id = periods[0] - - for start, end, id in periods[1:]: - if start <= current_end + timedelta(days=1): - current_end = max(current_end, end) - else: - merged_periods.append((current_start, current_end, current_id)) - current_start, current_end, current_id = start, end, id - - merged_periods.append((current_start, current_end, current_id)) - - return merged_periods - - @staticmethod - def find_non_overlapping_periods(existing_periods, test_period): - existing_periods.sort(key=lambda x: x[0]) - - test_start, test_end, id = test_period - non_overlapping_periods = [] - - for start, end, _ in existing_periods: - if test_end < start: - non_overlapping_periods.append((test_start, test_end, id)) - return non_overlapping_periods - - elif test_start > end: - continue - - else: - if test_start < start: - non_overlapping_periods.append((test_start, start - timedelta(days=1), id)) - - test_start = end + timedelta(days=1) - - if test_start <= test_end: - non_overlapping_periods.append((test_start, test_end, id)) - - return non_overlapping_periods - - def calculate_prediction(self, launch_date, duration, **kwargs): - total_days = 0 - total_months = 0 - updated = True - prediction_start = launch_date + duration - timedelta(days = 1) - prediction = prediction_start - - events = [] - half_projects = [] - full_projects = [] - other_kwargs = {} - - for k, v in kwargs.items(): - if k == "event": - events.extend(v) - elif k == "half_project": - half_projects.extend(v) - elif k == "full_project": - full_projects.extend(v) - elif k == "two_years": - full_projects.extend(v) - else: - other_kwargs[k] = v - - while updated: - updated = False - considered_events = self.truncate_periods(events, launch_date, prediction) - considered_full_projects = self.truncate_periods(full_projects, launch_date, prediction) - considered_half_projects = self.truncate_periods(half_projects, launch_date, prediction) - - considered_full_projects_merged = self.merge_periods(considered_full_projects) - considered_full_projects_rounded, months = self.round_periods(considered_full_projects_merged) - considered_full_projects_merged2 = self.merge_periods(considered_full_projects_rounded) - considered_full_projects_rounded2, months = self.round_periods(considered_full_projects_merged2) - - non_overlapping_half_projects = [] - for test_interval in considered_half_projects: - non_overlapping_half_projects.extend( - self.find_non_overlapping_periods(considered_full_projects_rounded2, test_interval) - ) - - considered_half_projects_merged = self.merge_periods(non_overlapping_half_projects) - considered_half_projects_rounded, months2 = self.round_periods(considered_half_projects_merged) - considered_half_projects_merged2 = self.merge_periods(considered_half_projects_rounded) - considered_half_projects_rounded2, months2 = self.round_periods(considered_half_projects_merged2) - - all_projects_merged = self.merge_periods( - considered_full_projects_rounded2 + considered_half_projects_rounded2 - ) - merged_event_periods = self.merge_periods(considered_events) - - non_overlapping_event_periods = [] - for test_interval in merged_event_periods: - non_overlapping_event_periods.extend( - self.find_non_overlapping_periods(all_projects_merged, test_interval) - ) - - new_total_months = months + math.ceil(months2 / 2) - new_total_days = sum((end - start).days + 1 for start, end, _ in non_overlapping_event_periods) - - if new_total_days != total_days or new_total_months != total_months: - total_days = new_total_days - total_months = new_total_months - updated = True - prediction = launch_date + duration + relativedelta(months=total_months) + timedelta(days=total_days-1) - - # print(prediction, prediction_start + relativedelta(years = 6)) - if prediction > prediction_start + relativedelta(years = 6): - prediction = prediction_start + relativedelta(years = 6) - +# date_calculator.py
+from datetime import datetime, timedelta
+from dateutil.relativedelta import relativedelta
+import math
+
+class DateCalculator:
+ @staticmethod
+ def truncate_periods(periods, launch, prediction):
+ considered_periods = []
+ for start, end, id in periods:
+ # print(start)
+ # print(launch)
+ truncated_start = max(start, launch)
+ truncated_end = min(end, prediction)
+ if truncated_start <= end and truncated_start <= prediction:
+ considered_periods.append((truncated_start, truncated_end, id))
+ return considered_periods
+
+ @staticmethod
+ def round_periods(periods):
+ rounded_periods = []
+ total_months = 0
+
+ for start, end, id in periods:
+ year_diff = end.year - start.year
+ month_diff = end.month - start.month
+ months = year_diff * 12 + month_diff
+ if end.day >= start.day:
+ months += 1
+ rounded_end = start + relativedelta(months=months) - timedelta(days=1)
+
+ rounded_periods.append((start, rounded_end, id))
+ total_months += months
+
+ return rounded_periods, total_months
+
+ @staticmethod
+ def merge_periods(periods):
+ if not periods:
+ return []
+
+ periods.sort()
+ merged_periods = []
+
+ current_start, current_end, current_id = periods[0]
+
+ for start, end, id in periods[1:]:
+ if start <= current_end + timedelta(days=1):
+ current_end = max(current_end, end)
+ else:
+ merged_periods.append((current_start, current_end, current_id))
+ current_start, current_end, current_id = start, end, id
+
+ merged_periods.append((current_start, current_end, current_id))
+
+ return merged_periods
+
+ @staticmethod
+ def find_non_overlapping_periods(existing_periods, test_period):
+ existing_periods.sort(key=lambda x: x[0])
+
+ test_start, test_end, id = test_period
+ non_overlapping_periods = []
+
+ for start, end, _ in existing_periods:
+ if test_end < start:
+ non_overlapping_periods.append((test_start, test_end, id))
+ return non_overlapping_periods
+
+ elif test_start > end:
+ continue
+
+ else:
+ if test_start < start:
+ non_overlapping_periods.append((test_start, start - timedelta(days=1), id))
+
+ test_start = end + timedelta(days=1)
+
+ if test_start <= test_end:
+ non_overlapping_periods.append((test_start, test_end, id))
+
+ return non_overlapping_periods
+
+ def calculate_prediction(self, launch_date, duration, **kwargs):
+ total_days = 0
+ total_months = 0
+ updated = True
+ prediction_start = launch_date + duration - timedelta(days = 1)
+ prediction = prediction_start
+
+ events = []
+ half_projects = []
+ full_projects = []
+ other_kwargs = {}
+
+ for k, v in kwargs.items():
+ if k == "event":
+ events.extend(v)
+ elif k == "half_project":
+ half_projects.extend(v)
+ elif k == "full_project":
+ full_projects.extend(v)
+ elif k == "two_years":
+ full_projects.extend(v)
+ else:
+ other_kwargs[k] = v
+
+ while updated:
+ updated = False
+ considered_events = self.truncate_periods(events, launch_date, prediction)
+ considered_full_projects = self.truncate_periods(full_projects, launch_date, prediction)
+ considered_half_projects = self.truncate_periods(half_projects, launch_date, prediction)
+
+ considered_full_projects_merged = self.merge_periods(considered_full_projects)
+ considered_full_projects_rounded, months = self.round_periods(considered_full_projects_merged)
+ considered_full_projects_merged2 = self.merge_periods(considered_full_projects_rounded)
+ considered_full_projects_rounded2, months = self.round_periods(considered_full_projects_merged2)
+
+ non_overlapping_half_projects = []
+ for test_interval in considered_half_projects:
+ non_overlapping_half_projects.extend(
+ self.find_non_overlapping_periods(considered_full_projects_rounded2, test_interval)
+ )
+
+ considered_half_projects_merged = self.merge_periods(non_overlapping_half_projects)
+ considered_half_projects_rounded, months2 = self.round_periods(considered_half_projects_merged)
+ considered_half_projects_merged2 = self.merge_periods(considered_half_projects_rounded)
+ considered_half_projects_rounded2, months2 = self.round_periods(considered_half_projects_merged2)
+
+ all_projects_merged = self.merge_periods(
+ considered_full_projects_rounded2 + considered_half_projects_rounded2
+ )
+ merged_event_periods = self.merge_periods(considered_events)
+
+ non_overlapping_event_periods = []
+ for test_interval in merged_event_periods:
+ non_overlapping_event_periods.extend(
+ self.find_non_overlapping_periods(all_projects_merged, test_interval)
+ )
+
+ new_total_months = months + math.ceil(months2 / 2)
+ new_total_days = sum((end - start).days + 1 for start, end, _ in non_overlapping_event_periods)
+
+ if new_total_days != total_days or new_total_months != total_months:
+ total_days = new_total_days
+ total_months = new_total_months
+ updated = True
+ prediction = launch_date + duration + relativedelta(months=total_months) + timedelta(days=total_days-1)
+
+ # print(prediction, prediction_start + relativedelta(years = 6))
+ if prediction > prediction_start + relativedelta(years = 6):
+ prediction = prediction_start + relativedelta(years = 6)
+
return prediction, considered_full_projects_rounded2 + considered_half_projects_rounded2 + non_overlapping_event_periods
\ No newline at end of file |
