@@ -415,11 +415,22 @@ def check_start_and_end_dates_sensible(self) -> typing.Self:
415415
416416 @model_validator (mode = "after" )
417417 def check_no_overlapping_iterations (self ) -> typing .Self :
418- iterations_by_date = Counter ([i .iteration_date for i in self .iterations ])
419- if multiple_found := next (((d , c ) for d , c in iterations_by_date .most_common () if c > 1 ), None ):
420- iteration_date , count = multiple_found
421- message = f"{ count } iterations with iteration date { iteration_date } in campaign { self .id } "
418+ date_time_pairs = []
419+ for i in self .iterations :
420+ effective_time = i .iteration_time or self .iteration_time
421+ date_time_pairs .append ((i .iteration_date , effective_time ))
422+
423+ counts = Counter (date_time_pairs )
424+
425+ duplicate = next (((dt , c ) for dt , c in counts .items () if c > 1 ), None )
426+
427+ if duplicate :
428+ (iteration_date , iteration_time ), count = duplicate
429+ message = (
430+ f"{ count } iterations with iteration date/time { iteration_date } { iteration_time } in campaign { self .id } "
431+ )
422432 raise ValueError (message )
433+
423434 return self
424435
425436 @cached_property
@@ -429,9 +440,9 @@ def campaign_live(self) -> bool:
429440
430441 @cached_property
431442 def current_iteration (self ) -> Iteration :
432- today = datetime .now (tz = UTC ). date ( )
433- iterations_by_date_descending = sorted (self .iterations , key = attrgetter ("iteration_date " ), reverse = True )
434- return next (i for i in iterations_by_date_descending if i .iteration_date <= today )
443+ now = datetime .now (tz = UTC )
444+ iterations_by_date_descending = sorted (self .iterations , key = attrgetter ("iteration_datetime " ), reverse = True )
445+ return next (i for i in iterations_by_date_descending if i .iteration_datetime <= now )
435446
436447 def __str__ (self ) -> str :
437448 return json .dumps (self .model_dump (by_alias = True ), indent = 2 )
0 commit comments