Reject trailing text in a datetime field instead of slicing it away
Also published in our primary archive.
Reject trailing text in a datetime field instead of slicing it away
Parse the complete datetime field with datetime.strptime(value, '%Y-%m-%d'); do not slice value[:10] before parsing. With that exact format, '2026-09-08' succeeds and '2026-09-08junk' raises ValueError: unconverted data remains: junk.
The example first exposes the failure. sliced_parse() passes only the first ten characters to strptime, so both the clean input and the suffixed input become the same parsed date. That code has discarded the evidence that the second field violated the format contract. It is only appropriate if an earlier, explicit stage has separated an approved date field from other structured content.
complete_parse() instead gives strptime() the original value. The clean field is converted to an ISO date for deterministic output. For the invalid field, the code catches ValueError at the reporting boundary and prints the exception type and message. The assertion checks that the reported error contains unconverted data remains, which is the meaningful contract here; the exact prose of an exception should not be used as a machine-readable error code.
datetime.strptime() has long been part of Python’s standard library and this example uses only the portable numeric directives %Y, %m, and %d; it works on supported Python 3 versions. It validates this date-only format, not time zones, whitespace normalization, or a broader timestamp syntax. Python datetime.strptime() documentation describes parsing with an explicit format.
AI assistance disclosure: This article was prepared with AI assistance and checked with the synthetic assertions shown below.
from datetime import datetime
FORMAT = "%Y-%m-%d"
clean = "2026-09-08"
suffixed = "2026-09-08junk"
def sliced_parse(value):
return datetime.strptime(value[:10], FORMAT).date()
def complete_parse(value):
return datetime.strptime(value, FORMAT).date()
assert sliced_parse(clean) == sliced_parse(suffixed)
assert complete_parse(clean).isoformat() == "2026-09-08"
try:
complete_parse(suffixed)
except ValueError as error:
error_report = f"{type(error).__name__}: {error}"
else:
raise AssertionError("the suffixed field must be rejected")
assert "unconverted data remains" in error_report
print(f"slicing accepts clean: {sliced_parse(clean).isoformat()}")
print(f"slicing accepts suffixed: {sliced_parse(suffixed).isoformat()}")
print(f"complete clean: {complete_parse(clean).isoformat()}")
print(f"complete suffixed: {error_report}")
slicing accepts clean: 2026-09-08
slicing accepts suffixed: 2026-09-08
complete clean: 2026-09-08
complete suffixed: ValueError: unconverted data remains: junk