import arrow import calendar from ApiLayers.AllConfigs.main import MainConfig as Config class DateTimeLocal: def __init__(self, timezone: str = None, is_client: bool = True): if timezone and timezone not in Config.SUPPORTED_TIMEZONES: raise ValueError( f"Unsupported timezone: {timezone}. Must be one of {Config.SUPPORTED_TIMEZONES}" ) self.timezone = Config.SYSTEM_TIMEZONE if is_client: self.timezone = (timezone or Config.DEFAULT_TIMEZONE).replace("-", "+") def find_last_day_of_month(self, date_value): today = self.get(date_value).date() _, last_day = calendar.monthrange(today.year, today.month) return self.get(today.year, today.month, last_day, 23, 59, 59).to(self.timezone) def find_first_day_of_month(self, date_value): today = self.get(date_value).date() return self.get(today.year, today.month, 1).to(self.timezone) def get(self, *args): return arrow.get(*args).to(str(self.timezone)) def now(self): return arrow.now().to(str(self.timezone)) def shift(self, date, **kwargs): return self.get(date).shift(**kwargs) def date(self, date): return self.get(date).date() def time(self, date): return self.get(date).time() def string_date(self, date, splitter: str = "-"): return str(self.get(date).date()).replace("-", splitter) def string_time_only(self, date): return self.get(date).format("HH:mm:ss") def string_date_only(self, date): return self.get(date).format("YYYY-MM-DD") def to_timestamp(self, date): """Convert datetime to UTC timestamp""" return self.get(date).timestamp() def from_timestamp(self, timestamp): """Convert timestamp to timezone-aware datetime""" return arrow.get(timestamp).to(str(self.timezone)) def is_timezone_aware(self, date): """Check if a date is timezone-aware""" return self.get(date).tzinfo is not None def standardize_timezone(self, date): """Ensure date is in the correct timezone""" if not self.is_timezone_aware(date): return self.get(date).to(str(self.timezone)) return self.get(date) def get_expiry_time(self, **kwargs): """Get future time for cache expiry Example: get_expiry_time(hours=1, minutes=30) """ return self.now().shift(**kwargs) def is_expired(self, timestamp): """Check if a timestamp is expired""" if not timestamp: return True return self.from_timestamp(timestamp) < self.now() def get_cache_key(self, base_key, *args): """Generate a cache key with timezone info Example: get_cache_key('user_profile', user_id, 'details') """ components = [str(base_key)] components.extend(str(arg) for arg in args) components.append(f"tz_{self.timezone}") return ":".join(components) def format_for_db(self, date): """Format date for database storage""" return self.get(date).format("YYYY-MM-DD HH:mm:ss.SSSZZ") def parse_from_db(self, date_str): """Parse date from database format""" if not date_str: return None return self.get(date_str) def get_day_boundaries(self, date=None): """Get start and end of day in current timezone""" dt = self.get(date) if date else self.now() start = dt.floor("day") end = dt.ceil("day") return start, end def get_month_boundaries(self, date=None): """Get start and end of month in current timezone""" dt = self.get(date) if date else self.now() start = dt.floor("month") end = dt.ceil("month") return start, end client_arrow = DateTimeLocal(is_client=True) system_arrow = DateTimeLocal(is_client=False)