Skip to content

Commit 389b63a

Browse files
committed
Datetime must not be in the future
1 parent 551ac8b commit 389b63a

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

backend/src/models/utils/pre_validator_utils.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from datetime import datetime, timedelta
33
from decimal import Decimal
44
from typing import Union
5+
from datetime import datetime, date
56

67
from .generic_utils import nhs_number_mod11_check, is_valid_simple_snomed
78

@@ -91,12 +92,15 @@ def for_date(field_value: str, field_location: str):
9192
raise TypeError(f"{field_location} must be a string")
9293

9394
try:
94-
datetime.strptime(field_value, "%Y-%m-%d").date()
95+
parsed_date = datetime.strptime(field_value, "%Y-%m-%d").date()
9596
except ValueError as value_error:
9697
raise ValueError(
9798
f'{field_location} must be a valid date string in the format "YYYY-MM-DD"'
9899
) from value_error
99100

101+
# Enforce not-in-the-future rule using central checker
102+
PreValidation.check_if_future_date(parsed_date)
103+
100104
@staticmethod
101105
def for_date_time(field_value: str, field_location: str, strict_timezone: bool = True):
102106
"""
@@ -117,10 +121,12 @@ def for_date_time(field_value: str, field_location: str, strict_timezone: bool =
117121
"- 'YYYY-MM-DDThh:mm:ss%z' — Full date and time with timezone (e.g. +00:00 or +01:00)"
118122
"- 'YYYY-MM-DDThh:mm:ss.f%z' — Full date and time with milliseconds and timezone"
119123
)
120-
121124
if strict_timezone:
122-
error_message += "Only '+00:00' and '+01:00' are accepted as valid timezone offsets.\n"
123-
error_message += f"Note that partial dates are not allowed for {field_location} in this service."
125+
error_message += (
126+
"Only '+00:00' and '+01:00' are accepted as valid timezone offsets.\n"
127+
f"Note that partial dates are not allowed for {field_location} in this service.\n"
128+
"Date must not be in the future."
129+
)
124130

125131
allowed_suffixes = {"+00:00", "+01:00", "+0000", "+0100",}
126132

@@ -135,8 +141,11 @@ def for_date_time(field_value: str, field_location: str, strict_timezone: bool =
135141
fhir_date = datetime.strptime(field_value, fmt)
136142

137143
if strict_timezone and fhir_date.tzinfo is not None:
144+
if PreValidation.check_if_future_date(fhir_date):
145+
raise ValueError(error_message)
138146
if not any(field_value.endswith(suffix) for suffix in allowed_suffixes):
139147
raise ValueError(error_message)
148+
# Enforce not-in-the-future rule using central checker
140149
return fhir_date.isoformat()
141150
except ValueError:
142151
continue
@@ -234,3 +243,15 @@ def for_nhs_number(nhs_number: str, field_location: str):
234243
"""
235244
if not nhs_number_mod11_check(nhs_number):
236245
raise ValueError(f"{field_location} is not a valid NHS number")
246+
247+
@staticmethod
248+
def check_if_future_date(parsed_value: date | datetime):
249+
"""
250+
Ensure a parsed date or datetime object is not in the future.
251+
"""
252+
if isinstance(parsed_value, datetime):
253+
now = datetime.now(parsed_value.tzinfo) if parsed_value.tzinfo else datetime.now()
254+
elif isinstance(parsed_value, date):
255+
now = datetime.now().date()
256+
if parsed_value > now:
257+
return True

backend/tests/utils/pre_validation_test_utils.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,11 @@ def test_date_time_value(
336336
)
337337

338338
if is_occurrence_date_time:
339-
expected_error_message += "Only '+00:00' and '+01:00' are accepted as valid timezone offsets.\n"
340-
expected_error_message += f"Note that partial dates are not allowed for {field_location} in this service."
339+
expected_error_message += (
340+
"Only '+00:00' and '+01:00' are accepted as valid timezone offsets.\n"
341+
f"Note that partial dates are not allowed for {field_location} in this service.\n"
342+
"Date must not be in the future."
343+
)
341344
valid_datetime_formats = ValidValues.for_date_times_strict_timezones
342345
invalid_datetime_formats = InvalidValues.for_date_time_string_formats_for_strict_timezone
343346
else:

0 commit comments

Comments
 (0)