Internationalization and Localization

Timezone Support

Modern web applications serve users across multiple time zones, making proper timezone handling essential for accurate time display and scheduling. Django provides comprehensive timezone support that automatically handles timezone conversion, user preferences, and daylight saving time transitions while maintaining data integrity and user experience.

Timezone Support

Modern web applications serve users across multiple time zones, making proper timezone handling essential for accurate time display and scheduling. Django provides comprehensive timezone support that automatically handles timezone conversion, user preferences, and daylight saving time transitions while maintaining data integrity and user experience.

Django Timezone Configuration

Basic Timezone Settings

# settings.py
import os
from django.utils.translation import gettext_lazy as _

# Enable timezone support
USE_TZ = True

# Default timezone (UTC recommended for storage)
TIME_ZONE = 'UTC'

# Available timezones for user selection
COMMON_TIMEZONES = [
    ('UTC', 'UTC'),
    ('US/Eastern', 'Eastern Time (US & Canada)'),
    ('US/Central', 'Central Time (US & Canada)'),
    ('US/Mountain', 'Mountain Time (US & Canada)'),
    ('US/Pacific', 'Pacific Time (US & Canada)'),
    ('Europe/London', 'London'),
    ('Europe/Paris', 'Paris'),
    ('Europe/Berlin', 'Berlin'),
    ('Asia/Tokyo', 'Tokyo'),
    ('Asia/Shanghai', 'Shanghai'),
    ('Australia/Sydney', 'Sydney'),
]

# Timezone detection settings
TIMEZONE_COOKIE_NAME = 'timezone'
TIMEZONE_COOKIE_AGE = 365 * 24 * 60 * 60  # 1 year

Advanced Timezone Configuration

# settings/base.py
import pytz
from django.conf import settings

# Generate timezone choices from pytz
def get_timezone_choices():
    """Generate timezone choices for forms."""
    common_timezones = [
        'UTC',
        'US/Eastern', 'US/Central', 'US/Mountain', 'US/Pacific',
        'Europe/London', 'Europe/Paris', 'Europe/Berlin', 'Europe/Rome',
        'Asia/Tokyo', 'Asia/Shanghai', 'Asia/Kolkata', 'Asia/Dubai',
        'Australia/Sydney', 'Australia/Melbourne',
        'America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles',
        'America/Toronto', 'America/Mexico_City', 'America/Sao_Paulo',
    ]
    
    choices = []
    for tz in common_timezones:
        try:
            timezone = pytz.timezone(tz)
            # Get timezone display name
            display_name = tz.replace('_', ' ').replace('/', ' - ')
            choices.append((tz, display_name))
        except pytz.exceptions.UnknownTimeZoneError:
            continue
    
    return sorted(choices, key=lambda x: x[1])

TIMEZONE_CHOICES = get_timezone_choices()

# Timezone middleware configuration
TIMEZONE_MIDDLEWARE_ENABLED = True
TIMEZONE_AUTO_DETECT = True

User Timezone Management

User Profile with Timezone

# models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from django.conf import settings
import pytz

class UserProfile(models.Model):
    """User profile with timezone preferences."""
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    timezone = models.CharField(
        max_length=50,
        choices=settings.TIMEZONE_CHOICES,
        default='UTC',
        verbose_name=_('Timezone'),
        help_text=_('Select your local timezone')
    )
    auto_detect_timezone = models.BooleanField(
        default=True,
        verbose_name=_('Auto-detect timezone'),
        help_text=_('Automatically detect timezone from browser')
    )
    date_format = models.CharField(
        max_length=20,
        choices=[
            ('%Y-%m-%d', 'YYYY-MM-DD'),
            ('%m/%d/%Y', 'MM/DD/YYYY'),
            ('%d/%m/%Y', 'DD/MM/YYYY'),
            ('%d.%m.%Y', 'DD.MM.YYYY'),
        ],
        default='%Y-%m-%d',
        verbose_name=_('Date Format')
    )
    time_format = models.CharField(
        max_length=20,
        choices=[
            ('%H:%M', '24-hour (HH:MM)'),
            ('%I:%M %p', '12-hour (HH:MM AM/PM)'),
        ],
        default='%H:%M',
        verbose_name=_('Time Format')
    )
    
    class Meta:
        verbose_name = _('User Profile')
        verbose_name_plural = _('User Profiles')
    
    def get_timezone(self):
        """Get user's timezone as pytz timezone object."""
        return pytz.timezone(self.timezone)
    
    def get_local_time(self, utc_datetime):
        """Convert UTC datetime to user's local time."""
        if not utc_datetime:
            return None
        
        user_tz = self.get_timezone()
        if utc_datetime.tzinfo is None:
            # Assume UTC if no timezone info
            from django.utils import timezone
            utc_datetime = timezone.make_aware(utc_datetime, pytz.UTC)
        
        return utc_datetime.astimezone(user_tz)
    
    def format_datetime(self, dt):
        """Format datetime according to user preferences."""
        if not dt:
            return ''
        
        local_dt = self.get_local_time(dt)
        date_str = local_dt.strftime(self.date_format)
        time_str = local_dt.strftime(self.time_format)
        return f"{date_str} {time_str}"

# Signal to create profile
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
    if created:
        UserProfile.objects.create(user=instance)

Timezone Detection Middleware

# middleware/timezone.py
import pytz
from django.utils import timezone
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings

class TimezoneMiddleware(MiddlewareMixin):
    """Middleware to activate user's timezone."""
    
    def process_request(self, request):
        """Activate appropriate timezone for the request."""
        user_timezone = self.get_user_timezone(request)
        
        if user_timezone:
            timezone.activate(user_timezone)
        else:
            timezone.deactivate()
    
    def get_user_timezone(self, request):
        """Determine user's timezone from various sources."""
        # 1. Check authenticated user's profile
        if hasattr(request, 'user') and request.user.is_authenticated:
            try:
                profile = request.user.userprofile
                if not profile.auto_detect_timezone:
                    return pytz.timezone(profile.timezone)
            except:
                pass
        
        # 2. Check session
        session_tz = request.session.get('timezone')
        if session_tz:
            try:
                return pytz.timezone(session_tz)
            except pytz.exceptions.UnknownTimeZoneError:
                pass
        
        # 3. Check cookie
        cookie_tz = request.COOKIES.get(settings.TIMEZONE_COOKIE_NAME)
        if cookie_tz:
            try:
                return pytz.timezone(cookie_tz)
            except pytz.exceptions.UnknownTimeZoneError:
                pass
        
        # 4. Check HTTP headers (from JavaScript detection)
        header_tz = request.META.get('HTTP_X_TIMEZONE')
        if header_tz:
            try:
                return pytz.timezone(header_tz)
            except pytz.exceptions.UnknownTimeZoneError:
                pass
        
        return None

Timezone-Aware Models

Models with Timezone Support

# models.py
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User
import pytz

class TimestampedModel(models.Model):
    """Abstract model with timezone-aware timestamps."""
    created_at = models.DateTimeField(
        auto_now_add=True,
        verbose_name=_('Created at')
    )
    updated_at = models.DateTimeField(
        auto_now=True,
        verbose_name=_('Updated at')
    )
    
    class Meta:
        abstract = True
    
    def get_created_at_local(self, user_timezone='UTC'):
        """Get creation time in specified timezone."""
        if isinstance(user_timezone, str):
            user_timezone = pytz.timezone(user_timezone)
        return self.created_at.astimezone(user_timezone)

class Event(TimestampedModel):
    """Event model with timezone-aware scheduling."""
    title = models.CharField(max_length=200, verbose_name=_('Title'))
    description = models.TextField(blank=True, verbose_name=_('Description'))
    
    # Store in UTC, display in user's timezone
    start_time = models.DateTimeField(verbose_name=_('Start Time'))
    end_time = models.DateTimeField(verbose_name=_('End Time'))
    
    # Store the timezone for reference
    timezone = models.CharField(
        max_length=50,
        default='UTC',
        verbose_name=_('Timezone'),
        help_text=_('Timezone for this event')
    )
    
    organizer = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        verbose_name=_('Organizer')
    )
    
    class Meta:
        verbose_name = _('Event')
        verbose_name_plural = _('Events')
        ordering = ['start_time']
    
    def __str__(self):
        return self.title
    
    def get_local_start_time(self, user_timezone=None):
        """Get start time in user's timezone."""
        if user_timezone is None:
            user_timezone = self.timezone
        
        if isinstance(user_timezone, str):
            user_timezone = pytz.timezone(user_timezone)
        
        return self.start_time.astimezone(user_timezone)
    
    def get_local_end_time(self, user_timezone=None):
        """Get end time in user's timezone."""
        if user_timezone is None:
            user_timezone = self.timezone
        
        if isinstance(user_timezone, str):
            user_timezone = pytz.timezone(user_timezone)
        
        return self.end_time.astimezone(user_timezone)
    
    def get_duration(self):
        """Get event duration."""
        return self.end_time - self.start_time
    
    def is_happening_now(self):
        """Check if event is currently happening."""
        now = timezone.now()
        return self.start_time <= now <= self.end_time
    
    def is_upcoming(self):
        """Check if event is upcoming."""
        return self.start_time > timezone.now()
    
    def save(self, *args, **kwargs):
        """Ensure times are stored in UTC."""
        if self.start_time and self.start_time.tzinfo is None:
            # If no timezone info, assume it's in the event's timezone
            event_tz = pytz.timezone(self.timezone)
            self.start_time = event_tz.localize(self.start_time).astimezone(pytz.UTC)
        
        if self.end_time and self.end_time.tzinfo is None:
            event_tz = pytz.timezone(self.timezone)
            self.end_time = event_tz.localize(self.end_time).astimezone(pytz.UTC)
        
        super().save(*args, **kwargs)

class BlogPost(TimestampedModel):
    """Blog post with timezone-aware publishing."""
    title = models.CharField(max_length=200, verbose_name=_('Title'))
    content = models.TextField(verbose_name=_('Content'))
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    
    # Scheduled publishing
    publish_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name=_('Publish at'),
        help_text=_('Schedule when this post should be published')
    )
    
    is_published = models.BooleanField(default=False, verbose_name=_('Published'))
    
    class Meta:
        verbose_name = _('Blog Post')
        verbose_name_plural = _('Blog Posts')
        ordering = ['-created_at']
    
    def is_scheduled(self):
        """Check if post is scheduled for future publishing."""
        if not self.publish_at:
            return False
        return self.publish_at > timezone.now()
    
    def should_be_published(self):
        """Check if scheduled post should now be published."""
        if not self.publish_at or self.is_published:
            return False
        return self.publish_at <= timezone.now()
    
    def get_publish_time_local(self, user_timezone='UTC'):
        """Get publish time in user's timezone."""
        if not self.publish_at:
            return None
        
        if isinstance(user_timezone, str):
            user_timezone = pytz.timezone(user_timezone)
        
        return self.publish_at.astimezone(user_timezone)

Timezone-Aware Views

Views with Timezone Handling

# views.py
from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from django.http import JsonResponse
from django.views.generic import ListView, DetailView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
import pytz
from datetime import datetime, timedelta
from .models import Event, BlogPost

class TimezoneAwareListView(ListView):
    """Base list view with timezone awareness."""
    
    def get_user_timezone(self):
        """Get current user's timezone."""
        if self.request.user.is_authenticated:
            try:
                return self.request.user.userprofile.get_timezone()
            except:
                pass
        return pytz.UTC
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['user_timezone'] = self.get_user_timezone()
        context['current_time'] = timezone.now()
        return context

class EventListView(TimezoneAwareListView):
    """List events with timezone-aware filtering."""
    model = Event
    template_name = 'events/event_list.html'
    context_object_name = 'events'
    paginate_by = 20
    
    def get_queryset(self):
        """Filter events based on timezone and date range."""
        queryset = Event.objects.all()
        
        # Filter by date range if provided
        start_date = self.request.GET.get('start_date')
        end_date = self.request.GET.get('end_date')
        
        if start_date:
            try:
                start_dt = datetime.strptime(start_date, '%Y-%m-%d')
                user_tz = self.get_user_timezone()
                start_dt = user_tz.localize(start_dt)
                queryset = queryset.filter(start_time__gte=start_dt)
            except ValueError:
                pass
        
        if end_date:
            try:
                end_dt = datetime.strptime(end_date, '%Y-%m-%d')
                user_tz = self.get_user_timezone()
                end_dt = user_tz.localize(end_dt).replace(hour=23, minute=59, second=59)
                queryset = queryset.filter(end_time__lte=end_dt)
            except ValueError:
                pass
        
        return queryset.order_by('start_time')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        
        # Add timezone-aware date ranges
        user_tz = self.get_user_timezone()
        now = timezone.now().astimezone(user_tz)
        
        context.update({
            'today': now.date(),
            'tomorrow': (now + timedelta(days=1)).date(),
            'this_week_start': (now - timedelta(days=now.weekday())).date(),
            'this_week_end': (now + timedelta(days=6-now.weekday())).date(),
            'next_week_start': (now + timedelta(days=7-now.weekday())).date(),
            'next_week_end': (now + timedelta(days=13-now.weekday())).date(),
        })
        
        return context

@method_decorator(login_required, name='dispatch')
class EventDetailView(DetailView):
    """Event detail view with timezone conversion."""
    model = Event
    template_name = 'events/event_detail.html'
    context_object_name = 'event'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        event = self.object
        
        # Get user's timezone
        try:
            user_tz = self.request.user.userprofile.get_timezone()
        except:
            user_tz = pytz.UTC
        
        # Convert event times to user's timezone
        context.update({
            'local_start_time': event.get_local_start_time(user_tz),
            'local_end_time': event.get_local_end_time(user_tz),
            'user_timezone': user_tz,
            'event_timezone': pytz.timezone(event.timezone),
            'duration': event.get_duration(),
            'is_happening_now': event.is_happening_now(),
            'is_upcoming': event.is_upcoming(),
        })
        
        return context

def timezone_api_view(request):
    """API endpoint for timezone operations."""
    if request.method == 'POST':
        # Set user's timezone preference
        timezone_name = request.POST.get('timezone')
        
        if timezone_name:
            try:
                # Validate timezone
                pytz.timezone(timezone_name)
                
                # Save to session
                request.session['timezone'] = timezone_name
                
                # Save to user profile if authenticated
                if request.user.is_authenticated:
                    try:
                        profile = request.user.userprofile
                        profile.timezone = timezone_name
                        profile.save()
                    except:
                        pass
                
                return JsonResponse({
                    'success': True,
                    'timezone': timezone_name,
                    'message': 'Timezone updated successfully'
                })
            except pytz.exceptions.UnknownTimeZoneError:
                return JsonResponse({
                    'success': False,
                    'error': 'Invalid timezone'
                })
    
    elif request.method == 'GET':
        # Get current timezone info
        current_tz = timezone.get_current_timezone()
        now = timezone.now()
        
        return JsonResponse({
            'current_timezone': str(current_tz),
            'current_time_utc': now.isoformat(),
            'current_time_local': now.astimezone(current_tz).isoformat(),
            'available_timezones': [tz[0] for tz in settings.TIMEZONE_CHOICES],
        })
    
    return JsonResponse({'error': 'Method not allowed'}, status=405)

def world_clock_view(request):
    """Display world clock with multiple timezones."""
    world_timezones = [
        ('UTC', 'UTC'),
        ('US/Eastern', 'New York'),
        ('US/Pacific', 'Los Angeles'),
        ('Europe/London', 'London'),
        ('Europe/Paris', 'Paris'),
        ('Asia/Tokyo', 'Tokyo'),
        ('Asia/Shanghai', 'Shanghai'),
        ('Australia/Sydney', 'Sydney'),
    ]
    
    current_time = timezone.now()
    world_times = []
    
    for tz_name, display_name in world_timezones:
        tz = pytz.timezone(tz_name)
        local_time = current_time.astimezone(tz)
        
        world_times.append({
            'timezone': tz_name,
            'display_name': display_name,
            'time': local_time,
            'formatted_time': local_time.strftime('%H:%M'),
            'formatted_date': local_time.strftime('%Y-%m-%d'),
            'is_dst': local_time.dst() != timedelta(0),
        })
    
    return render(request, 'timezone/world_clock.html', {
        'world_times': world_times,
        'current_utc': current_time,
    })

Template Timezone Handling

Timezone-Aware Templates

<!-- templates/events/event_list.html -->
{% load i18n tz %}

<div class="events-container">
    <header class="events-header">
        <h1>{% trans "Events" %}</h1>
        <div class="timezone-info">
            {% blocktrans with tz=user_timezone %}
                Times shown in {{ tz }}
            {% endblocktrans %}
            <a href="#" id="change-timezone">{% trans "Change timezone" %}</a>
        </div>
    </header>
    
    <div class="date-filters">
        <a href="?start_date={{ today }}&end_date={{ today }}">
            {% trans "Today" %}
        </a>
        <a href="?start_date={{ tomorrow }}&end_date={{ tomorrow }}">
            {% trans "Tomorrow" %}
        </a>
        <a href="?start_date={{ this_week_start }}&end_date={{ this_week_end }}">
            {% trans "This Week" %}
        </a>
        <a href="?start_date={{ next_week_start }}&end_date={{ next_week_end }}">
            {% trans "Next Week" %}
        </a>
    </div>
    
    <div class="events-list">
        {% for event in events %}
            <div class="event-card">
                <h3><a href="{% url 'events:detail' event.pk %}">{{ event.title }}</a></h3>
                
                <div class="event-time">
                    {% timezone user_timezone %}
                        <time datetime="{{ event.start_time|date:'c' }}">
                            {{ event.start_time|date:'F j, Y' }} at {{ event.start_time|time:'H:i' }}
                        </time>
                        {% if event.end_time %}
                            - 
                            <time datetime="{{ event.end_time|date:'c' }}">
                                {% if event.start_time|date:'Y-m-d' == event.end_time|date:'Y-m-d' %}
                                    {{ event.end_time|time:'H:i' }}
                                {% else %}
                                    {{ event.end_time|date:'F j, Y' }} at {{ event.end_time|time:'H:i' }}
                                {% endif %}
                            </time>
                        {% endif %}
                    {% endtimezone %}
                </div>
                
                <div class="event-status">
                    {% if event.is_happening_now %}
                        <span class="status happening">{% trans "Happening now" %}</span>
                    {% elif event.is_upcoming %}
                        <span class="status upcoming">{% trans "Upcoming" %}</span>
                    {% else %}
                        <span class="status past">{% trans "Past" %}</span>
                    {% endif %}
                </div>
                
                {% if event.description %}
                    <p class="event-description">{{ event.description|truncatewords:20 }}</p>
                {% endif %}
            </div>
        {% empty %}
            <p class="no-events">{% trans "No events found." %}</p>
        {% endfor %}
    </div>
    
    <!-- Pagination -->
    {% if is_paginated %}
        <div class="pagination">
            {% if page_obj.has_previous %}
                <a href="?page={{ page_obj.previous_page_number }}">{% trans "Previous" %}</a>
            {% endif %}
            
            <span class="current">
                {% blocktrans with current=page_obj.number total=page_obj.paginator.num_pages %}
                    Page {{ current }} of {{ total }}
                {% endblocktrans %}
            </span>
            
            {% if page_obj.has_next %}
                <a href="?page={{ page_obj.next_page_number }}">{% trans "Next" %}</a>
            {% endif %}
        </div>
    {% endif %}
</div>

World Clock Template

<!-- templates/timezone/world_clock.html -->
{% load i18n tz %}

<div class="world-clock">
    <h1>{% trans "World Clock" %}</h1>
    
    <div class="current-utc">
        <h2>{% trans "Current UTC Time" %}</h2>
        <time datetime="{{ current_utc|date:'c' }}" class="utc-time">
            {{ current_utc|date:'Y-m-d H:i:s' }} UTC
        </time>
    </div>
    
    <div class="timezone-grid">
        {% for time_info in world_times %}
            <div class="timezone-card">
                <h3>{{ time_info.display_name }}</h3>
                <div class="time-display">
                    <time datetime="{{ time_info.time|date:'c' }}" class="local-time">
                        {{ time_info.formatted_time }}
                    </time>
                    <div class="date">{{ time_info.formatted_date }}</div>
                </div>
                
                <div class="timezone-info">
                    <span class="timezone-name">{{ time_info.timezone }}</span>
                    {% if time_info.is_dst %}
                        <span class="dst-indicator">{% trans "DST" %}</span>
                    {% endif %}
                </div>
            </div>
        {% endfor %}
    </div>
</div>

<script>
// Update times every second
function updateTimes() {
    const now = new Date();
    
    document.querySelectorAll('.timezone-card').forEach(card => {
        const timeElement = card.querySelector('.local-time');
        const dateElement = card.querySelector('.date');
        const timezoneName = card.querySelector('.timezone-name').textContent;
        
        // Format time for timezone
        const localTime = new Intl.DateTimeFormat('en-US', {
            timeZone: timezoneName,
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit',
            hour12: false
        }).format(now);
        
        const localDate = new Intl.DateTimeFormat('en-CA', {
            timeZone: timezoneName,
            year: 'numeric',
            month: '2-digit',
            day: '2-digit'
        }).format(now);
        
        timeElement.textContent = localTime;
        dateElement.textContent = localDate;
    });
    
    // Update UTC time
    const utcElement = document.querySelector('.utc-time');
    if (utcElement) {
        utcElement.textContent = now.toISOString().slice(0, 19).replace('T', ' ') + ' UTC';
    }
}

// Update immediately and then every second
updateTimes();
setInterval(updateTimes, 1000);
</script>

JavaScript Timezone Detection

Client-Side Timezone Detection

<!-- templates/base.html -->
<script>
// Detect and set user's timezone
function detectAndSetTimezone() {
    // Get timezone from browser
    const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
    
    if (timezone) {
        // Set timezone cookie
        document.cookie = `timezone=${timezone}; path=/; max-age=31536000`; // 1 year
        
        // Send to server via AJAX
        fetch('/api/timezone/', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
                'X-Timezone': timezone
            },
            body: `timezone=${encodeURIComponent(timezone)}`
        })
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                console.log('Timezone set to:', timezone);
                // Optionally reload page to apply new timezone
                // window.location.reload();
            }
        })
        .catch(error => {
            console.error('Error setting timezone:', error);
        });
    }
}

// Run on page load
document.addEventListener('DOMContentLoaded', detectAndSetTimezone);

// Timezone selector functionality
function initTimezoneSelector() {
    const selector = document.getElementById('timezone-selector');
    if (selector) {
        selector.addEventListener('change', function() {
            const selectedTimezone = this.value;
            
            fetch('/api/timezone/', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                    'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
                },
                body: `timezone=${encodeURIComponent(selectedTimezone)}`
            })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    // Reload page to apply new timezone
                    window.location.reload();
                } else {
                    alert('Error setting timezone: ' + data.error);
                }
            })
            .catch(error => {
                console.error('Error:', error);
                alert('Error setting timezone');
            });
        });
    }
}

document.addEventListener('DOMContentLoaded', initTimezoneSelector);
</script>

Management Commands

Timezone Management Commands

# management/commands/update_scheduled_posts.py
from django.core.management.base import BaseCommand
from django.utils import timezone
from blog.models import BlogPost

class Command(BaseCommand):
    help = 'Publish scheduled blog posts'
    
    def handle(self, *args, **options):
        # Find posts that should be published
        posts_to_publish = BlogPost.objects.filter(
            is_published=False,
            publish_at__lte=timezone.now()
        )
        
        count = 0
        for post in posts_to_publish:
            post.is_published = True
            post.save()
            count += 1
            
            self.stdout.write(
                self.style.SUCCESS(f'Published: {post.title}')
            )
        
        self.stdout.write(
            self.style.SUCCESS(f'Published {count} scheduled posts')
        )

# management/commands/timezone_stats.py
from django.core.management.base import BaseCommand
from django.contrib.auth.models import User
from collections import Counter
import pytz

class Command(BaseCommand):
    help = 'Show timezone usage statistics'
    
    def handle(self, *args, **options):
        # Get timezone distribution
        timezones = []
        for user in User.objects.select_related('userprofile'):
            try:
                timezones.append(user.userprofile.timezone)
            except:
                timezones.append('UTC')  # Default
        
        timezone_counts = Counter(timezones)
        
        self.stdout.write('Timezone Usage Statistics\n' + '=' * 40)
        
        for tz, count in timezone_counts.most_common():
            percentage = (count / len(timezones)) * 100
            self.stdout.write(f'{tz}: {count} users ({percentage:.1f}%)')
        
        self.stdout.write(f'\nTotal users: {len(timezones)}')

Testing Timezone Functionality

Timezone Tests

# tests/test_timezone.py
from django.test import TestCase, override_settings
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
import pytz
from datetime import datetime, timedelta
from events.models import Event

class TimezoneTestCase(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            password='testpass'
        )
        
        # Set user timezone to Eastern Time
        profile = self.user.userprofile
        profile.timezone = 'US/Eastern'
        profile.save()
    
    def test_timezone_activation(self):
        """Test timezone activation in middleware."""
        self.client.login(username='testuser', password='testpass')
        
        response = self.client.get('/')
        
        # Check if Eastern timezone is activated
        current_tz = timezone.get_current_timezone()
        self.assertEqual(str(current_tz), 'US/Eastern')
    
    def test_event_timezone_conversion(self):
        """Test event time conversion to user timezone."""
        # Create event in UTC
        utc_time = timezone.now().replace(hour=15, minute=0, second=0, microsecond=0)
        event = Event.objects.create(
            title='Test Event',
            start_time=utc_time,
            end_time=utc_time + timedelta(hours=2),
            organizer=self.user
        )
        
        # Get event in Eastern time (UTC-5 or UTC-4 depending on DST)
        eastern_tz = pytz.timezone('US/Eastern')
        local_start = event.get_local_start_time(eastern_tz)
        
        # Verify conversion
        self.assertEqual(local_start.tzinfo.zone, 'US/Eastern')
    
    def test_scheduled_post_publishing(self):
        """Test timezone-aware scheduled publishing."""
        from blog.models import BlogPost
        
        # Create scheduled post
        future_time = timezone.now() + timedelta(hours=1)
        post = BlogPost.objects.create(
            title='Scheduled Post',
            content='Test content',
            author=self.user,
            publish_at=future_time,
            is_published=False
        )
        
        # Should not be published yet
        self.assertFalse(post.should_be_published())
        
        # Move time forward
        past_time = timezone.now() - timedelta(hours=1)
        post.publish_at = past_time
        post.save()
        
        # Should now be published
        self.assertTrue(post.should_be_published())
    
    @override_settings(USE_TZ=False)
    def test_timezone_disabled(self):
        """Test behavior when timezone support is disabled."""
        # When USE_TZ=False, Django should work with naive datetimes
        event = Event.objects.create(
            title='Naive Event',
            start_time=datetime.now(),
            end_time=datetime.now() + timedelta(hours=1),
            organizer=self.user
        )
        
        # Times should be naive
        self.assertIsNone(event.start_time.tzinfo)

Proper timezone support is essential for global applications. Store all times in UTC, convert to user timezones for display, and provide intuitive timezone selection interfaces. Django's timezone framework handles the complexity of timezone conversion, daylight saving time transitions, and user preferences while maintaining data integrity and excellent user experience across all time zones.