160 Zeilen
5.5 KiB
Python
160 Zeilen
5.5 KiB
Python
"""
|
|
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
|
|
} |