88from dateutil .relativedelta import relativedelta
99from django .apps import apps
1010from django .db import models
11- from django .db .models import (
12- Prefetch ,
13- Q ,
14- )
11+ from django .db .models import Prefetch , Q
1512from django .utils import timezone
1613
1714from app import config
@@ -388,12 +385,47 @@ def time_line_sort_key(media):
388385 return timezone .localdate (media .start_date )
389386
390387
388+ def _build_month_labels (date_range , week_start_weekday ):
389+ """Build month labels and their corresponding week counts for the activity grid."""
390+ months = []
391+ weeks_per_month = []
392+ current_month = date_range [0 ].strftime ("%b" )
393+ week_count = 0
394+
395+ for current_date in date_range :
396+ if current_date .weekday () == week_start_weekday :
397+ month = current_date .strftime ("%b" )
398+
399+ if current_month != month :
400+ if current_month is not None :
401+ if week_count > 1 :
402+ months .append (current_month )
403+ weeks_per_month .append (week_count )
404+ else :
405+ months .append ("" )
406+ weeks_per_month .append (week_count )
407+ current_month = month
408+ week_count = 0
409+
410+ week_count += 1
411+ # For the last month
412+ if week_count > 1 :
413+ months .append (current_month )
414+ weeks_per_month .append (week_count )
415+
416+ return months , weeks_per_month
417+
418+
391419def get_activity_data (user , start_date , end_date ):
392420 """Get daily activity counts for the last year."""
393421 if end_date is None :
394422 end_date = timezone .localtime ()
395423
396- start_date_aligned = get_aligned_monday (start_date )
424+ week_start_sunday = getattr (user , "week_start_day" , "monday" ) == "sunday"
425+ start_date_aligned = get_aligned_week_start (
426+ start_date ,
427+ week_start_sunday = week_start_sunday ,
428+ )
397429
398430 combined_data = get_filtered_historical_data (start_date_aligned , end_date , user )
399431
@@ -404,7 +436,10 @@ def get_activity_data(user, start_date, end_date):
404436 min (dates ) if dates else timezone .localdate (),
405437 datetime .time .min ,
406438 )
407- start_date_aligned = get_aligned_monday (start_date )
439+ start_date_aligned = get_aligned_week_start (
440+ start_date ,
441+ week_start_sunday = week_start_sunday ,
442+ )
408443
409444 # Aggregate counts by date
410445 date_counts = {}
@@ -440,36 +475,19 @@ def get_activity_data(user, start_date, end_date):
440475 # Format data into calendar weeks
441476 calendar_weeks = [activity_data [i : i + 7 ] for i in range (0 , len (activity_data ), 7 )]
442477
443- # Generate months list with their Monday counts
444- months = []
445- mondays_per_month = []
446- current_month = date_range [0 ].strftime ("%b" )
447- monday_count = 0
478+ # Generate months list with their week-start-day counts
479+ # The first day of each week column corresponds to the user's chosen week start day
480+ week_start_weekday = 6 if week_start_sunday else 0 # 0=Monday, 6=Sunday
481+ months , weeks_per_month = _build_month_labels (date_range , week_start_weekday )
448482
449- for current_date in date_range :
450- if current_date .weekday () == 0 : # Monday
451- month = current_date .strftime ("%b" )
452-
453- if current_month != month :
454- if current_month is not None :
455- if monday_count > 1 :
456- months .append (current_month )
457- mondays_per_month .append (monday_count )
458- else :
459- months .append ("" )
460- mondays_per_month .append (monday_count )
461- current_month = month
462- monday_count = 0
463-
464- monday_count += 1
465- # For the last month
466- if monday_count > 1 :
467- months .append (current_month )
468- mondays_per_month .append (monday_count )
483+ # Weekday labels depend on week start day
484+ days = list (calendar .day_abbr )
485+ weekday_labels = [days [6 ], * days [0 :6 ]] if week_start_sunday else days
469486
470487 return {
471488 "calendar_weeks" : calendar_weeks ,
472- "months" : list (zip (months , mondays_per_month , strict = False )),
489+ "months" : list (zip (months , weeks_per_month , strict = False )),
490+ "weekday_labels" : weekday_labels ,
473491 "stats" : {
474492 "most_active_day" : most_active_day ,
475493 "most_active_day_percentage" : day_percentage ,
@@ -479,12 +497,16 @@ def get_activity_data(user, start_date, end_date):
479497 }
480498
481499
482- def get_aligned_monday (datetime_obj ):
483- """Get the Monday of the week containing the given date."""
500+ def get_aligned_week_start (datetime_obj , * , week_start_sunday = False ):
501+ """Get the first day of the week containing the given date."""
484502 if datetime_obj is None :
485503 return None
486504
487- days_to_subtract = datetime_obj .weekday () # 0=Monday, 6=Sunday
505+ if week_start_sunday :
506+ # Sunday=weekday 6; if Sunday, subtract 0; else subtract (weekday+1)
507+ days_to_subtract = (datetime_obj .weekday () + 1 ) % 7
508+ else :
509+ days_to_subtract = datetime_obj .weekday () # 0=Monday, 6=Sunday
488510 return datetime_obj - datetime .timedelta (days = days_to_subtract )
489511
490512
0 commit comments