From c52e44f90c18f2f325f106f8d0486f380d29d777 Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Tue, 4 Nov 2025 08:10:50 +1100 Subject: [PATCH] BE/PLG: TZ timestamp work #1251 Signed-off-by: jokob-sk --- server/api_server/device_endpoint.py | 4 ++- server/helper.py | 11 ++++++-- server/scan/device_handling.py | 38 ++++++++++++++++++---------- test/test_dbquery_endpoints.py | 5 +++- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/server/api_server/device_endpoint.py b/server/api_server/device_endpoint.py index 3e66a560..7a331c5d 100755 --- a/server/api_server/device_endpoint.py +++ b/server/api_server/device_endpoint.py @@ -27,10 +27,12 @@ def get_device_data(mac): # Open temporary connection for this request conn = get_temp_db_connection() cur = conn.cursor() + + now = timeNowTZ().astimezone().isoformat() # Special case for new device if mac.lower() == "new": - now = timeNowTZ().astimezone().isoformat() + device_data = { "devMac": "", "devName": "", diff --git a/server/helper.py b/server/helper.py index 1212265e..f7787af1 100755 --- a/server/helper.py +++ b/server/helper.py @@ -99,8 +99,15 @@ def parse_datetime(dt_str): return None def format_date(date_str: str) -> str: - dt = parse_datetime(date_str) - return dt.strftime('%Y-%m-%d %H:%M') if dt else "invalid" + try: + dt = parse_datetime(date_str) + if dt.tzinfo is None: + # Set timezone if missing — change to timezone.utc if you prefer UTC + now = datetime.datetime.now(conf.tz) + dt = dt.replace(tzinfo=now.astimezone().tzinfo) + return dt.astimezone().isoformat() + except Exception: + return "invalid" def format_date_diff(date1, date2): """ diff --git a/server/scan/device_handling.py b/server/scan/device_handling.py index 57dcc923..08686885 100755 --- a/server/scan/device_handling.py +++ b/server/scan/device_handling.py @@ -532,21 +532,33 @@ def update_devices_names(pm): # Retrieve last time name resolution was checked last_checked = pm.name_plugins_checked - # Collect valid state update timestamps for name-related plugins - state_times = [] + # Collect and normalize valid state update timestamps for name-related plugins + state_times = [] + latest_state = None + for p in name_plugins: state_updated = pm.plugin_states.get(p, {}).get("stateUpdated") - if state_updated: # skip empty or None - state_times.append(state_updated) + if not state_updated: + continue + + # Normalize and validate timestamp + if isinstance(state_updated, datetime.datetime): + state_times.append(state_updated) + elif isinstance(state_updated, str): + try: + state_times.append(parser.parse(state_updated)) + except Exception as e: + mylog('none', f'[Update Device Name] Failed to parse timestamp for {p}: {state_updated!r} ({e})') + else: + mylog('none', f'[Update Device Name] Unexpected timestamp type for {p}: {type(state_updated)}') + # Determine the latest valid timestamp safely + try: + if state_times: + latest_state = max(state_times) + except Exception as e: + mylog('none', f'[Update Device Name] Failed to determine latest timestamp, using fallback ({e})') + latest_state = state_times[-1] if state_times else None - # Determine the latest valid stateUpdated timestamp - latest_state_str = max(state_times, default=None) - if isinstance(latest_state_str, datetime.datetime): - latest_state = latest_state_str - elif latest_state_str: - latest_state = parser.parse(latest_state_str) - else: - latest_state = None # Skip if no plugin state changed since last check if last_checked and latest_state and latest_state <= last_checked: @@ -650,7 +662,7 @@ def update_devices_names(pm): # --- Step 3: Log last checked time --- # After resolving names, update last checked - pm.name_plugins_checked = timeNowTZ() + pm.name_plugins_checked = timeNowTZ().astimezone().isoformat() #------------------------------------------------------------------------------- # Updates devPresentLastScan for parent devices based on the presence of their NICs diff --git a/test/test_dbquery_endpoints.py b/test/test_dbquery_endpoints.py index 981ab2f9..ff4347ed 100755 --- a/test/test_dbquery_endpoints.py +++ b/test/test_dbquery_endpoints.py @@ -40,9 +40,12 @@ def b64(sql: str) -> str: # Device lifecycle via dbquery endpoints # ----------------------------- def test_dbquery_create_device(client, api_token, test_mac): + + now = timeNowTZ().astimezone().isoformat() + sql = f""" INSERT INTO Devices (devMac, devName, devVendor, devOwner, devFirstConnection, devLastConnection, devLastIP) - VALUES ('{test_mac}', 'UnitTestDevice', 'TestVendor', 'UnitTest', '{timeNowTZ()}', '{timeNowTZ()}', '192.168.100.22' ) + VALUES ('{test_mac}', 'UnitTestDevice', 'TestVendor', 'UnitTest', '{now}', '{now}', '192.168.100.22' ) """ resp = client.post("/dbquery/write", json={"rawSql": b64(sql)}, headers=auth_headers(api_token)) print(resp.json)