Coverage for nexusLIMS/utils/time.py: 100%
21 statements
« prev ^ index » next coverage.py v7.11.3, created at 2026-03-24 05:23 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2026-03-24 05:23 +0000
1"""Time and date utilities for NexusLIMS."""
3import time
4from datetime import datetime, timedelta
5from typing import Tuple
7import pytz
8import tzlocal
10from nexusLIMS.config import settings
12# Re-export time.sleep for backward compatibility with tests
13sleep = time.sleep
16def get_timespan_overlap(
17 range_1: Tuple[datetime, datetime],
18 range_2: Tuple[datetime, datetime],
19) -> timedelta:
20 """
21 Find the amount of overlap between two time spans.
23 Adapted from https://stackoverflow.com/a/9044111.
25 Parameters
26 ----------
27 range_1
28 Tuple of length 2 of datetime objects: first is the start of the time
29 range and the second is the end of the time range
30 range_2
31 Tuple of length 2 of datetime objects: first is the start of the time
32 range and the second is the end of the time range
34 Returns
35 -------
36 datetime.timedelta
37 The amount of overlap between the time ranges
38 """
39 latest_start = max(range_1[0], range_2[0])
40 earliest_end = min(range_1[1], range_2[1])
41 delta = earliest_end - latest_start
43 return max(timedelta(0), delta)
46def has_delay_passed(date: datetime) -> bool:
47 """
48 Check if the current time is greater than the configured delay.
50 Check if the current time is greater than the configured (or default) record
51 building delay configured in the ``NX_FILE_DELAY_DAYS`` environment variable.
52 If the date given is timezone-aware, the current time in that timezone will be
53 compared.
55 Parameters
56 ----------
57 date
58 The datetime to check; can be either timezone aware or naive
60 Returns
61 -------
62 bool
63 Whether the current time is greater than the given date plus the
64 configurable delay.
65 """
66 # get record builder delay from settings (already validated as float > 0)
67 delay = timedelta(days=settings.NX_FILE_DELAY_DAYS)
69 # Match timezone awareness of input date
70 now = (
71 datetime.now() # noqa: DTZ005
72 if date.tzinfo is None
73 else datetime.now(date.tzinfo)
74 )
76 delta = now - date
78 return delta > delay
81def current_system_tz_name() -> str:
82 """
83 Get the system's timezone name.
85 Returns the IANA timezone database name for the system's current timezone
86 (e.g., 'America/New_York'), never a simple UTC offset.
88 Returns
89 -------
90 str
91 The IANA timezone name (e.g., 'America/New_York', 'Europe/London')
93 Examples
94 --------
95 >>> current_system_tz_name()
96 'America/New_York'
97 """
98 # Get the system's local timezone using tzlocal
99 return tzlocal.get_localzone_name()
102def current_system_tz() -> pytz.tzinfo.DstTzInfo:
103 """
104 Get the system's timezone as a pytz timezone object.
106 Returns the system's current timezone as a pytz timezone object with a
107 named timezone (e.g., 'America/New_York'), never a simple UTC offset.
109 Returns
110 -------
111 pytz.tzinfo.DstTzInfo
112 A pytz timezone object representing the system's timezone
114 Examples
115 --------
116 >>> tz = get_system_tz()
117 >>> tz.zone
118 'America/New_York'
119 """
120 # Return the corresponding pytz timezone object
121 return pytz.timezone(current_system_tz_name())