Repository navigation
isISO8601Date rejects valid ISO 8601 timestamps, including the form the NWB schema recommends #329
Description
Activity
Note on provenance: This was found by Claude Opus 5 while reviewing #320. The output below was produced by building and running the code, but I have only briefly reviewed the analysis myself and I am not an expert in this area. Please review it critically.
Worth recording here because the downstream effect on
Subjectis larger than a validation helper returning the wrong answer.Passing
dateOfBirth = "2024-01-15T00:00:00+00:00"toNWBFile::initializemakes it returnStatus::Failure, even though the file it produced is complete and valid apart from the missingdate_of_birth. A caller that treats a nonSuccessreturn as "recording setup failed" aborts on good data.Measured acceptance, calling isISO8601Date directly
"2024-01-15T00:00:00.000000+00:00" true <- the shape getCurrentTime() emits "2024-01-15T00:00:00+00:00" false "2024-01-15T00:00:00Z" false "2024-01-15T00:00:00.123456Z" false "2024-01-15" false "2024-01-15T00:00:00" false "2024-01-15T00:00:00.5+00:00" trueThe resulting file state after that
Failure:NWBFile::initialize returned Failure /general/subject exists subject_id exists species exists date_of_birth absentSo the group is written, everything except
date_of_birthis written, and the caller is told it failed. The partial write, and the fact that a corrected retry reports success while changing nothing, are tracked separately in #338.- addedcategory: bugerrors in the code or code behaviorerrors in the code or code behaviorpriority: mediumnon-critical problem and/or affecting only a small set of usersnon-critical problem and/or affecting only a small set of userstopic: apiissues related to the core AqNWB APIissues related to the core AqNWB APItopic: testingissues related to testingissues related to testing
on Sep 3, 2026 - added a commit that references this issue
on Sep 3, 2026
AQNWB::isISO8601Date(src/Utils.hpp:200) requires a fractional seconds part and a numeric±HH:MMoffset. Both are optional in ISO 8601.This has stayed hidden because
getCurrentTime()(src/Utils.hpp:174) emits exactly the one accepted shape, so AqNWB generated values always pass. It bites on caller supplied values, atNWBFile.cpp:81(sessionStartTime),NWBFile.cpp:86(timestampsReferenceTime), andSubject.cpp:73(date_of_birth).Rejected, all valid ISO 8601:
2024-01-15T00:00:00Z, the UTC designator2024-01-15T00:00:00.000Z, the form the NWB schema'sisodatetimedoc text describes ("Dates stored in UTC end in "Z" with no timezone offset. Date accuracy is up to milliseconds.")2024-01-15T00:00:00+00:00, whatdatetime.isoformat()produces for a whole second2024-01-15T00:00:00.123+0000, basic format offsetThe tests assert the wrong contract
Four assertions in
tests/testUtilsFunctions.cpp:21-36classify valid ISO 8601 as invalid, with comments that do not hold. Fractional seconds are optional,+0200and-0800are valid basic format offsets, andZspecifies UTC rather than omitting it.The other three assertions in that section are correct and should stay: a space in place of
T, a string with no timezone information, and free text. Requiring an explicit timezone is a real NWB best practice.Proposed change
Checked against every string above and every string the current tests accept. It still rejects the hour only offset (
+02), which ISO 8601 permits but nothing in the NWB ecosystem emits.Relatedly, the function name says
Datewhile it validates a datetime. Rename toisISO8601DateTime?Acceptance criteria
getCurrentTime()output still validates.T, and free text remain rejected.tests/testUtilsFunctions.cppmoves the four mislabeled cases to the valid section and drops the incorrect comments.Out of scope: a bare date such as
2024-01-15stays rejected, since the NWB dtype for all three fields isisodatetime.Generated by Claude Code and reviewed by me.