mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-02-14 08:51:35 -05:00
fixes
This commit is contained in:
@@ -452,11 +452,11 @@ function localizeTimestamp(input) {
|
||||
// - Has GMT±offset: "Wed Feb 11 2026 12:34:12 GMT+1100 (...)"
|
||||
// - Has offset at end: "2026-02-11 11:37:02+11:00"
|
||||
// - Has timezone name in parentheses: "(Australian Eastern Daylight Time)"
|
||||
const hasOffset = /Z$/i.test(str.trim()) ||
|
||||
const hasOffset = /Z$/i.test(str.trim()) ||
|
||||
/GMT[+-]\d{2,4}/.test(str) ||
|
||||
/[+-]\d{2}:?\d{2}$/.test(str.trim()) ||
|
||||
/\([^)]+\)$/.test(str.trim());
|
||||
|
||||
|
||||
// ⚠️ CRITICAL: All DB timestamps are stored in UTC without timezone markers.
|
||||
// If no offset is present, we must explicitly mark it as UTC by appending 'Z'
|
||||
// so JavaScript doesn't interpret it as local browser time.
|
||||
@@ -464,9 +464,9 @@ function localizeTimestamp(input) {
|
||||
if (!hasOffset) {
|
||||
// Ensure proper ISO format before appending Z
|
||||
// Replace space with 'T' if needed: "2026-02-11 11:37:02" → "2026-02-11T11:37:02Z"
|
||||
isoStr = isoStr.replace(' ', 'T') + 'Z';
|
||||
isoStr = isoStr.trim().replace(/^(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})$/, '$1T$2') + 'Z';
|
||||
}
|
||||
|
||||
|
||||
const date = new Date(isoStr);
|
||||
if (!isFinite(date)) {
|
||||
console.error(`ERROR: Couldn't parse date: '${str}' with TIMEZONE ${tz}`);
|
||||
|
||||
@@ -93,7 +93,7 @@ class EventInstance:
|
||||
eve_EventType, eve_AdditionalInfo,
|
||||
eve_PendingAlertEmail, eve_PairEventRowid
|
||||
) VALUES (?,?,?,?,?,?,?)
|
||||
""", (mac, ip, timeNowUTC(as_string=False), eventType, info,
|
||||
""", (mac, ip, timeNowUTC(), eventType, info,
|
||||
1 if pendingAlert else 0, pairRow))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@@ -27,18 +27,18 @@ DATETIME_REGEX = re.compile(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$')
|
||||
def timeNowUTC(as_string=True):
|
||||
"""
|
||||
Return the current time in UTC.
|
||||
|
||||
|
||||
This is the ONLY function that calls datetime.datetime.now() in the entire codebase.
|
||||
All timestamps stored in the database MUST use UTC format.
|
||||
|
||||
|
||||
Args:
|
||||
as_string (bool): If True, returns formatted string for DB storage.
|
||||
If False, returns datetime object for operations.
|
||||
|
||||
|
||||
Returns:
|
||||
str: UTC timestamp as 'YYYY-MM-DD HH:MM:SS' when as_string=True
|
||||
datetime.datetime: UTC datetime object when as_string=False
|
||||
|
||||
|
||||
Examples:
|
||||
timeNowUTC() → '2025-11-04 07:09:11' (for DB writes)
|
||||
timeNowUTC(as_string=False) → datetime.datetime(2025, 11, 4, 7, 9, 11, tzinfo=UTC)
|
||||
@@ -48,9 +48,12 @@ def timeNowUTC(as_string=True):
|
||||
|
||||
|
||||
def get_timezone_offset():
|
||||
now = timeNowUTC(as_string=False).replace(tzinfo=conf.tz) if conf.tz else timeNowUTC(as_string=False)
|
||||
offset_hours = now.utcoffset().total_seconds() / 3600 if now.utcoffset() else 0
|
||||
offset_formatted = "{:+03d}:{:02d}".format(int(offset_hours), int((offset_hours % 1) * 60))
|
||||
if conf.tz:
|
||||
now = timeNowUTC(as_string=False).astimezone(conf.tz)
|
||||
offset_hours = now.utcoffset().total_seconds() / 3600
|
||||
else:
|
||||
offset_hours = 0
|
||||
offset_formatted = "{:+03d}:{:02d}".format(int(offset_hours), int((offset_hours % 1) * 60))
|
||||
return offset_formatted
|
||||
|
||||
|
||||
@@ -107,7 +110,7 @@ def normalizeTimeStamp(inputTimeStamp):
|
||||
# -------------------------------------------------------------------------------------------
|
||||
def format_date_iso(date_val: str) -> Optional[str]:
|
||||
"""Ensures a date string from DB is returned as a proper ISO string with TZ.
|
||||
|
||||
|
||||
Assumes DB timestamps are stored in UTC and converts them to user's configured timezone.
|
||||
"""
|
||||
if not date_val:
|
||||
@@ -173,7 +176,7 @@ def parse_datetime(dt_str):
|
||||
|
||||
def format_date(date_str: str) -> str:
|
||||
"""Format a date string from DB for display.
|
||||
|
||||
|
||||
Assumes DB timestamps are stored in UTC and converts them to user's configured timezone.
|
||||
"""
|
||||
try:
|
||||
|
||||
@@ -188,7 +188,7 @@ def test_get_sessions_calendar(client, api_token, test_mac):
|
||||
Cleans up test sessions after test.
|
||||
"""
|
||||
# --- Setup: create two sessions for the test MAC ---
|
||||
now = datetime.now()
|
||||
now = timeNowUTC(as_string=False)
|
||||
start1 = (now - timedelta(days=2)).isoformat(timespec="seconds")
|
||||
end1 = (now - timedelta(days=1, hours=20)).isoformat(timespec="seconds")
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ class TestTimeNowUTC:
|
||||
def test_timeNowUTC_datetime_has_UTC_timezone(self):
|
||||
"""Test that datetime object has UTC timezone"""
|
||||
result = timeNowUTC(as_string=False)
|
||||
assert result.tzinfo is datetime.UTC or result.tzinfo is not None
|
||||
assert result.tzinfo is datetime.UTC
|
||||
|
||||
def test_timeNowUTC_datetime_no_microseconds(self):
|
||||
"""Test that datetime object has microseconds set to 0"""
|
||||
@@ -55,7 +55,7 @@ class TestTimeNowUTC:
|
||||
"""Test that string and datetime modes return consistent values"""
|
||||
dt_obj = timeNowUTC(as_string=False)
|
||||
str_result = timeNowUTC(as_string=True)
|
||||
|
||||
|
||||
# Convert datetime to string and compare (within 1 second tolerance)
|
||||
dt_str = dt_obj.strftime(DATETIME_PATTERN)
|
||||
# Parse both to compare timestamps
|
||||
@@ -68,7 +68,7 @@ class TestTimeNowUTC:
|
||||
"""Test that timeNowUTC() returns actual UTC time, not local time"""
|
||||
utc_now = datetime.datetime.now(datetime.UTC).replace(microsecond=0)
|
||||
result = timeNowUTC(as_string=False)
|
||||
|
||||
|
||||
# Should be within 1 second
|
||||
diff = abs((utc_now - result).total_seconds())
|
||||
assert diff <= 1
|
||||
@@ -77,10 +77,10 @@ class TestTimeNowUTC:
|
||||
"""Test that string result matches datetime object conversion"""
|
||||
dt_obj = timeNowUTC(as_string=False)
|
||||
str_result = timeNowUTC(as_string=True)
|
||||
|
||||
|
||||
# Convert datetime to string using same format
|
||||
expected = dt_obj.strftime(DATETIME_PATTERN)
|
||||
|
||||
|
||||
# Should be same or within 1 second
|
||||
t1 = datetime.datetime.strptime(expected, DATETIME_PATTERN)
|
||||
t2 = datetime.datetime.strptime(str_result, DATETIME_PATTERN)
|
||||
@@ -95,12 +95,12 @@ class TestTimeNowUTC:
|
||||
def test_timeNowUTC_multiple_calls_increase(self):
|
||||
"""Test that subsequent calls return increasing timestamps"""
|
||||
import time
|
||||
|
||||
|
||||
t1_str = timeNowUTC()
|
||||
time.sleep(0.1)
|
||||
t2_str = timeNowUTC()
|
||||
|
||||
|
||||
t1 = datetime.datetime.strptime(t1_str, DATETIME_PATTERN)
|
||||
t2 = datetime.datetime.strptime(t2_str, DATETIME_PATTERN)
|
||||
|
||||
|
||||
assert t2 >= t1
|
||||
|
||||
Reference in New Issue
Block a user