diff --git a/app/api/inspections.py b/app/api/inspections.py index 3a17d0f..caeee38 100644 --- a/app/api/inspections.py +++ b/app/api/inspections.py @@ -41,13 +41,24 @@ _UUID_RE = re.compile( def _parse_datetime(value): - """Parse an ISO 8601 datetime string; return None on failure.""" + """Parse an ISO 8601 datetime string; return None on failure. + + Handles the formats produced by both the web forms and iOS + ISO8601DateFormatter(), which appends a 'Z' UTC suffix: + 2026-05-28T09:41:00 (web form) + 2026-05-28T09:41:00.000 (web form with ms) + 2026-05-28T09:41:00Z (iOS ISO8601DateFormatter) + 2026-05-28T09:41:00.000000Z (iOS with fractional seconds) + """ if not value: return None from datetime import datetime + # Strip trailing 'Z' (UTC marker) so strptime can parse it as naive datetime. + # The system treats all datetimes as Eastern-local; UTC offset is ignored. + normalised = value.rstrip('Z') if isinstance(value, str) else value for fmt in ('%Y-%m-%dT%H:%M:%S', '%Y-%m-%dT%H:%M:%S.%f', '%Y-%m-%d'): try: - return datetime.strptime(value, fmt) + return datetime.strptime(normalised, fmt) except (ValueError, TypeError): pass return None @@ -275,6 +286,12 @@ def create_inspection(): notes_payload['_inspector_notes'] = data['notes'] notes_payload['_form_data'] = form_data + # If the client sent completed_at but it failed to parse (e.g. unrecognised + # format), fall back to now rather than storing NULL. This mirrors the + # PATCH handler's behaviour. + if completed_at is None and status == 'completed': + completed_at = now_eastern() + inspection = Inspection( template_id = template_id, facility_id = facility_id,