update
This commit is contained in:
75
fusion_clock/models/tz_utils.py
Normal file
75
fusion_clock/models/tz_utils.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# -*- 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)
|
||||
Reference in New Issue
Block a user