summaryrefslogtreecommitdiff
path: root/date_calculator.py
diff options
context:
space:
mode:
Diffstat (limited to 'date_calculator.py')
-rw-r--r--date_calculator.py131
1 files changed, 50 insertions, 81 deletions
diff --git a/date_calculator.py b/date_calculator.py
index fe74827..bca7dda 100644
--- a/date_calculator.py
+++ b/date_calculator.py
@@ -1,11 +1,14 @@
-# date_calculator.py
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
import math
class DateCalculator:
@staticmethod
- def truncate_periods(periods, launch, prediction):
+ def sort_periods(periods):
+ return sorted(periods, key=lambda p: (p[0], p[1]))
+
+ @staticmethod
+ def truncate_periods(periods, launch):
considered_periods = []
for start, end, id in periods:
# print(start)
@@ -19,8 +22,14 @@ class DateCalculator:
def round_periods(periods):
rounded_periods = []
total_months = 0
+
+ last_end = None
for start, end, id in periods:
+ if last_end and start <= last_end:
+ start = last_end + timedelta(days=1)
+ if start > end:
+ continue
year_diff = end.year - start.year
month_diff = end.month - start.month
months = year_diff * 12 + month_diff
@@ -30,29 +39,9 @@ class DateCalculator:
rounded_periods.append((start, rounded_end, id))
total_months += months
+ last_end = rounded_end
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 adjust_periods(periods):
@@ -63,9 +52,6 @@ class DateCalculator:
if not periods:
return []
- # Sort by start date, then end date for stability
- periods = sorted(periods, key=lambda p: (p[0], p[1]))
-
adjusted = []
for start, end, pid in periods:
if not adjusted:
@@ -87,10 +73,9 @@ class DateCalculator:
adjusted.append((start, end, pid))
return adjusted
-
+
@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 = []
@@ -113,19 +98,16 @@ class DateCalculator:
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
+
+ @staticmethod
+ def calculate_prediction(launch_date, duration, **kwargs):
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 == "Sonstige":
events.extend(v)
@@ -137,51 +119,38 @@ class DateCalculator:
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
+
+ events = DateCalculator.sort_periods(events)
+ half_projects = DateCalculator.sort_periods(half_projects)
+ full_projects = DateCalculator.sort_periods(full_projects)
+
+ considered_events = DateCalculator.truncate_periods(events, launch_date)
+ considered_full_projects = DateCalculator.truncate_periods(full_projects, launch_date)
+ considered_half_projects = DateCalculator.truncate_periods(half_projects, launch_date)
+
+ considered_full_projects_rounded, months = DateCalculator.round_periods(considered_full_projects)
+
+ non_overlapping_half_projects = []
+ for test_interval in considered_half_projects:
+ non_overlapping_half_projects.extend(
+ DateCalculator.find_non_overlapping_periods(considered_full_projects_rounded, test_interval)
+ )
+
+ considered_half_projects_rounded, months2 = DateCalculator.round_periods(non_overlapping_half_projects)
+
+ all_projects_merged = DateCalculator.sort_periods(considered_full_projects_rounded + considered_half_projects_rounded)
+ merged_event_periods = DateCalculator.adjust_periods(considered_events)
+
+ non_overlapping_event_periods = []
+ for test_interval in merged_event_periods:
+ non_overlapping_event_periods.extend(
+ DateCalculator.find_non_overlapping_periods(all_projects_merged, test_interval)
)
- merged_event_periods = self.adjust_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
+ total_months = months + math.ceil(months2 / 2)
+ total_days = sum((end - start).days + 1 for start, end, _ in non_overlapping_event_periods)
+ prediction = launch_date + duration + relativedelta(months=total_months) + timedelta(days=total_days-1)
+
+ prediction = min(prediction, prediction_start + relativedelta(years = 6))
+
+ return prediction, considered_full_projects_rounded + considered_half_projects_rounded + non_overlapping_event_periods \ No newline at end of file