def validate_literal_datetime(value: str) -> datetime:
"""
title: Validate an astx datetime literal.
parameters:
value:
type: str
returns:
type: datetime
"""
stripped = value.strip()
if "T" in stripped:
date_part, time_part = stripped.split("T", 1)
elif " " in stripped:
date_part, time_part = stripped.split(" ", 1)
else:
raise ValueError("invalid datetime format")
if "." in time_part:
raise ValueError("fractional seconds are not supported")
if time_part.endswith("Z") or "+" in time_part or "-" in time_part[2:]:
raise ValueError("timezone offsets are not supported")
try:
year_str, month_str, day_str = date_part.split("-")
year = int(year_str)
month = int(month_str)
day = int(day_str)
except Exception as exc:
raise ValueError("invalid date part") from exc
if not (INT32_MIN <= year <= INT32_MAX):
raise ValueError("year out of 32-bit range")
try:
time_parts = time_part.split(":")
if len(time_parts) not in {
TIME_PARTS_HOUR_MINUTE,
TIME_PARTS_HOUR_MINUTE_SECOND,
}:
raise ValueError("invalid time part")
hour = int(time_parts[0])
minute = int(time_parts[1])
second = (
int(time_parts[2])
if len(time_parts) == TIME_PARTS_HOUR_MINUTE_SECOND
else 0
)
except Exception as exc:
raise ValueError("invalid time part") from exc
if not (0 <= hour <= MAX_HOUR):
raise ValueError("hour out of range")
if not (0 <= minute <= MAX_MINUTE_SECOND):
raise ValueError("minute out of range")
if not (0 <= second <= MAX_MINUTE_SECOND):
raise ValueError("second out of range")
try:
return datetime(year, month, day, hour, minute, second)
except ValueError as exc:
raise ValueError("invalid calendar date/time") from exc