a digital entity named phi that roams bsky
phi.zzstoatzz.io
1"""Tests for the canonical relative_when helper used across system prompt blocks."""
2
3from datetime import UTC, datetime, timedelta
4
5from bot.utils.time import relative_when
6
7
8def _ago(delta: timedelta) -> str:
9 """Build an ISO timestamp N seconds/minutes/etc in the past."""
10 return (datetime.now(UTC) - delta).isoformat()
11
12
13def test_seconds():
14 assert relative_when(_ago(timedelta(seconds=5))) == "5s ago"
15
16
17def test_seconds_at_boundary():
18 # 59s should still be seconds
19 s = relative_when(_ago(timedelta(seconds=59)))
20 assert s.endswith("s ago")
21
22
23def test_minutes():
24 assert relative_when(_ago(timedelta(minutes=15))) == "15m ago"
25
26
27def test_hours_under_10_has_decimal():
28 # 1.5h should show one decimal
29 s = relative_when(_ago(timedelta(hours=1, minutes=30)))
30 assert s.endswith("h ago")
31 assert "." in s
32
33
34def test_hours_over_10_no_decimal():
35 s = relative_when(_ago(timedelta(hours=15)))
36 assert s.endswith("h ago")
37 assert "." not in s
38
39
40def test_days_under_10_has_decimal():
41 s = relative_when(_ago(timedelta(days=2, hours=12)))
42 assert s.endswith("d ago")
43 assert "." in s
44
45
46def test_days_over_10_no_decimal():
47 s = relative_when(_ago(timedelta(days=15)))
48 assert s.endswith("d ago")
49 assert "." not in s
50
51
52def test_months():
53 s = relative_when(_ago(timedelta(days=60)))
54 assert s.endswith("mo ago")
55 assert s.startswith("2")
56
57
58def test_years():
59 s = relative_when(_ago(timedelta(days=400)))
60 assert s.endswith("y ago")
61 assert s.startswith("1")
62
63
64def test_future_returns_empty():
65 future = (datetime.now(UTC) + timedelta(hours=1)).isoformat()
66 assert relative_when(future) == ""
67
68
69def test_invalid_returns_empty():
70 assert relative_when("not a timestamp") == ""
71
72
73def test_empty_returns_empty():
74 assert relative_when("") == ""
75
76
77def test_z_suffix_handled():
78 # "2026-04-19T12:00:00Z" form (Z suffix) should parse
79 z_form = (
80 (datetime.now(UTC) - timedelta(minutes=30)).isoformat().replace("+00:00", "Z")
81 )
82 s = relative_when(z_form)
83 assert s.endswith("m ago")
84
85
86def test_tz_naive_handled_as_utc():
87 # Legacy memory rows used `datetime.now().isoformat()` with no tz info.
88 # Those tz-naive strings must not raise; should be treated as UTC.
89 naive = datetime.now(UTC).replace(tzinfo=None, microsecond=0).isoformat()
90 s = relative_when(naive)
91 # Should parse cleanly; age is "0s ago" or near-zero.
92 assert s.endswith("s ago") or s.endswith("m ago")