Skip to content

fix: replace deprecated datetime.utcnow() with timezone-aware datetime.now(timezone.utc) - #6787

Open
GauravPatil2515 wants to merge 2 commits into
crewAIInc:mainfrom
GauravPatil2515:fix/datetime-utcnow-deprecation
Open

fix: replace deprecated datetime.utcnow() with timezone-aware datetime.now(timezone.utc)#6787
GauravPatil2515 wants to merge 2 commits into
crewAIInc:mainfrom
GauravPatil2515:fix/datetime-utcnow-deprecation

Conversation

@GauravPatil2515

Copy link
Copy Markdown

Summary

Python 3.12+ deprecated datetime.utcnow() in favor of timezone-aware datetime.now(timezone.utc). This PR 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 (placeholder creation, row parsing, touch_records)
  • 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()

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.

…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.
Copilot AI review requested due to automatic review settings August 3, 2026 15:28
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Memory timestamp creation and age calculations now use timezone-aware UTC datetimes. Storage fallbacks, record updates, and scoring fixtures use the same UTC representation.

Changes

Memory timestamp consistency

Layer / File(s) Summary
Timezone-aware timestamp producers
lib/crewai/src/crewai/memory/encoding_flow.py, lib/crewai/src/crewai/memory/storage/lancedb_storage.py, lib/crewai/src/crewai/memory/unified_memory.py
Execution, storage, and memory updates now create timezone-aware UTC timestamps and ISO strings.
Record defaults, age scoring, and validation fixtures
lib/crewai/src/crewai/memory/types.py, lib/crewai/tests/memory/test_unified_memory.py
MemoryRecord defaults use timezone-aware UTC values. Composite scoring normalizes naive timestamps before calculating record age. Scoring fixtures now use aware UTC timestamps.

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: replacing deprecated naive UTC timestamps with timezone-aware UTC timestamps.
Description check ✅ Passed The description directly explains the datetime changes, affected files, backward compatibility, and test results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between c8f441c and e89a4e3.

📒 Files selected for processing (4)
  • lib/crewai/src/crewai/memory/encoding_flow.py
  • lib/crewai/src/crewai/memory/storage/lancedb_storage.py
  • lib/crewai/src/crewai/memory/types.py
  • lib/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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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() with datetime.now(timezone.utc) in timestamp writes/updates across memory flows and storage.
  • Updated MemoryRecord defaults to produce timezone-aware UTC datetimes and adjusted recency scoring to handle naive created_at values.
  • 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.

Comment on lines 167 to 170
"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": "",
Comment on lines 46 to 50
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.
Copilot AI review requested due to automatic review settings August 3, 2026 15:46

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
lib/crewai/tests/memory/test_unified_memory.py (2)

5-5: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert that the default timestamp is UTC-aware.

test_memory_record_defaults() currently checks only isinstance(r.created_at, datetime). A naive default would still pass. Add assertions for a non-None tzinfo and a zero UTC offset.

As per coding guidelines, test the behavior of the new timestamp contract. Based on the PR objective, MemoryRecord.created_at must 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 win

Retain 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 reasons

Also 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

📥 Commits

Reviewing files that changed from the base of the PR and between e89a4e3 and 9f801a4.

📒 Files selected for processing (1)
  • lib/crewai/tests/memory/test_unified_memory.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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(), the created_at/last_accessed entries 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_at to a timezone-aware default means records will now commonly be offset-aware (+00:00). However, existing code compares record.created_at to cutoffs that can be offset-naive (e.g., RecallFlow parses analysis.time_filter via datetime.fromisoformat(...), and time_filter is documented as an ISO date string like 2026-02-01). Comparing aware vs naive datetimes raises TypeError, which can break recall filtering and any older_than logic. 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.",
    )

Comment on lines 265 to 269
def _parse_dt(val: Any) -> datetime:
if val is None:
return datetime.utcnow()
return datetime.now(timezone.utc)
if isinstance(val, datetime):
return val
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants