mcmasterathl: I will rebase this when #495 is merged, as I am pretty sure they conflict.
jmvrbanac: @mcmasterathl when you have time, could you rebase your change? Thanks!
mcmasterathl: Yup, was working on that right now actually.
mcmasterathl: @jmvrbanac All set
jmvrbanac: :+1: LGTM
diff --git a/falcon/request.py b/falcon/request.py
index 6acb1e6..116af67 100644
--- a/falcon/request.py
+++ b/falcon/request.py
@@ -617,12 +617,13 @@ class Request(object):
 
         try:
             http_date = self.get_header(header, required=required)
-            return util.http_date_to_dt(http_date)
+            return util.http_date_to_dt(http_date, obs_date=True)
         except TypeError:
             # When the header does not exist and isn't required
             return None
         except ValueError:
-            msg = ('It must be formatted according to RFC 1123.')
+            msg = ('It must be formatted according to RFC 7231, '
+                   'Section 7.1.1.1')
             raise HTTPInvalidHeader(msg, header)
 
     def get_param(self, name, required=False, store=None, default=None):
diff --git a/falcon/util/misc.py b/falcon/util/misc.py
index ebfefcf..8922e44 100644
--- a/falcon/util/misc.py
+++ b/falcon/util/misc.py
@@ -88,19 +88,41 @@ def dt_to_http(dt):
     return dt.strftime('%a, %d %b %Y %H:%M:%S GMT')
 
 
-def http_date_to_dt(http_date):
+def http_date_to_dt(http_date, obs_date=False):
     """Converts an HTTP date string to a datetime instance.
 
     Args:
         http_date (str): An RFC 1123 date string, e.g.:
             "Tue, 15 Nov 1994 12:45:26 GMT".
+        obs_date (bool): Support obs-date formats according to RFC 7231, e.g.:
+            "Sunday, 06-Nov-94 08:49:37 GMT"
+            "Sun Nov  6 08:49:37 1994".
 
     Returns:
         datetime: A UTC datetime instance corresponding to the given
             HTTP date.
+
+    Raises:
+        ValueError: http_date doesn't match any of the available time formats
     """
 
-    return strptime(http_date, '%a, %d %b %Y %H:%M:%S %Z')
+    time_formats = ['%a, %d %b %Y %H:%M:%S %Z']
+
+    if obs_date:
+        time_formats.extend([
+            '%A, %d-%b-%y %H:%M:%S %Z',
+            '%a %b %d %H:%M:%S %Y',
+        ])
+
+    # Loop through the formats and return the first that matches
+    for time_format in time_formats:
+        try:
+            return strptime(http_date, time_format)
+        except ValueError:
+            continue
+
+    # Did not match any formats
+    raise ValueError('time data %r does not match known formats' % http_date)
 
 
 def to_query_str(params):

Support obsolete HTTP date formats
In looking at [RFC 7231](http://tools.ietf.org/html/rfc7231#section-7.1.1.1), Falcon date parsing is actually restricted to IMF-fixdate and does not support the other two obsolete formats. Should we support those formats? Doing so may have minor performance implications for little benefit.

Otherwise, we should update the docstrings and such to reference IMF-fixdate instead of HTTP-Date.
diff --git a/tests/test_req_vars.py b/tests/test_req_vars.py
index 56a786d..48dfe06 100644
--- a/tests/test_req_vars.py
+++ b/tests/test_req_vars.py
@@ -527,7 +527,7 @@ class TestReqVars(testing.TestBase):
         headers = {header: 'Thu, 04 Apr 2013'}
         expected_desc = ('The value provided for the {0} '
                          'header is invalid. It must be formatted '
-                         'according to RFC 1123.')
+                         'according to RFC 7231, Section 7.1.1.1')
 
         self._test_error_details(headers, attr,
                                  falcon.HTTPInvalidHeader,
diff --git a/tests/test_utils.py b/tests/test_utils.py
index b5a0d35..29576a8 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -70,6 +70,15 @@ class TestFalconUtils(testtools.TestCase):
             falcon.http_date_to_dt('Thu, 04 Apr 2013 10:28:54 GMT'),
             datetime(2013, 4, 4, 10, 28, 54))
 
+        self.assertEqual(
+            falcon.http_date_to_dt('Sunday, 06-Nov-94 08:49:37 GMT',
+                                   obs_date=True),
+            datetime(1994, 11, 6, 8, 49, 37))
+
+        self.assertEqual(
+            falcon.http_date_to_dt('Sun Nov  6 08:49:37 1994', obs_date=True),
+            datetime(1994, 11, 6, 8, 49, 37))
+
     def test_pack_query_params_none(self):
         self.assertEqual(
             falcon.to_query_str({}),

pip install -e .
parse_log_pytest
requirements.txt
nose coverage ddt pyyaml requests testtools pytest
apt-get update apt-get install -y gcc
3.9
tools/test-requires
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi==2025.1.31
charset-normalizer==3.4.1
coverage==7.8.0
ddt==1.7.2
exceptiongroup==1.2.2
-e git+https://github.com/falconry/falcon.git@92560ebafb8dc20f8aaa6e072536185622c5a88e#egg=falcon
idna==3.10
iniconfig==2.1.0
nose==1.3.7
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
python-mimeparse==2.0.0
PyYAML==6.0.2
requests==2.32.3
six==1.17.0
testtools==2.7.2
tomli==2.2.1
urllib3==2.3.0

name: falcon
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - coverage==7.8.0
      - ddt==1.7.2
      - exceptiongroup==1.2.2
      - idna==3.10
      - iniconfig==2.1.0
      - nose==1.3.7
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - python-mimeparse==2.0.0
      - pyyaml==6.0.2
      - requests==2.32.3
      - six==1.17.0
      - testtools==2.7.2
      - tomli==2.2.1
      - urllib3==2.3.0
prefix: /opt/conda/envs/falcon

tests/test_req_vars.py::TestReqVars::test_date_invalid_1___Date____date__ tests/test_req_vars.py::TestReqVars::test_date_invalid_2___If_Modified_Since____if_modified_since__ tests/test_req_vars.py::TestReqVars::test_date_invalid_3___If_Unmodified_Since____if_unmodified_since__ tests/test_utils.py::TestFalconUtils::test_http_date_to_dt
tests/test_req_vars.py::TestReqVars::test_client_accepts tests/test_utils.py::TestFalconUtils::test_deprecated_decorator
tests/test_req_vars.py::TestReqVars::test_attribute_headers tests/test_req_vars.py::TestReqVars::test_bogus_content_length_nan tests/test_req_vars.py::TestReqVars::test_bogus_content_length_neg tests/test_req_vars.py::TestReqVars::test_client_accepts_bogus tests/test_req_vars.py::TestReqVars::test_client_accepts_props tests/test_req_vars.py::TestReqVars::test_client_prefers tests/test_req_vars.py::TestReqVars::test_content_length tests/test_req_vars.py::TestReqVars::test_content_length_method tests/test_req_vars.py::TestReqVars::test_content_type_method tests/test_req_vars.py::TestReqVars::test_date_1___Date____date__ tests/test_req_vars.py::TestReqVars::test_date_2___If_Modified_since____if_modified_since__ tests/test_req_vars.py::TestReqVars::test_date_3___If_Unmodified_since____if_unmodified_since__ tests/test_req_vars.py::TestReqVars::test_date_missing_1_date tests/test_req_vars.py::TestReqVars::test_date_missing_2_if_modified_since tests/test_req_vars.py::TestReqVars::test_date_missing_3_if_unmodified_since tests/test_req_vars.py::TestReqVars::test_empty tests/test_req_vars.py::TestReqVars::test_empty_path tests/test_req_vars.py::TestReqVars::test_host tests/test_req_vars.py::TestReqVars::test_method tests/test_req_vars.py::TestReqVars::test_missing_attribute_header tests/test_req_vars.py::TestReqVars::test_missing_qs tests/test_req_vars.py::TestReqVars::test_range tests/test_req_vars.py::TestReqVars::test_range_invalid tests/test_req_vars.py::TestReqVars::test_reconstruct_url tests/test_req_vars.py::TestReqVars::test_relative_uri tests/test_req_vars.py::TestReqVars::test_subdomain tests/test_req_vars.py::TestReqVars::test_uri tests/test_req_vars.py::TestReqVars::test_uri_http_1_0 tests/test_req_vars.py::TestReqVars::test_uri_https tests/test_utils.py::TestFalconUtils::test_dt_to_http tests/test_utils.py::TestFalconUtils::test_pack_query_params_none tests/test_utils.py::TestFalconUtils::test_pack_query_params_one tests/test_utils.py::TestFalconUtils::test_pack_query_params_several tests/test_utils.py::TestFalconUtils::test_parse_host tests/test_utils.py::TestFalconUtils::test_parse_query_string tests/test_utils.py::TestFalconUtils::test_prop_uri_decode_models_stdlib_unquote_plus tests/test_utils.py::TestFalconUtils::test_prop_uri_encode_models_stdlib_quote tests/test_utils.py::TestFalconUtils::test_prop_uri_encode_value_models_stdlib_quote_safe_tilde tests/test_utils.py::TestFalconUtils::test_uri_decode tests/test_utils.py::TestFalconUtils::test_uri_encode tests/test_utils.py::TestFalconUtils::test_uri_encode_value tests/test_utils.py::TestFalconTesting::test_decode_empty_result tests/test_utils.py::TestFalconTesting::test_none_header_value_in_create_environ tests/test_utils.py::TestFalconTesting::test_path_escape_chars_in_create_environ
falcon/request.py falcon/util/misc.py
falcon/request.py falcon/util/misc.py