76 lines
2.4 KiB
Python
76 lines
2.4 KiB
Python
# -*- 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)
|