Merge pull request #28093 from gavindsouza/perf-datetime-utils
refactor: Replace pytz to std lib zoneinfo & datetime
This commit is contained in:
commit
14510ea96f
13 changed files with 49 additions and 52 deletions
|
|
@ -4,7 +4,6 @@
|
|||
import datetime
|
||||
from contextlib import suppress
|
||||
|
||||
import pytz
|
||||
from rq import Worker
|
||||
|
||||
import frappe
|
||||
|
|
@ -104,6 +103,7 @@ def serialize_worker(worker: Worker) -> frappe._dict:
|
|||
def compute_utilization(worker: Worker) -> float:
|
||||
with suppress(Exception):
|
||||
total_time = (
|
||||
datetime.datetime.now(pytz.UTC) - worker.birth_date.replace(tzinfo=pytz.UTC)
|
||||
datetime.datetime.now(datetime.timezone.utc)
|
||||
- worker.birth_date.replace(tzinfo=datetime.timezone.utc)
|
||||
).total_seconds()
|
||||
return worker.total_working_time / total_time * 100
|
||||
|
|
|
|||
|
|
@ -808,9 +808,9 @@ class User(Document):
|
|||
|
||||
@frappe.whitelist()
|
||||
def get_timezones():
|
||||
import pytz
|
||||
import zoneinfo
|
||||
|
||||
return {"timezones": pytz.all_timezones}
|
||||
return {"timezones": zoneinfo.available_timezones()}
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
|
|
|||
|
|
@ -814,15 +814,19 @@ def get_tests_CompatFrappeTestCase():
|
|||
|
||||
@contextmanager
|
||||
def freeze_time(self, time_to_freeze, is_utc=False, *args, **kwargs):
|
||||
import pytz
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from freezegun import freeze_time
|
||||
|
||||
from frappe.utils.data import convert_utc_to_timezone, get_datetime, get_system_timezone
|
||||
|
||||
if not is_utc:
|
||||
# Freeze time expects UTC or tzaware objects. We have neither, so convert to UTC.
|
||||
timezone = pytz.timezone(get_system_timezone())
|
||||
time_to_freeze = timezone.localize(get_datetime(time_to_freeze)).astimezone(pytz.utc)
|
||||
time_to_freeze = (
|
||||
get_datetime(time_to_freeze)
|
||||
.replace(tzinfo=ZoneInfo(get_system_timezone()))
|
||||
.astimezone(ZoneInfo("UTC"))
|
||||
)
|
||||
|
||||
with freeze_time(time_to_freeze, *args, **kwargs):
|
||||
yield
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
from datetime import datetime
|
||||
from typing import Any
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import pytz
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
|
@ -122,12 +121,11 @@ class FrappeMail:
|
|||
|
||||
def add_or_update_tzinfo(date_time: datetime | str, timezone: str | None = None) -> str:
|
||||
"""Adds or updates timezone to the datetime."""
|
||||
|
||||
date_time = get_datetime(date_time)
|
||||
target_tz = pytz.timezone(timezone or get_system_timezone())
|
||||
target_tz = ZoneInfo(timezone or get_system_timezone())
|
||||
|
||||
if date_time.tzinfo is None:
|
||||
date_time = target_tz.localize(date_time)
|
||||
date_time = date_time.replace(tzinfo=target_tz)
|
||||
else:
|
||||
date_time = date_time.astimezone(target_tz)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@
|
|||
# License: MIT. See LICENSE
|
||||
|
||||
import datetime
|
||||
|
||||
import pytz
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cint, cstr, get_system_timezone
|
||||
from frappe.utils import cint, cstr, get_datetime, get_system_timezone
|
||||
|
||||
|
||||
class TokenCache(Document):
|
||||
|
|
@ -73,11 +72,10 @@ class TokenCache(Document):
|
|||
return self
|
||||
|
||||
def get_expires_in(self):
|
||||
system_timezone = pytz.timezone(get_system_timezone())
|
||||
modified = frappe.utils.get_datetime(self.modified)
|
||||
modified = system_timezone.localize(modified)
|
||||
expiry_utc = modified.astimezone(pytz.utc) + datetime.timedelta(seconds=self.expires_in)
|
||||
now_utc = datetime.datetime.now(pytz.utc)
|
||||
system_timezone = ZoneInfo(get_system_timezone())
|
||||
modified: datetime.datetime = get_datetime(self.modified).replace(tzinfo=system_timezone)
|
||||
expiry_utc = modified.astimezone(datetime.timezone.utc) + datetime.timedelta(seconds=self.expires_in)
|
||||
now_utc = datetime.datetime.now(datetime.timezone.utc)
|
||||
return cint((expiry_utc - now_utc).total_seconds())
|
||||
|
||||
def is_expired(self):
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import os
|
|||
import traceback
|
||||
import uuid
|
||||
|
||||
import pytz
|
||||
import rq
|
||||
|
||||
import frappe
|
||||
|
|
@ -52,7 +51,7 @@ class Monitor:
|
|||
self.data = frappe._dict(
|
||||
{
|
||||
"site": frappe.local.site,
|
||||
"timestamp": datetime.datetime.now(pytz.UTC),
|
||||
"timestamp": datetime.datetime.now(datetime.timezone.utc),
|
||||
"transaction_type": transaction_type,
|
||||
"uuid": str(uuid.uuid4()),
|
||||
}
|
||||
|
|
@ -85,7 +84,7 @@ class Monitor:
|
|||
|
||||
if job := rq.get_current_job():
|
||||
self.data.uuid = job.id
|
||||
waitdiff = self.data.timestamp - job.enqueued_at.replace(tzinfo=pytz.UTC)
|
||||
waitdiff = self.data.timestamp - job.enqueued_at.replace(tzinfo=datetime.timezone.utc)
|
||||
self.data.job.wait = int(waitdiff.total_seconds() * 1000000)
|
||||
|
||||
def add_custom_data(self, **kwargs):
|
||||
|
|
@ -94,7 +93,7 @@ class Monitor:
|
|||
|
||||
def dump(self, response=None):
|
||||
try:
|
||||
timediff = datetime.datetime.now(pytz.UTC) - self.data.timestamp
|
||||
timediff = datetime.datetime.now(datetime.timezone.utc) - self.data.timestamp
|
||||
# Obtain duration in microseconds
|
||||
self.data.duration = int(timediff.total_seconds() * 1000000)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ from http import cookies
|
|||
from urllib.parse import unquote, urljoin, urlparse
|
||||
|
||||
import jwt
|
||||
import pytz
|
||||
from oauthlib.openid import RequestValidator
|
||||
|
||||
import frappe
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import datetime
|
|||
from collections.abc import Callable
|
||||
from functools import wraps
|
||||
|
||||
import pytz
|
||||
from werkzeug.wrappers import Response
|
||||
|
||||
import frappe
|
||||
|
|
@ -35,7 +34,7 @@ class RateLimiter:
|
|||
self.limit = int(limit * 1000000)
|
||||
self.window = window
|
||||
|
||||
self.start = datetime.datetime.now(pytz.UTC)
|
||||
self.start = datetime.datetime.now(datetime.timezone.utc)
|
||||
timestamp = int(frappe.utils.now_datetime().timestamp())
|
||||
|
||||
self.window_number, self.spent = divmod(timestamp, self.window)
|
||||
|
|
@ -80,7 +79,7 @@ class RateLimiter:
|
|||
def record_request_end(self):
|
||||
if self.end is not None:
|
||||
return
|
||||
self.end = datetime.datetime.now(pytz.UTC)
|
||||
self.end = datetime.datetime.now(datetime.timezone.utc)
|
||||
self.duration = int((self.end - self.start).total_seconds() * 1000000)
|
||||
|
||||
def respond(self):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import logging
|
|||
from collections.abc import Callable
|
||||
from contextlib import contextmanager
|
||||
from functools import wraps
|
||||
from inspect import isfunction, ismethod
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
import frappe
|
||||
|
|
@ -28,15 +27,18 @@ logger = logging.Logger(__file__)
|
|||
@contextmanager
|
||||
def freeze_time(time_to_freeze: Any, is_utc: bool = False, *args: Any, **kwargs: Any) -> None:
|
||||
"""Temporarily: freeze time with freezegun."""
|
||||
import pytz
|
||||
from datetime import UTC
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from freezegun import freeze_time as freezegun_freeze_time
|
||||
|
||||
from frappe.utils.data import get_datetime, get_system_timezone
|
||||
|
||||
if not is_utc:
|
||||
# Freeze time expects UTC or tzaware objects. We have neither, so convert to UTC.
|
||||
timezone = pytz.timezone(get_system_timezone())
|
||||
time_to_freeze = timezone.localize(get_datetime(time_to_freeze)).astimezone(pytz.utc)
|
||||
time_to_freeze = (
|
||||
get_datetime(time_to_freeze).replace(tzinfo=ZoneInfo(get_system_timezone())).astimezone(UTC)
|
||||
)
|
||||
|
||||
with freezegun_freeze_time(time_to_freeze, *args, **kwargs):
|
||||
yield
|
||||
|
|
|
|||
|
|
@ -5,14 +5,13 @@ import io
|
|||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from datetime import date, datetime, time, timedelta, timezone
|
||||
from decimal import ROUND_HALF_UP, Decimal, localcontext
|
||||
from enum import Enum
|
||||
from io import StringIO
|
||||
from mimetypes import guess_type
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytz
|
||||
from hypothesis import given
|
||||
from hypothesis import strategies as st
|
||||
from PIL import Image
|
||||
|
|
@ -736,9 +735,9 @@ class TestResponse(IntegrationTestCase):
|
|||
minute=23,
|
||||
second=23,
|
||||
microsecond=23,
|
||||
tzinfo=pytz.utc,
|
||||
tzinfo=timezone.utc,
|
||||
),
|
||||
time(hour=23, minute=23, second=23, microsecond=23, tzinfo=pytz.utc),
|
||||
time(hour=23, minute=23, second=23, microsecond=23, tzinfo=timezone.utc),
|
||||
timedelta(days=10, hours=12, minutes=120, seconds=10),
|
||||
],
|
||||
"float": [
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ from collections import defaultdict
|
|||
from collections.abc import Callable
|
||||
from functools import wraps
|
||||
|
||||
import pytz
|
||||
|
||||
import frappe
|
||||
|
||||
_SITE_CACHE = defaultdict(lambda: defaultdict(dict))
|
||||
|
|
@ -115,7 +113,9 @@ def site_cache(ttl: int | None = None, maxsize: int | None = None) -> Callable:
|
|||
|
||||
if ttl is not None and not callable(ttl):
|
||||
func.ttl = ttl
|
||||
func.expiration = datetime.datetime.now(pytz.UTC) + datetime.timedelta(seconds=func.ttl)
|
||||
func.expiration = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(
|
||||
seconds=func.ttl
|
||||
)
|
||||
|
||||
if maxsize is not None and not callable(maxsize):
|
||||
func.maxsize = maxsize
|
||||
|
|
@ -125,9 +125,11 @@ def site_cache(ttl: int | None = None, maxsize: int | None = None) -> Callable:
|
|||
if getattr(frappe.local, "initialised", None):
|
||||
func_call_key = json.dumps((args, kwargs))
|
||||
|
||||
if hasattr(func, "ttl") and datetime.datetime.now(pytz.UTC) >= func.expiration:
|
||||
if hasattr(func, "ttl") and datetime.datetime.now(datetime.timezone.utc) >= func.expiration:
|
||||
func.clear_cache()
|
||||
func.expiration = datetime.datetime.now(pytz.UTC) + datetime.timedelta(seconds=func.ttl)
|
||||
func.expiration = datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(
|
||||
seconds=func.ttl
|
||||
)
|
||||
|
||||
if hasattr(func, "maxsize") and len(_SITE_CACHE[func_key][frappe.local.site]) >= func.maxsize:
|
||||
_SITE_CACHE[func_key][frappe.local.site].pop(
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ from code import compile_command
|
|||
from enum import Enum
|
||||
from typing import Any, Literal, Optional, TypeVar
|
||||
from urllib.parse import parse_qsl, quote, urlencode, urljoin, urlparse, urlunparse
|
||||
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
||||
|
||||
import pytz
|
||||
from click import secho
|
||||
from dateutil import parser
|
||||
from dateutil.parser import ParserError
|
||||
|
|
@ -350,8 +350,7 @@ def time_diff_in_hours(string_ed_date: DateTimeLikeObject, string_st_date: DateT
|
|||
|
||||
def now_datetime() -> datetime.datetime:
|
||||
"""Return the current datetime in system timezone."""
|
||||
dt = convert_utc_to_system_timezone(datetime.datetime.now(pytz.UTC))
|
||||
return dt.replace(tzinfo=None)
|
||||
return datetime.datetime.now(ZoneInfo(get_system_timezone())).replace(tzinfo=None)
|
||||
|
||||
|
||||
def get_timestamp(date: Optional["DateTimeLikeObject"] = None) -> float:
|
||||
|
|
@ -372,19 +371,18 @@ def get_system_timezone() -> str:
|
|||
|
||||
|
||||
def convert_utc_to_timezone(utc_timestamp: datetime.datetime, time_zone: str) -> datetime.datetime:
|
||||
from pytz import UnknownTimeZoneError, timezone
|
||||
|
||||
if utc_timestamp.tzinfo is None:
|
||||
utc_timestamp = timezone("UTC").localize(utc_timestamp)
|
||||
utc_timestamp = utc_timestamp.replace(tzinfo=ZoneInfo(time_zone))
|
||||
|
||||
try:
|
||||
return utc_timestamp.astimezone(timezone(time_zone))
|
||||
except UnknownTimeZoneError:
|
||||
return utc_timestamp.astimezone(ZoneInfo(time_zone))
|
||||
except ZoneInfoNotFoundError:
|
||||
return utc_timestamp
|
||||
|
||||
|
||||
def get_datetime_in_timezone(time_zone: str) -> datetime.datetime:
|
||||
"""Return the current datetime in the given timezone (e.g. 'Asia/Kolkata')."""
|
||||
utc_timestamp = datetime.datetime.now(pytz.UTC)
|
||||
utc_timestamp = datetime.datetime.now(datetime.timezone.utc)
|
||||
return convert_utc_to_timezone(utc_timestamp, time_zone)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import random
|
|||
import time
|
||||
from typing import NoReturn
|
||||
|
||||
import pytz
|
||||
import setproctitle
|
||||
from croniter import CroniterBadCronError
|
||||
from filelock import FileLock, Timeout
|
||||
|
|
@ -72,7 +71,7 @@ def sleep_duration(tick):
|
|||
# This makes scheduler aligned with real clock,
|
||||
# so event scheduled at 12:00 happen at 12:00 and not 12:00:35.
|
||||
minutes = tick // 60
|
||||
now = datetime.datetime.now(pytz.UTC)
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
left_minutes = minutes - now.minute % minutes
|
||||
next_execution = now.replace(second=0) + datetime.timedelta(minutes=left_minutes)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue