{t.rich("postNotebookMoveDateModalCopy", { - tournament_forecasting_end_date: - default_project?.forecasting_end_date - ? formatDate( - locale, - new Date(default_project.forecasting_end_date) - ) - : "", + tournament_close_date: default_project?.close_date + ? formatDate(locale, new Date(default_project.close_date)) + : "", question_close_date: approvalData.scheduled_close_time ? formatDate( locale, diff --git a/front_end/src/components/promo_tiles/tile_status_row.tsx b/front_end/src/components/promo_tiles/tile_status_row.tsx index 1656f24216..175bbb0ad2 100644 --- a/front_end/src/components/promo_tiles/tile_status_row.tsx +++ b/front_end/src/components/promo_tiles/tile_status_row.tsx @@ -83,8 +83,8 @@ function getScheduledCloseTime( const rawCloseTime = rule === FeedTileRule.ALL_QUESTIONS_RESOLVED && projectResolutionDate ? projectResolutionDate - : project.forecasting_end_date ?? - project.close_date ?? + : project.close_date ?? + project.winners_announced_date ?? project.start_date; const rawCloseTs = safeTs(rawCloseTime) ?? Date.now() + 1000; return new Date(Math.max(rawCloseTs, Date.now() + 1000)).toISOString(); @@ -102,7 +102,7 @@ function getStatusLabel( } = {} ): ReactNode | null { const now = Date.now(); - const closeTs = safeTs(project.forecasting_end_date ?? project.close_date); + const closeTs = safeTs(project.close_date ?? project.winners_announced_date); const startTs = safeTs(project.start_date); const resolveTs = safeTs(projectResolutionDate); diff --git a/front_end/src/stories/feed_card/binary_group/mock_data.ts b/front_end/src/stories/feed_card/binary_group/mock_data.ts index 1a3a8c881e..5d445654bf 100644 --- a/front_end/src/stories/feed_card/binary_group/mock_data.ts +++ b/front_end/src/stories/feed_card/binary_group/mock_data.ts @@ -61,8 +61,8 @@ export const getMockData = (isResolved: boolean, isFanChart?: boolean) => { header_image: null, prize_pool: null, start_date: "2025-06-18T13:00:10Z", + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: true, user_permission: null, @@ -82,8 +82,8 @@ export const getMockData = (isResolved: boolean, isFanChart?: boolean) => { header_image: null, prize_pool: null, start_date: "2025-06-18T13:00:10Z", + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: true, user_permission: null, diff --git a/front_end/src/stories/feed_card/binary_question/mock_data.ts b/front_end/src/stories/feed_card/binary_question/mock_data.ts index 4970bac01d..7e3419e002 100644 --- a/front_end/src/stories/feed_card/binary_question/mock_data.ts +++ b/front_end/src/stories/feed_card/binary_question/mock_data.ts @@ -35,8 +35,8 @@ export const getMockData = (isResolved: boolean) => { header_image: "https://cdn.metaculus.com/mcup-banner.jpg", prize_pool: "5000.00", start_date: "2025-05-02T17:00:00Z", - close_date: "2025-09-04T00:00:00Z", - forecasting_end_date: "2025-09-01T00:00:00Z", + winners_announced_date: "2025-09-04T00:00:00Z", + close_date: "2025-09-01T00:00:00Z", meta_description: "", is_ongoing: true, user_permission: null, @@ -56,8 +56,8 @@ export const getMockData = (isResolved: boolean) => { header_image: "https://cdn.metaculus.com/mcup-banner.jpg", prize_pool: "5000.00", start_date: "2025-05-02T17:00:00Z", - close_date: "2025-09-04T00:00:00Z", - forecasting_end_date: "2025-09-01T00:00:00Z", + winners_announced_date: "2025-09-04T00:00:00Z", + close_date: "2025-09-01T00:00:00Z", meta_description: "", is_ongoing: true, user_permission: null, diff --git a/front_end/src/stories/feed_card/continuous_question/mock_data.ts b/front_end/src/stories/feed_card/continuous_question/mock_data.ts index f6a950ea33..4515a24806 100644 --- a/front_end/src/stories/feed_card/continuous_question/mock_data.ts +++ b/front_end/src/stories/feed_card/continuous_question/mock_data.ts @@ -61,8 +61,8 @@ export const getMockData = (isResolved: boolean) => { header_image: null, prize_pool: null, start_date: "2025-06-18T13:00:10Z", + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: true, user_permission: "admin", @@ -81,8 +81,8 @@ export const getMockData = (isResolved: boolean) => { header_image: null, prize_pool: null, start_date: "2025-06-19T16:05:02Z", + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: true, user_permission: null, @@ -102,8 +102,8 @@ export const getMockData = (isResolved: boolean) => { header_image: null, prize_pool: null, start_date: "2025-06-19T16:05:02Z", + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: true, user_permission: null, diff --git a/front_end/src/stories/feed_card/date_group/mock_data.tsx b/front_end/src/stories/feed_card/date_group/mock_data.tsx index 6099a3b02b..deffb8b18d 100644 --- a/front_end/src/stories/feed_card/date_group/mock_data.tsx +++ b/front_end/src/stories/feed_card/date_group/mock_data.tsx @@ -51,8 +51,8 @@ export const getMockData = (isResolved: boolean, isFanChart?: boolean) => { header_image: null, prize_pool: null, start_date: null, + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: null, user_permission: null, @@ -72,8 +72,8 @@ export const getMockData = (isResolved: boolean, isFanChart?: boolean) => { header_image: null, prize_pool: null, start_date: null, + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: null, user_permission: null, diff --git a/front_end/src/stories/feed_card/date_question/mock_data.ts b/front_end/src/stories/feed_card/date_question/mock_data.ts index 011be17a82..e76be21f36 100644 --- a/front_end/src/stories/feed_card/date_question/mock_data.ts +++ b/front_end/src/stories/feed_card/date_question/mock_data.ts @@ -53,8 +53,8 @@ export const getMockData = (isResolved: boolean) => { header_image: "https://cdn.metaculus.com/neural_net.png", prize_pool: "6500.00", start_date: "2022-02-08T13:02:52Z", - close_date: "2022-04-16T15:54:55Z", - forecasting_end_date: null, + winners_announced_date: "2022-04-16T15:54:55Z", + close_date: null, meta_description: "Welcome to the AI Progress Essay Contest! Metaculus aims to support accurate forecasting of and preparation for the impacts of transformative AI.\r\n\r\nThank you for your participation!", is_ongoing: false, @@ -74,8 +74,8 @@ export const getMockData = (isResolved: boolean) => { header_image: "https://cdn.metaculus.com/agi.png", prize_pool: null, start_date: "2023-08-09T13:41:42.701000Z", - close_date: "2023-08-09T13:41:42.701000Z", - forecasting_end_date: null, + winners_announced_date: "2023-08-09T13:41:42.701000Z", + close_date: null, meta_description: "", is_ongoing: false, user_permission: null, @@ -109,8 +109,8 @@ export const getMockData = (isResolved: boolean) => { header_image: "https://cdn.metaculus.com/agi.png", prize_pool: null, start_date: "2023-08-09T13:41:42.701000Z", - close_date: "2023-08-09T13:41:42.701000Z", - forecasting_end_date: null, + winners_announced_date: "2023-08-09T13:41:42.701000Z", + close_date: null, meta_description: "", is_ongoing: false, user_permission: null, @@ -148,8 +148,8 @@ export const getMockData = (isResolved: boolean) => { header_image: null, prize_pool: null, start_date: null, + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: null, user_permission: "admin", diff --git a/front_end/src/stories/feed_card/mc_question/mock_data.ts b/front_end/src/stories/feed_card/mc_question/mock_data.ts index ab0448fb12..1490d16e8c 100644 --- a/front_end/src/stories/feed_card/mc_question/mock_data.ts +++ b/front_end/src/stories/feed_card/mc_question/mock_data.ts @@ -54,8 +54,8 @@ export const getMockData = (isResolved: boolean) => { header_image: "https://cdn.metaculus.com/2027-banner.jpg", prize_pool: null, start_date: "2025-06-10T00:00:00Z", + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: true, user_permission: null, @@ -75,8 +75,8 @@ export const getMockData = (isResolved: boolean) => { header_image: "https://cdn.metaculus.com/2027-banner.jpg", prize_pool: null, start_date: "2025-06-10T00:00:00Z", + winners_announced_date: null, close_date: null, - forecasting_end_date: null, meta_description: "", is_ongoing: true, user_permission: null, diff --git a/front_end/src/stories/feed_card/numeric_group/mock_data.ts b/front_end/src/stories/feed_card/numeric_group/mock_data.ts index ab7dce5802..e8489e7b04 100644 --- a/front_end/src/stories/feed_card/numeric_group/mock_data.ts +++ b/front_end/src/stories/feed_card/numeric_group/mock_data.ts @@ -35,8 +35,8 @@ export const getMockData = (isResolved: boolean, isFanChart?: boolean) => { header_image: "https://cdn.metaculus.com/potus-banner0.5x.webp", prize_pool: "15000.00", start_date: "2025-03-28T12:00:00Z", - close_date: "2029-01-20T00:00:00Z", - forecasting_end_date: "2029-01-03T00:00:00Z", + winners_announced_date: "2029-01-20T00:00:00Z", + close_date: "2029-01-03T00:00:00Z", meta_description: "", is_ongoing: true, user_permission: null, @@ -56,8 +56,8 @@ export const getMockData = (isResolved: boolean, isFanChart?: boolean) => { header_image: "https://cdn.metaculus.com/potus-banner0.5x.webp", prize_pool: "15000.00", start_date: "2025-03-28T12:00:00Z", - close_date: "2029-01-20T00:00:00Z", - forecasting_end_date: "2029-01-03T00:00:00Z", + winners_announced_date: "2029-01-20T00:00:00Z", + close_date: "2029-01-03T00:00:00Z", meta_description: "", is_ongoing: true, user_permission: null, diff --git a/front_end/src/types/projects.ts b/front_end/src/types/projects.ts index 37d6e07458..8541d9f35a 100644 --- a/front_end/src/types/projects.ts +++ b/front_end/src/types/projects.ts @@ -45,7 +45,7 @@ export enum TaxonomyProjectType { export enum TournamentsSortBy { Featured = "featured", PrizePoolDesc = "-prize_pool", - CloseDateAsc = "close_date", + WinnersAnnouncedDateAsc = "winners_announced_date", StartDateDesc = "-start_date", } @@ -62,8 +62,8 @@ export type TournamentPreview = Project & { forecasters_count: number; prize_pool: string | null; start_date: string; + winners_announced_date?: string; close_date?: string; - forecasting_end_date?: string; is_ongoing: boolean; created_at: string; questions_count: number; diff --git a/posts/services/common.py b/posts/services/common.py index 79098f0f2e..8ddef033d7 100644 --- a/posts/services/common.py +++ b/posts/services/common.py @@ -19,7 +19,7 @@ from projects.services.common import ( get_projects_staff_users, get_site_main_project, - move_project_forecasting_end_date, + move_project_close_date, ) from questions.models import Question from questions.services.common import ( @@ -463,7 +463,7 @@ def approve_post( Project.ProjectTypes.TOURNAMENT, Project.ProjectTypes.QUESTION_SERIES, ]: - move_project_forecasting_end_date(project, post) + move_project_close_date(project, post) post.update_pseudo_materialized_fields() diff --git a/projects/admin.py b/projects/admin.py index f356b9928c..17b86b2f8c 100644 --- a/projects/admin.py +++ b/projects/admin.py @@ -187,7 +187,7 @@ def closes_before(self, obj): if project.primary_leaderboard else None ) - finalize_time = finalize_time or project.close_date + finalize_time = finalize_time or project.winners_announced_date if not finalize_time: return True @@ -211,7 +211,7 @@ def resolved_before(self, obj): if project.primary_leaderboard else None ) - finalize_time = finalize_time or project.close_date + finalize_time = finalize_time or project.winners_announced_date if not finalize_time: return True @@ -368,19 +368,23 @@ def __init__(self, *args, **kwargs): def clean(self): cleaned_data = super().clean() start_date = cleaned_data.get("start_date") - forecasting_end_date = cleaned_data.get("forecasting_end_date") close_date = cleaned_data.get("close_date") + winners_announced_date = cleaned_data.get("winners_announced_date") - if forecasting_end_date and close_date and forecasting_end_date > close_date: + if ( + close_date + and winners_announced_date + and close_date > winners_announced_date + ): self.add_error( - "forecasting_end_date", - "Forecasting end date must be before the close date.", + "close_date", + "Close date must be before the winners announced date.", ) - if start_date and forecasting_end_date and start_date > forecasting_end_date: + if start_date and close_date and start_date > close_date: self.add_error( "start_date", - "Start date must be before the forecasting end date.", + "Start date must be before the close date.", ) return cleaned_data @@ -844,7 +848,7 @@ def questions_summary(self, obj): all_ids = list(all_questions.values_list("id", flat=True)) all_count = len(all_ids) - finalize_time = leaderboard.finalize_time or obj.close_date + finalize_time = leaderboard.finalize_time or obj.winners_announced_date if finalize_time: in_leaderboard_qs = all_questions.filter( Q(resolution_set_time__isnull=True) @@ -920,7 +924,9 @@ def primary_leaderboard_finalize_time(self, obj): return None leaderboard = obj.primary_leaderboard if leaderboard: - return leaderboard.finalize_time or (obj.close_date if obj else None) + return leaderboard.finalize_time or ( + obj.winners_announced_date if obj else None + ) primary_leaderboard_finalize_time.short_description = ( "Time when Primary Leaderboard is Finalized" diff --git a/projects/migrations/0024_rename_project_date_fields.py b/projects/migrations/0024_rename_project_date_fields.py new file mode 100644 index 0000000000..761368de89 --- /dev/null +++ b/projects/migrations/0024_rename_project_date_fields.py @@ -0,0 +1,53 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("projects", "0023_alter_project_bot_leaderboard_status"), + ] + + operations = [ + # Swap close_date and forecasting_end_date via a temporary name. + # close_date (old: tournament wrap-up) -> winners_announced_date + # forecasting_end_date (old: last scored question close) -> close_date + migrations.RenameField( + model_name="project", + old_name="close_date", + new_name="_winners_announced_date_tmp", + ), + migrations.RenameField( + model_name="project", + old_name="forecasting_end_date", + new_name="close_date", + ), + migrations.RenameField( + model_name="project", + old_name="_winners_announced_date_tmp", + new_name="winners_announced_date", + ), + migrations.AlterField( + model_name="project", + name="winners_announced_date", + field=models.DateTimeField( + blank=True, + help_text=( + "The date the tournament wraps up and prizes will be paid. " + "All questions that should be included in the leaderboard must close and resolve before this date." + ), + null=True, + ), + ), + migrations.AlterField( + model_name="project", + name="close_date", + field=models.DateTimeField( + blank=True, + help_text=( + "The date the last question that counts for the tournament is scheduled to close. " + "If such questions have scheduled close dates after the project Winners announced date, " + "the front end will show the latest of these close dates." + ), + null=True, + ), + ), + ] diff --git a/projects/models.py b/projects/models.py index 3566ccc4fb..a64fadbf2c 100644 --- a/projects/models.py +++ b/projects/models.py @@ -302,22 +302,21 @@ class BotLeaderboardStatus(models.TextChoices): default=None, decimal_places=2, max_digits=15, null=True, blank=True ) start_date = models.DateTimeField(null=True, blank=True) - close_date = models.DateTimeField( + winners_announced_date = models.DateTimeField( null=True, blank=True, help_text=( "The date the tournament wraps up and prizes will be paid. " - "All questions that should be included in the leaderboard must close and resolve before this date. " - "This is displayed on the front end as the “Winners announced date”" + "All questions that should be included in the leaderboard must close and resolve before this date." ), ) - forecasting_end_date = models.DateTimeField( + close_date = models.DateTimeField( null=True, blank=True, help_text=( - "The date the last scored question that counts for the tournament closes." - "The date shown is the latest of the Forecasting end date " - "and the latest question close date closing and resolving before the Close date." + "The date the last question that counts for the tournament is scheduled to close. " + "If such questions have scheduled close dates after the project Winners announced date, " + "the front end will show the latest of these close dates." ), ) sign_up_fields = models.JSONField( @@ -454,7 +453,11 @@ def is_ongoing(self): self.ProjectTypes.QUESTION_SERIES, self.ProjectTypes.INDEX, ): - return self.close_date > django_timezone.now() if self.close_date else True + return ( + self.winners_announced_date > django_timezone.now() + if self.winners_announced_date + else True + ) def get_users_for_permission(self, min_permission: ObjectPermission): """ diff --git a/projects/serializers/common.py b/projects/serializers/common.py index 45de14bcef..3c93a60bc4 100644 --- a/projects/serializers/common.py +++ b/projects/serializers/common.py @@ -35,8 +35,8 @@ class Meta: "order", "prize_pool", "start_date", + "winners_announced_date", "close_date", - "forecasting_end_date", "html_metadata_json", "default_permission", "visibility", @@ -90,8 +90,8 @@ class Meta: "header_image", "prize_pool", "start_date", + "winners_announced_date", "close_date", - "forecasting_end_date", "html_metadata_json", "is_ongoing", "user_permission", diff --git a/projects/services/common.py b/projects/services/common.py index 2250624d75..3a4ce73d04 100644 --- a/projects/services/common.py +++ b/projects/services/common.py @@ -138,25 +138,22 @@ def get_projects_for_posts( return post_projects_map -def move_project_forecasting_end_date(project: Project, post: Post): - if not project.close_date: +def move_project_close_date(project: Project, post: Post): + if not project.winners_announced_date: return - forecasting_end_date = project.forecasting_end_date + close_date = project.close_date for question in post.get_questions(): if ( - question.scheduled_close_time <= project.close_date - and question.scheduled_resolve_time <= project.close_date - and ( - not forecasting_end_date - or question.scheduled_close_time > forecasting_end_date - ) + question.scheduled_close_time <= project.winners_announced_date + and question.scheduled_resolve_time <= project.winners_announced_date + and (not close_date or question.scheduled_close_time > close_date) ): - forecasting_end_date = question.scheduled_close_time + close_date = question.scheduled_close_time - project.forecasting_end_date = forecasting_end_date - project.save(update_fields=["forecasting_end_date"]) + project.close_date = close_date + project.save(update_fields=["close_date"]) def get_questions_by_project( @@ -214,23 +211,24 @@ def _calculate_timeline_data(project: Project, questions: Iterable[Question]) -> actual_resolve_times = [] scheduled_resolve_times = [] - project_close_date = project.close_date or make_aware(datetime.max) - project_forecasting_end_date = project.forecasting_end_date or project_close_date + project_winners_announced_date = project.winners_announced_date or make_aware( + datetime.max + ) + project_close_date = project.close_date or project_winners_announced_date for question in questions: if all_questions_resolved: all_questions_resolved = ( question.actual_resolve_time # Or treat as resolved as scheduled resolution is in the future - or question.scheduled_resolve_time > project_close_date + or question.scheduled_resolve_time > project_winners_announced_date ) # Determine questions closure if all_questions_closed: close_time = question.actual_close_time or question.scheduled_close_time all_questions_closed = ( - close_time <= timezone.now() - or close_time > project_forecasting_end_date + close_time <= timezone.now() or close_time > project_close_date ) spot_scoring_time = question.get_spot_scoring_time() @@ -247,7 +245,9 @@ def _calculate_timeline_data(project: Project, questions: Iterable[Question]) -> scheduled_resolve_times.append(scheduled_resolve_time) def get_max(data: list): - return max([x for x in data if x <= project_close_date], default=None) + return max( + [x for x in data if x <= project_winners_announced_date], default=None + ) return { "last_spot_scoring_time": get_max(spot_scoring_times), @@ -381,13 +381,15 @@ def get_feed_project_tiles() -> list[dict]: for q in questions if q.resolution_set_time and q.resolution_set_time >= three_days_ago ) - project_close_date = project.close_date or make_aware(datetime.max) + project_winners_announced_date = project.winners_announced_date or make_aware( + datetime.max + ) all_resolved = len(questions) > 0 and all( q.actual_resolve_time # Or treat as resolved if scheduled resolution is in the future or ( q.scheduled_resolve_time - and q.scheduled_resolve_time > project_close_date + and q.scheduled_resolve_time > project_winners_announced_date ) for q in questions ) @@ -397,12 +399,12 @@ def get_feed_project_tiles() -> list[dict]: for q in questions if q.actual_resolve_time and q.resolution_set_time - and q.actual_resolve_time <= project_close_date + and q.actual_resolve_time <= project_winners_announced_date ), default=None, ) project_resolution_date = ( - max(last_resolve_time, project.close_date or last_resolve_time) + max(last_resolve_time, project.winners_announced_date or last_resolve_time) if last_resolve_time else None ) @@ -443,9 +445,9 @@ def get_feed_project_tiles() -> list[dict]: p for p in projects if p.start_date - and p.close_date - and (total := (p.close_date - p.start_date).total_seconds()) > 0 - and (p.close_date - now).total_seconds() / total > 0.5 + and p.winners_announced_date + and (total := (p.winners_announced_date - p.start_date).total_seconds()) > 0 + and (p.winners_announced_date - now).total_seconds() / total > 0.5 ] if candidates: pick = random.choice(candidates) diff --git a/scoring/jobs.py b/scoring/jobs.py index b6a6c54d5c..06a148fb11 100644 --- a/scoring/jobs.py +++ b/scoring/jobs.py @@ -45,7 +45,7 @@ def finalize_leaderboards(): active_leaderboards = Leaderboard.objects.filter(finalized=False) for leaderboard in active_leaderboards: finalize_time = leaderboard.finalize_time or ( - leaderboard.project.close_date if leaderboard.project else None + leaderboard.project.winners_announced_date if leaderboard.project else None ) if finalize_time and finalize_time <= timezone.now(): logger.info(f"Finalizing leaderboard: {leaderboard}") diff --git a/scoring/migrations/0022_alter_leaderboard_finalize_time.py b/scoring/migrations/0022_alter_leaderboard_finalize_time.py new file mode 100644 index 0000000000..bd8576a8ec --- /dev/null +++ b/scoring/migrations/0022_alter_leaderboard_finalize_time.py @@ -0,0 +1,22 @@ +# Generated by Django 5.2.14 on 2026-08-07 13:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("scoring", "0021_remove_leaderboard_bot_status_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="leaderboard", + name="finalize_time", + field=models.DateTimeField( + blank=True, + help_text="Optional. If not set, the Project's winners_announced_date will be used instead.\n - For all Leaderboards: used to filter out questions that have a resolution_set_time after this (as they were resolved after this Leaderboard was finalized).\n - Filtering MedalExclusionRecords: If set and end_time is not set, MedalExclusionRecords that have a start_time less than this (and no end_time or an end_time later that this Leaderboard's start_time) will be triggered.\n ", + null=True, + ), + ), + ] diff --git a/scoring/models.py b/scoring/models.py index 926ebdb405..30d34ca654 100644 --- a/scoring/models.py +++ b/scoring/models.py @@ -177,7 +177,7 @@ class Leaderboard(TimeStampedModel): finalize_time = models.DateTimeField( null=True, blank=True, - help_text="""Optional. If not set, the Project's close_date will be used instead. + help_text="""Optional. If not set, the Project's winners_announced_date will be used instead. - For all Leaderboards: used to filter out questions that have a resolution_set_time after this (as they were resolved after this Leaderboard was finalized). - Filtering MedalExclusionRecords: If set and end_time is not set, MedalExclusionRecords that have a start_time less than this (and no end_time or an end_time later that this Leaderboard's start_time) will be triggered. """, diff --git a/scoring/utils.py b/scoring/utils.py index 4e287fbd7c..619c05680d 100644 --- a/scoring/utils.py +++ b/scoring/utils.py @@ -152,7 +152,7 @@ def retrieve_question_scores( } finalize_time = leaderboard.finalize_time or ( - leaderboard.project.close_date if leaderboard.project else None + leaderboard.project.winners_announced_date if leaderboard.project else None ) if finalize_time: qs_filters["question__scheduled_close_time__lte"] = finalize_time @@ -446,10 +446,10 @@ def assign_exclusions_( leaderboard.project.start_date if leaderboard.project else None ) end_time = leaderboard.end_time or ( - leaderboard.project.close_date if leaderboard.project else None + leaderboard.project.winners_announced_date if leaderboard.project else None ) finalize_time = leaderboard.finalize_time or ( - leaderboard.project.close_date if leaderboard.project else None + leaderboard.project.winners_announced_date if leaderboard.project else None ) if start_time: exclusion_records = exclusion_records.filter( @@ -592,7 +592,7 @@ def calculate_medals_points_at_time(at_time): # Look only at leaderboard entries which are closed before the timestamp relevant_entries_qs = LeaderboardEntry.objects.filter( Q(leaderboard__end_time__lte=at_time) - | Q(leaderboard__project__close_date__lte=at_time), + | Q(leaderboard__project__winners_announced_date__lte=at_time), leaderboard__project__default_permission=ObjectPermission.FORECASTER, ) @@ -601,7 +601,10 @@ def calculate_medals_points_at_time(at_time): leaderboard_age_expr = Case( When( leaderboard__project__type="tournament", - then=(at_time.year - ExtractYear(F("leaderboard__project__close_date"))), + then=( + at_time.year + - ExtractYear(F("leaderboard__project__winners_announced_date")) + ), ), When( leaderboard__end_time__isnull=False, @@ -779,7 +782,7 @@ def process_entries_for_leaderboard_( assign_prizes_(entries, prize_pool) # check if we're ready to finalize and assign medals/prizes if applicable finalize_time = leaderboard.finalize_time or ( - project.close_date if project else None + project.winners_announced_date if project else None ) if force_finalize or (finalize_time and (timezone.now() >= finalize_time)): if (