diff --git a/docs/install.rst b/docs/install.rst
index eb618035..fa06068a 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -64,7 +64,7 @@ automatically installed without any action on your part:
* `pygments `_, for syntax highlighting
* `docutils `_, for supporting
reStructuredText as an input format
-* `pytz `_, for timezone definitions
+* `backports.zoneinfo` `_, for timezone definitions
* `blinker `_, an object-to-object and
broadcast signaling system
* `unidecode `_, for ASCII
diff --git a/pelican/contents.py b/pelican/contents.py
index 1740df88..84ee8c3e 100644
--- a/pelican/contents.py
+++ b/pelican/contents.py
@@ -7,7 +7,10 @@ import re
from html import unescape
from urllib.parse import unquote, urljoin, urlparse, urlunparse
-import pytz
+try:
+ import zoneinfo
+except ImportError:
+ from backports import zoneinfo
from pelican.plugins import signals
from pelican.settings import DEFAULT_CONFIG
@@ -122,7 +125,7 @@ class Content:
# manage timezone
default_timezone = settings.get('TIMEZONE', 'UTC')
timezone = getattr(self, 'timezone', default_timezone)
- self.timezone = pytz.timezone(timezone)
+ self.timezone = zoneinfo.ZoneInfo(timezone)
if hasattr(self, 'date'):
self.date = set_date_tzinfo(self.date, timezone)
@@ -525,7 +528,7 @@ class Article(Content):
if self.date.tzinfo is None:
now = datetime.datetime.now()
else:
- now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
+ now = datetime.datetime.utcnow().replace(tzinfo=zoneinfo.ZoneInfo("UTC"))
if self.date > now:
self.status = 'draft'
diff --git a/pelican/tests/test_utils.py b/pelican/tests/test_utils.py
index 710e14ed..3fc06aa0 100644
--- a/pelican/tests/test_utils.py
+++ b/pelican/tests/test_utils.py
@@ -6,7 +6,10 @@ import time
from sys import platform
from tempfile import mkdtemp
-import pytz
+try:
+ import zoneinfo
+except ImportError:
+ from backports import zoneinfo
from pelican import utils
from pelican.generators import TemplatePagesGenerator
@@ -42,21 +45,21 @@ class TestUtils(LoggedTestCase):
year=2012, month=11, day=22, hour=22, minute=11)
date_hour_z = utils.SafeDatetime(
year=2012, month=11, day=22, hour=22, minute=11,
- tzinfo=pytz.timezone('UTC'))
+ tzinfo=zoneinfo.ZoneInfo('UTC'))
date_hour_est = utils.SafeDatetime(
year=2012, month=11, day=22, hour=22, minute=11,
- tzinfo=pytz.timezone('EST'))
+ tzinfo=zoneinfo.ZoneInfo('EST'))
date_hour_sec = utils.SafeDatetime(
year=2012, month=11, day=22, hour=22, minute=11, second=10)
date_hour_sec_z = utils.SafeDatetime(
year=2012, month=11, day=22, hour=22, minute=11, second=10,
- tzinfo=pytz.timezone('UTC'))
+ tzinfo=zoneinfo.ZoneInfo('UTC'))
date_hour_sec_est = utils.SafeDatetime(
year=2012, month=11, day=22, hour=22, minute=11, second=10,
- tzinfo=pytz.timezone('EST'))
+ tzinfo=zoneinfo.ZoneInfo('EST'))
date_hour_sec_frac_z = utils.SafeDatetime(
year=2012, month=11, day=22, hour=22, minute=11, second=10,
- microsecond=123000, tzinfo=pytz.timezone('UTC'))
+ microsecond=123000, tzinfo=zoneinfo.ZoneInfo('UTC'))
dates = {
'2012-11-22': date,
'2012/11/22': date,
@@ -78,13 +81,13 @@ class TestUtils(LoggedTestCase):
iso_8601_date = utils.SafeDatetime(year=1997, month=7, day=16)
iso_8601_date_hour_tz = utils.SafeDatetime(
year=1997, month=7, day=16, hour=19, minute=20,
- tzinfo=pytz.timezone('CET'))
+ tzinfo=zoneinfo.ZoneInfo('CET'))
iso_8601_date_hour_sec_tz = utils.SafeDatetime(
year=1997, month=7, day=16, hour=19, minute=20, second=30,
- tzinfo=pytz.timezone('CET'))
+ tzinfo=zoneinfo.ZoneInfo('CET'))
iso_8601_date_hour_sec_ms_tz = utils.SafeDatetime(
year=1997, month=7, day=16, hour=19, minute=20, second=30,
- microsecond=450000, tzinfo=pytz.timezone('CET'))
+ microsecond=450000, tzinfo=zoneinfo.ZoneInfo('CET'))
iso_8601 = {
'1997-07-16': iso_8601_date,
'1997-07-16T19:20+01:00': iso_8601_date_hour_tz,
diff --git a/pelican/tools/pelican_quickstart.py b/pelican/tools/pelican_quickstart.py
index 2d5629ef..eab1d30f 100755
--- a/pelican/tools/pelican_quickstart.py
+++ b/pelican/tools/pelican_quickstart.py
@@ -4,10 +4,14 @@ import argparse
import locale
import os
from typing import Mapping
+from zoneinfo import available_timezones
from jinja2 import Environment, FileSystemLoader
-import pytz
+try:
+ import zoneinfo
+except ImportError:
+ from backports import zoneinfo
try:
import readline # NOQA
@@ -158,12 +162,13 @@ def ask(question, answer=str, default=None, length=None):
def ask_timezone(question, default, tzurl):
"""Prompt for time zone and validate input"""
- lower_tz = [tz.lower() for tz in pytz.all_timezones]
+ available_timezones = list(zoneinfo.available_timezones())
+ lower_tz = [tz.lower() for tz in available_timezones]
while True:
r = ask(question, str, default)
r = r.strip().replace(' ', '_').lower()
if r in lower_tz:
- r = pytz.all_timezones[lower_tz.index(r)]
+ r = available_timezones[lower_tz.index(r)]
break
else:
print('Please enter a valid time zone:\n'
diff --git a/pelican/utils.py b/pelican/utils.py
index 17667078..0b474f4e 100644
--- a/pelican/utils.py
+++ b/pelican/utils.py
@@ -20,7 +20,10 @@ import dateutil.parser
from markupsafe import Markup
-import pytz
+try:
+ import zoneinfo
+except ImportError:
+ from backports import zoneinfo
logger = logging.getLogger(__name__)
@@ -920,8 +923,8 @@ class FileSystemWatcher:
def set_date_tzinfo(d, tz_name=None):
"""Set the timezone for dates that don't have tzinfo"""
if tz_name and not d.tzinfo:
- tz = pytz.timezone(tz_name)
- d = tz.localize(d)
+ tz = zoneinfo.ZoneInfo(tz_name)
+ d = d.replace(tzinfo=tz)
return SafeDatetime(d.year, d.month, d.day, d.hour, d.minute, d.second,
d.microsecond, d.tzinfo)
return d
diff --git a/pyproject.toml b/pyproject.toml
index 8d7749b0..5ab037ef 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -37,10 +37,10 @@ feedgenerator = ">=1.9"
jinja2 = ">=2.7"
pygments = ">=2.6"
python-dateutil = ">=2.8"
-pytz = ">=2020.1"
rich = ">=10.1"
unidecode = ">=1.1"
markdown = {version = ">=3.1", optional = true}
+"backports.zoneinfo" = "^0.2.1"
[tool.poetry.dev-dependencies]
BeautifulSoup4 = "^4.9"
diff --git a/setup.py b/setup.py
index 3b538992..27414a97 100755
--- a/setup.py
+++ b/setup.py
@@ -5,12 +5,11 @@ from os.path import join, relpath
from setuptools import find_packages, setup
-
version = "4.7.1"
requires = ['feedgenerator >= 1.9', 'jinja2 >= 2.7', 'pygments',
- 'docutils>=0.15', 'pytz >= 0a', 'blinker', 'unidecode',
- 'python-dateutil', 'rich']
+ 'docutils>=0.15', 'backports.zoneinfo;python_version<"3.9"',
+ 'blinker', 'unidecode', 'python-dateutil', 'rich']
entry_points = {
'console_scripts': [