summaryrefslogtreecommitdiffstats
path: root/sphinx/util/http_date.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/util/http_date.py')
-rw-r--r--sphinx/util/http_date.py39
1 files changed, 39 insertions, 0 deletions
diff --git a/sphinx/util/http_date.py b/sphinx/util/http_date.py
new file mode 100644
index 0000000..8e245cb
--- /dev/null
+++ b/sphinx/util/http_date.py
@@ -0,0 +1,39 @@
+"""Convert times to and from HTTP-date serialisations.
+
+Reference: https://www.rfc-editor.org/rfc/rfc7231#section-7.1.1.1
+"""
+
+import time
+import warnings
+from email.utils import formatdate, parsedate_tz
+
+from sphinx.deprecation import RemovedInSphinx90Warning
+
+_GMT_OFFSET = float(time.localtime().tm_gmtoff)
+
+
+def epoch_to_rfc1123(epoch: float) -> str:
+ """Return HTTP-date string from epoch offset."""
+ return formatdate(epoch, usegmt=True)
+
+
+def rfc1123_to_epoch(rfc1123: str) -> float:
+ """Return epoch offset from HTTP-date string."""
+ t = parsedate_tz(rfc1123)
+ if t is None:
+ raise ValueError
+ if not rfc1123.endswith(" GMT"):
+ warnings.warn(
+ "HTTP-date string does not meet RFC 7231 requirements "
+ f"(must end with 'GMT'): {rfc1123!r}",
+ RemovedInSphinx90Warning, stacklevel=3,
+ )
+ epoch_secs = time.mktime(time.struct_time(t[:9])) + _GMT_OFFSET
+ if (gmt_offset := t[9]) != 0:
+ warnings.warn(
+ "HTTP-date string does not meet RFC 7231 requirements "
+ f"(must be GMT time): {rfc1123!r}",
+ RemovedInSphinx90Warning, stacklevel=3,
+ )
+ return epoch_secs - (gmt_offset or 0)
+ return epoch_secs