fix: replace deprecated datetime.utcnow() with timezone-aware datetime.now(timezone.utc) - #6787
Conversation
…e.now(timezone.utc) Python 3.12+ deprecated datetime.utcnow() in favor of timezone-aware datetime.now(timezone.utc). This change updates all occurrences in the memory module to use the new recommended approach. Changes: - encoding_flow.py: Use datetime.now(timezone.utc) for timestamps - lancedb_storage.py: Use datetime.now(timezone.utc) in 4 locations - unified_memory.py: Use datetime.now(timezone.utc) for update timestamps - types.py: Update default_factory lambdas and add _ensure_aware() helper for backward compatibility with naive datetimes in compute_composite_score() This resolves deprecation warnings and ensures consistent timezone-aware datetime handling across the memory system.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughMemory timestamp creation and age calculations now use timezone-aware UTC datetimes. Storage fallbacks, record updates, and scoring fixtures use the same UTC representation. ChangesMemory timestamp consistency
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/crewai/src/crewai/memory/storage/lancedb_storage.py`:
- Line 267: Update _parse_dt() to normalize every parsed timestamp to a
timezone-aware UTC datetime, including legacy naive values, while preserving the
current default for missing timestamps. Ensure both _row_to_record() and
get_scope_info() use this shared parser so list_records() and scope comparisons
never mix naive and aware datetimes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 14a94d7a-3c21-4297-b03d-a9f4def1ebae
📒 Files selected for processing (4)
lib/crewai/src/crewai/memory/encoding_flow.pylib/crewai/src/crewai/memory/storage/lancedb_storage.pylib/crewai/src/crewai/memory/types.pylib/crewai/src/crewai/memory/unified_memory.py
| def _parse_dt(val: Any) -> datetime: | ||
| if val is None: | ||
| return datetime.utcnow() | ||
| return datetime.now(timezone.utc) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Normalize legacy timestamps at the storage boundary.
_parse_dt() returns existing naive values unchanged. New rows use aware values. A table with both formats can raise TypeError: can't compare offset-naive and offset-aware datetimes in list_records() and get_scope_info().
Normalize every parsed timestamp to UTC. Reuse the same parser for both _row_to_record() and get_scope_info().
Suggested normalization
- if isinstance(val, datetime):
- return val
- s = str(val)
- return datetime.fromisoformat(s.replace("Z", "+00:00"))
+ dt = (
+ val
+ if isinstance(val, datetime)
+ else datetime.fromisoformat(str(val).replace("Z", "+00:00"))
+ )
+ if dt.tzinfo is None:
+ return dt.replace(tzinfo=timezone.utc)
+ return dt.astimezone(timezone.utc)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/crewai/src/crewai/memory/storage/lancedb_storage.py` at line 267, Update
_parse_dt() to normalize every parsed timestamp to a timezone-aware UTC
datetime, including legacy naive values, while preserving the current default
for missing timestamps. Ensure both _row_to_record() and get_scope_info() use
this shared parser so list_records() and scope comparisons never mix naive and
aware datetimes.
There was a problem hiding this comment.
Pull request overview
This PR updates the memory subsystem to stop using deprecated datetime.utcnow() and instead generate timezone-aware UTC timestamps via datetime.now(timezone.utc), aiming to be compatible with Python 3.12+ and preserve existing stored timestamps.
Changes:
- Replaced
datetime.utcnow()withdatetime.now(timezone.utc)in timestamp writes/updates across memory flows and storage. - Updated
MemoryRecorddefaults to produce timezone-aware UTC datetimes and adjusted recency scoring to handle naivecreated_atvalues. - Updated LanceDB storage placeholder/record-touch timestamps to emit ISO-8601 strings with UTC offsets.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| lib/crewai/src/crewai/memory/unified_memory.py | Uses timezone-aware UTC “now” when updating record access timestamps. |
| lib/crewai/src/crewai/memory/types.py | Makes created_at / last_accessed default factories timezone-aware and adds a helper for naive datetime compatibility in scoring. |
| lib/crewai/src/crewai/memory/storage/lancedb_storage.py | Emits timezone-aware ISO timestamps for placeholder rows and touch updates; adjusts “None timestamp” parsing default. |
| lib/crewai/src/crewai/memory/encoding_flow.py | Uses timezone-aware UTC “now” for plan execution timestamps. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "importance": 0.5, | ||
| "created_at": datetime.utcnow().isoformat(), | ||
| "last_accessed": datetime.utcnow().isoformat(), | ||
| "created_at": datetime.now(timezone.utc).isoformat(), | ||
| "last_accessed": datetime.now(timezone.utc).isoformat(), | ||
| "source": "", |
| created_at: datetime = Field( | ||
| default_factory=datetime.utcnow, | ||
| default_factory=lambda: datetime.now(timezone.utc), | ||
| description="When the memory was created.", | ||
| ) | ||
| last_accessed: datetime = Field( |
…ry.py Update test file to use timezone-aware datetime.now(timezone.utc) instead of deprecated datetime.utcnow(). This eliminates deprecation warnings during test runs and aligns with the source code fixes.
There was a problem hiding this comment.
🧹 Nitpick comments (2)
lib/crewai/tests/memory/test_unified_memory.py (2)
5-5: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAssert that the default timestamp is UTC-aware.
test_memory_record_defaults()currently checks onlyisinstance(r.created_at, datetime). A naive default would still pass. Add assertions for a non-Nonetzinfoand a zero UTC offset.As per coding guidelines, test the behavior of the new timestamp contract. Based on the PR objective,
MemoryRecord.created_atmust use timezone-aware UTC values.Proposed test assertion
assert isinstance(r.created_at, datetime) + assert r.created_at.tzinfo is not None + assert r.created_at.utcoffset() == timedelta(0)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/crewai/tests/memory/test_unified_memory.py` at line 5, Update test_memory_record_defaults() to verify that MemoryRecord.created_at is timezone-aware UTC: assert tzinfo is not None and utcoffset() equals timedelta(0), while preserving the existing datetime type assertion.Source: Coding guidelines
495-495: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winRetain a regression test for naive timestamps.
These fixtures now cover aware timestamps only. Add a separate scoring test with a naive UTC timestamp to exercise
_ensure_aware()and preserve compatibility with existing records.As per coding guidelines, cover this compatibility behavior with a unit test. Based on the PR objective,
_ensure_aware()must support existing naive datetimes.Proposed compatibility test
+def test_composite_score_accepts_naive_created_at() -> None: + config = MemoryConfig(recency_half_life_days=30) + old_date = ( + datetime.now(timezone.utc) - timedelta(days=60) + ).replace(tzinfo=None) + record = MemoryRecord( + content="legacy", + importance=0.5, + created_at=old_date, + ) + + score, reasons = compute_composite_score(record, 0.8, config) + + assert 0.55 <= score <= 0.60 + assert "recency" not in reasonsAlso applies to: 507-507, 542-542, 564-564, 574-574, 590-592
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lib/crewai/tests/memory/test_unified_memory.py` at line 495, Add a dedicated scoring unit test in the unified memory tests using a naive UTC datetime fixture, ensuring it exercises _ensure_aware() and verifies existing-record compatibility. Keep the current aware-timestamp fixtures unchanged, and cover the same behavior where the affected scoring fixtures are used.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@lib/crewai/tests/memory/test_unified_memory.py`:
- Line 5: Update test_memory_record_defaults() to verify that
MemoryRecord.created_at is timezone-aware UTC: assert tzinfo is not None and
utcoffset() equals timedelta(0), while preserving the existing datetime type
assertion.
- Line 495: Add a dedicated scoring unit test in the unified memory tests using
a naive UTC datetime fixture, ensuring it exercises _ensure_aware() and verifies
existing-record compatibility. Keep the current aware-timestamp fixtures
unchanged, and cover the same behavior where the affected scoring fixtures are
used.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: def9ca5e-ed1b-4534-9ccd-506091ab23d3
📒 Files selected for processing (1)
lib/crewai/tests/memory/test_unified_memory.py
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
lib/crewai/src/crewai/memory/storage/lancedb_storage.py:169
- In
_create_table(), thecreated_at/last_accessedentries are misindented relative to the rest of the placeholder row. This makes the dict hard to read and is likely to fail formatting/lint expectations (e.g., Black/Ruff) for this file.
"created_at": datetime.now(timezone.utc).isoformat(),
"last_accessed": datetime.now(timezone.utc).isoformat(),
lib/crewai/src/crewai/memory/types.py:49
- Switching
MemoryRecord.created_atto a timezone-aware default means records will now commonly be offset-aware (+00:00). However, existing code comparesrecord.created_atto cutoffs that can be offset-naive (e.g.,RecallFlowparsesanalysis.time_filterviadatetime.fromisoformat(...), andtime_filteris documented as an ISO date string like2026-02-01). Comparing aware vs naive datetimes raisesTypeError, which can break recall filtering and anyolder_thanlogic. Consider ensuring all parsed cutoffs are made UTC-aware when naive (or normalize record timestamps consistently) wherever these comparisons occur.
created_at: datetime = Field(
default_factory=lambda: datetime.now(timezone.utc),
description="When the memory was created.",
)
| def _parse_dt(val: Any) -> datetime: | ||
| if val is None: | ||
| return datetime.utcnow() | ||
| return datetime.now(timezone.utc) | ||
| if isinstance(val, datetime): | ||
| return val |
Summary
Python 3.12+ deprecated
datetime.utcnow()in favor of timezone-awaredatetime.now(timezone.utc). This PR updates all occurrences in the memory module to use the new recommended approach.Changes
datetime.now(timezone.utc)for timestampsdatetime.now(timezone.utc)in 4 locations (placeholder creation, row parsing, touch_records)datetime.now(timezone.utc)for update timestampsdefault_factorylambdas and add_ensure_aware()helper for backward compatibility with naive datetimes incompute_composite_score()Testing
All 133 memory-related tests pass (128 memory tests + 5 crew memory integration tests). The changes maintain backward compatibility with existing naive datetime objects stored in the database.
Related
This follows the same pattern as commit 017acc7 which added timezone to event timestamps.