41 lines
1.6 KiB
Python
41 lines
1.6 KiB
Python
from datetime import datetime
|
|
from typing import Callable, cast
|
|
|
|
from ...core.common import tzdatetime, Literal
|
|
|
|
|
|
'''
|
|
Depending on the specific data provider and your level of paranoia you might expect different behaviour.. E.g.:
|
|
- if your objects already have tz info, you might not need to call localize() at all
|
|
- it's safer when either all of your objects are tz aware or all are tz unware, not a mixture
|
|
- you might trust your original timezone, or it might just be UTC, and you want to use something more reasonable
|
|
'''
|
|
Policy = Literal[
|
|
'keep' , # if datetime is tz aware, just preserve it
|
|
'convert', # if datetime is tz aware, convert to provider's tz
|
|
'throw' , # if datetime is tz aware, throw exception
|
|
# todo 'warn'? not sure if very useful
|
|
]
|
|
|
|
def default_policy() -> Policy:
|
|
try:
|
|
from my.config import time as user_config
|
|
return cast(Policy, user_config.tz.policy)
|
|
except Exception as e:
|
|
# todo meh.. need to think how to do this more carefully
|
|
# rationale: do not mess with user's data until they want
|
|
return 'keep'
|
|
|
|
|
|
def localize_with_policy(lfun: Callable[[datetime], tzdatetime], dt: datetime, policy: Policy=default_policy()) -> tzdatetime:
|
|
tz = dt.tzinfo
|
|
if tz is None:
|
|
return lfun(dt)
|
|
|
|
if policy == 'keep':
|
|
return dt
|
|
elif policy == 'convert':
|
|
ldt = lfun(dt.replace(tzinfo=None))
|
|
return dt.astimezone(ldt.tzinfo)
|
|
else: # policy == 'error':
|
|
raise RuntimeError(f"{dt} already has timezone information (use 'policy' argument to adjust this behaviour)")
|