# -*- coding: utf-8 -*- # Copyright 2026 Nexa Systems Inc. # License OPL-1 (Odoo Proprietary License v1.0) """ Timezone helpers for Fusion Clock. All Odoo datetimes are stored in UTC. These helpers derive "today", date boundaries, and display strings in the **user's local timezone** so that queries, penalties, and UI all reflect the real calendar day. Timezone resolution order: 1. Explicit employee.tz (if an employee record is available) 2. env.user.tz (logged-in portal / backend user) 3. env.company.tz (company-level default) 4. 'UTC' (last resort — should rarely happen) """ import pytz from datetime import datetime, timedelta def _resolve_tz(env, employee=None): """Return a pytz timezone from the best available source.""" tz_name = ( (employee.tz if employee else None) or env.user.tz or env.company.tz or 'UTC' ) try: return pytz.timezone(tz_name) except pytz.UnknownTimeZoneError: return pytz.UTC def get_local_now(env, employee=None): """Return the current datetime in the resolved local timezone (aware).""" tz = _resolve_tz(env, employee) return datetime.now(pytz.UTC).astimezone(tz) def get_local_today(env, employee=None): """Return today's date in the resolved local timezone.""" return get_local_now(env, employee).date() def get_local_day_boundaries(env, date_val, employee=None): """ Return (start_utc, end_utc) as **naive** UTC datetimes representing midnight-to-midnight of *date_val* in the local timezone. Suitable for Odoo domain filters like: ('check_in', '>=', start_utc), ('check_in', '<', end_utc), """ tz = _resolve_tz(env, employee) local_start = tz.localize(datetime.combine(date_val, datetime.min.time())) local_end = tz.localize(datetime.combine(date_val + timedelta(days=1), datetime.min.time())) return ( local_start.astimezone(pytz.UTC).replace(tzinfo=None), local_end.astimezone(pytz.UTC).replace(tzinfo=None), ) def utc_to_local_str(dt_utc, env, employee=None, fmt='%I:%M %p'): """ Convert a naive-UTC datetime to a formatted string in local timezone. Returns '' if dt_utc is falsy. """ if not dt_utc: return '' tz = _resolve_tz(env, employee) aware = pytz.UTC.localize(dt_utc) return aware.astimezone(tz).strftime(fmt)