""" Timezone Location Service - Manages timezone and location consistency. """ import random from typing import Dict, Optional, Tuple, Any class TimezoneLocationService: """Service for managing timezone and location relationships.""" TIMEZONE_MAPPING = { "de": { "timezones": ["Europe/Berlin", "Europe/Munich"], "offset": -60, # UTC+1 "dst_offset": -120 # UTC+2 during DST }, "us": { "timezones": ["America/New_York", "America/Chicago", "America/Los_Angeles", "America/Denver"], "offset": 300, # UTC-5 (New York) "dst_offset": 240 # UTC-4 during DST }, "uk": { "timezones": ["Europe/London"], "offset": 0, # UTC "dst_offset": -60 # UTC+1 during DST }, "jp": { "timezones": ["Asia/Tokyo"], "offset": -540, # UTC+9 "dst_offset": -540 # No DST }, "au": { "timezones": ["Australia/Sydney", "Australia/Melbourne"], "offset": -600, # UTC+10 "dst_offset": -660 # UTC+11 during DST } } CITY_TO_TIMEZONE = { "Berlin": "Europe/Berlin", "Munich": "Europe/Munich", "Frankfurt": "Europe/Berlin", "Hamburg": "Europe/Berlin", "New York": "America/New_York", "Los Angeles": "America/Los_Angeles", "Chicago": "America/Chicago", "London": "Europe/London", "Tokyo": "Asia/Tokyo", "Sydney": "Australia/Sydney" } LANGUAGE_TO_LOCATION = { "de-DE": ["de", "at", "ch"], "en-US": ["us"], "en-GB": ["uk"], "ja-JP": ["jp"], "en-AU": ["au"], "fr-FR": ["fr"], "es-ES": ["es"], "it-IT": ["it"] } def get_timezone_for_location(self, location: Optional[str] = None) -> Tuple[str, int]: """Get timezone and offset for a location.""" if not location: location = random.choice(list(self.TIMEZONE_MAPPING.keys())) location_lower = location.lower() # Check if it's a city for city, tz in self.CITY_TO_TIMEZONE.items(): if city.lower() in location_lower: # Find the offset from the mapping for country, data in self.TIMEZONE_MAPPING.items(): if tz in data["timezones"]: return tz, data["offset"] return tz, 0 # Check if it's a country code if location_lower in self.TIMEZONE_MAPPING: data = self.TIMEZONE_MAPPING[location_lower] timezone = random.choice(data["timezones"]) return timezone, data["offset"] # Default to Berlin return "Europe/Berlin", -60 def get_location_for_language(self, language: str) -> str: """Get a suitable location for a language.""" if language in self.LANGUAGE_TO_LOCATION: locations = self.LANGUAGE_TO_LOCATION[language] return random.choice(locations) # Extract base language base_lang = language.split('-')[0] for lang, locations in self.LANGUAGE_TO_LOCATION.items(): if lang.startswith(base_lang): return random.choice(locations) # Default return "us" def validate_timezone_consistency(self, timezone: str, language: str) -> bool: """Validate if timezone is consistent with language.""" expected_location = self.get_location_for_language(language) # Get timezones for the expected location if expected_location in self.TIMEZONE_MAPPING: expected_timezones = self.TIMEZONE_MAPPING[expected_location]["timezones"] return timezone in expected_timezones # If we can't determine, assume it's valid return True def get_locale_for_timezone(self, timezone: str) -> str: """Get appropriate locale for a timezone.""" tz_to_locale = { "Europe/Berlin": "de-DE", "Europe/Munich": "de-DE", "America/New_York": "en-US", "America/Los_Angeles": "en-US", "America/Chicago": "en-US", "Europe/London": "en-GB", "Asia/Tokyo": "ja-JP", "Australia/Sydney": "en-AU" } return tz_to_locale.get(timezone, "en-US") def calculate_timezone_offset(self, timezone: str, is_dst: bool = False) -> int: """Calculate timezone offset in minutes from UTC.""" # Find the timezone in our mapping for country, data in self.TIMEZONE_MAPPING.items(): if timezone in data["timezones"]: return data["dst_offset"] if is_dst else data["offset"] # Default to UTC return 0 def get_consistent_location_data(self, proxy_location: Optional[str] = None) -> Dict[str, Any]: """Get consistent location data including timezone, locale, and language.""" timezone, offset = self.get_timezone_for_location(proxy_location) locale = self.get_locale_for_timezone(timezone) # Extract language from locale language = locale.split('-')[0] languages = [locale, language] # Add fallback languages if language != "en": languages.extend(["en-US", "en"]) return { "timezone": timezone, "timezone_offset": offset, "locale": locale, "language": language, "languages": languages }