Skip to content

Conversation

@ttak-apphelix
Copy link
Contributor

@ttak-apphelix ttak-apphelix commented Oct 22, 2025

Description

pytz got deprecated in Django 4.0 && has been completely removed in Django 5.0.
Django 4.2 had provided USE_DEPRECATED_PYTZ flag for pytz support which has now been completely removed in Django 5.0 as well.
Django now uses zoneinfo by default and datetime module use this under the hood now instead of pytz

Difference between datetime.timezone and zoneinfo

datetime.timezone and the zoneinfo package are both related to handling time zones in Python, but they serve slightly different purposes and have different use cases.

datetime.timezone

This is part of the standard library in Python.
It provides a simple way to represent a fixed offset from UTC (Coordinated Universal Time).
It doesn't have information about daylight saving time (DST) or historical changes in time zones.
It's suitable for scenarios where you only need to work with a constant offset, and historical changes in time zones are not important.

zoneinfo

The zoneinfo package is introduced in Python 3.9 as part of PEP 615.
It provides a more comprehensive and accurate way to handle time zones by including historical changes, daylight saving time transitions, and more.
It uses the IANA Time Zone Database, which is regularly updated to reflect changes in time zones around the world.
This package is suitable for applications that require precise handling of time zones, especially when dealing with historical dates.

Original Issue link:
#33980

Related PR:
#37148

Since it involves multiple files changes and as suggested in the PR planning to break that PR into multiple small PR.

Smaller PR link:

@ttak-apphelix ttak-apphelix requested review from a team as code owners October 22, 2025 09:44
@ttak-apphelix ttak-apphelix removed request for a team October 22, 2025 10:14
Copy link
Contributor

Copilot AI left a comment

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 replaces the deprecated pytz library with Python's standard zoneinfo module across the OpenEdx platform codebase. As Django 5.0 has completely removed pytz support, this change migrates all timezone handling to use ZoneInfo("UTC") instead of pytz.UTC or pytz.utc, along with converting timezone list utilities from pytz.common_timezones to zoneinfo.available_timezones().

Key changes:

  • Replaced pytz.UTC and pytz.utc imports with ZoneInfo("UTC") for UTC timezone handling
  • Migrated timezone enumeration from pytz.common_timezones to zoneinfo.available_timezones()
  • Updated time-related factory fixtures and datetime manipulation code
  • Modified timezone utility functions and their associated tests

Reviewed Changes

Copilot reviewed 78 out of 78 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
Multiple test files Updated timezone references in test fixtures and assertions from pytz to zoneinfo
openedx/core/lib/time_zone_utils.py Core timezone utilities migrated from pytz to zoneinfo for display and enumeration
openedx/core/djangoapps/user_api/preferences/api.py Added compatibility layer for country_timezones fallback while migrating to zoneinfo
Multiple views and models Updated UTC datetime generation from pytz.UTC to ZoneInfo("UTC")
Multiple management commands Updated command date parsing and timestamp generation to use zoneinfo

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@ttak-apphelix ttak-apphelix requested a review from robrap October 23, 2025 12:28
Copy link
Contributor

@robrap robrap left a comment

Choose a reason for hiding this comment

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

Thanks @ttak-apphelix.

Here are some high level comments:

  1. Have you read https://docs.djangoproject.com/en/5.2/topics/i18n/timezones/? I don't imagine we'll want to switch to Django's timezone, but you should be aware of the docs and warnings.
  2. I would make a PR that only has direct replacements of [pytz.]UTC => ZoneInfo("UTC"). At a minimum keep this to a separate commit, but a separate PR would make things even simpler. Then, other changes like utc.localize can be discussed with fewer distractions, and it would be easier to see and test these unique cases.
  3. The ! in the title means "backward-incompatible" or "breaking change". Can you explain why this is a breaking change?
  4. I'd use fixup! <COMMIT TITLE> vs fix: <COMMIT TITLE> for commits you plan to squash, and don't intend to leave separate upon merging. That will differentiate from PRs where you intentionally have multiple commits with prefixes that you want to be merged as-is with rebase or merge (vs squash).

@ttak-apphelix
Copy link
Contributor Author

3. The ! in the title means "backward-incompatible" or "breaking change". Can you explain why this is a breaking change?

Thanks @robrap

  1. I did went through the link but not in details. I'll keep a tap on the changes.
  2. Noted. I have updated the PR with only [pytz.]UTC => ZoneInfo("UTC"). Will take the other changes seperatly as suggested.
  3. API response changes: Different number and set of timezones
    Data contract violation: "common" → "all" timezones
    Test breakage: Hard-coded expectations (433 count) fail
    But since PR is been updated with only [pytz.]UTC => ZoneInfo("UTC") changes, i can remove !
  4. Noted

@ttak-apphelix ttak-apphelix changed the title chore!: use zoneinfo instead of pytz chore: use zoneinfo instead of pytz Oct 24, 2025
Copy link
Contributor

@robrap robrap left a comment

Choose a reason for hiding this comment

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

Thanks. Minor comments.

@robrap
Copy link
Contributor

robrap commented Oct 27, 2025

@ttak-apphelix: Could you craft a short commit message, and probably an updated PR description as well, for what we are doing here? This is now not really about the Django changes, but more about moving toward retiring pytz usage, simply because their docs note that the newer way is the recommended way.

@ttak-apphelix
Copy link
Contributor Author

@ttak-apphelix: Could you craft a short commit message, and probably an updated PR description as well, for what we are doing here? This is now not really about the Django changes, but more about moving toward retiring pytz usage, simply because their docs note that the newer way is the recommended way.

@robrap Below are the requested details. Let me know if this is fine:

Commit message:
Replace pytz with zoneinfo for UTC handling across codebase

Updated PR description:
This PR migrates all UTC timezone handling from pytz to Python’s standard library zoneinfo. The pytz library is now deprecated, and its documentation recommends using zoneinfo for all new code. This update modernizes our codebase, removes legacy pytz usage, and ensures compatibility with current best practices for timezone management in Python 3.9+. No functional changes to timezone logic—just a direct replacement for UTC handling.

@robrap
Copy link
Contributor

robrap commented Oct 27, 2025

Thanks @ttak-apphelix. Looks pretty good. I've looked at the issue again: #33980.

Some thoughts and questions:

  • [inform] When I squash, I'll probably update the commit message to include the longer description as well. I'd also link to the github issue. I know there is some redundancy, but when people review commits it can be helpful to have more context without having to go to the PR. This is especially important for community PRs, but can be helpful even for 2U commits.
  • [inform] I added a section to the end of the issue description describing the post-Django 5.2 effort to continue the pytz deprecation.
  • [question] The original issue mentioned moving to something like zoneinfo.UTC. Does that exist, and would it be cleaner to use in this PR before landing this?

@ttak-apphelix
Copy link
Contributor Author

Thanks @ttak-apphelix. Looks pretty good. I've looked at the issue again: #33980.

Some thoughts and questions:

  • [inform] When I squash, I'll probably update the commit message to include the longer description as well. I'd also link to the github issue. I know there is some redundancy, but when people review commits it can be helpful to have more context without having to go to the PR. This is especially important for community PRs, but can be helpful even for 2U commits.
  • [inform] I added a section to the end of the issue description describing the post-Django 5.2 effort to continue the pytz deprecation.
  • [question] The original issue mentioned moving to something like zoneinfo.UTC. Does that exist, and would it be cleaner to use in this PR before landing this?

@robrap No, zoneinfo.UTC does not exist in the standard library. Right way to use is ZoneInfo("UTC")

@robrap robrap merged commit 18d5abb into openedx:master Oct 28, 2025
49 checks passed
@robrap
Copy link
Contributor

robrap commented Oct 28, 2025

@ttak-apphelix: You can see my final commit message here: 18d5abb. In the title I called it "Part 1", because my understanding is that the replacement was not yet done across the whole codebase, but we are doing this in chunks.

haftamuk pushed a commit to haftamuk/edx-platform that referenced this pull request Nov 3, 2025
…37523)

First PR to replace pytz with zoneinfo for UTC handling across codebase.

This PR migrates all UTC timezone handling from pytz to Python’s standard
library zoneinfo. The pytz library is now deprecated, and its documentation
recommends using zoneinfo for all new code. This update modernizes our
codebase, removes legacy pytz usage, and ensures compatibility with
current best practices for timezone management in Python 3.9+. No functional
changes to timezone logic - just a direct replacement for UTC handling.

openedx#33980
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.

4 participants