Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 5, 2026

Python 3.10's datetime.fromisoformat() requires fractional seconds to be exactly 3 or 6 digits. Juju 4.0 returns timestamps with arbitrary precision (e.g., 2026-01-05T23:34:25.50029526Z with 8 digits), causing parse failures.

Changes

  • ops/hookcmds/_utils.py: Modified datetime_from_iso() to use existing parse_rfc3339 from ops._private.timeconv, which handles arbitrary precision fractional seconds. Added logic to handle timestamps without timezone by assuming UTC.

  • test/test_hookcmds.py: Added parametrized test covering edge cases: no fractional seconds, 8 digits, 5 digits, 1 digit, 9 digits (nanosecond precision), and no timezone.

Example

# Before: Fails on Python 3.10
datetime_from_iso('2026-01-05T23:34:25.50029526Z')  # ValueError

# After: Uses parse_rfc3339 which handles arbitrary precision
datetime_from_iso('2026-01-05T23:34:25.50029526Z')  # 2026-01-05 23:34:25.500295+00:00
datetime_from_iso('2026-04-10T18:34:45.65844+00:00')  # 2026-04-10 18:34:45.658440+00:00

This solution reuses existing, well-tested code from the repository rather than reimplementing datetime parsing logic.

Original prompt

This section details on the original issue you should resolve

<issue_title>Failed to parse datetime in datetime.datetime.fromisoformat()</issue_title>
<issue_description>I came across this bug while running tests in canonical/self-signed-certificates-operator:

The datetime conversion in ops/hookcmds/_utils.py fails because the expiry string of the secret is an Invalid isoformat string.

This is probably happening because we're using Python 3.10 in the tests, of which the datetime package can not actually parse the string sent by juju 4: "2026-04-10T18:34:45.65844+00:00"

The format for the string should be "YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]]"
A careful inspection of the format will have you notice that the reason for the failed parse is the fact that the millisecond number must either be 3 or 6 digits long according to the format.

At some point between 3.10 where this format was given, and now where this format isn't specified in the documentation for datetime.datetime.fromisoformat(), this function was expanded to parse beyond this strict format. I haven't bothered to check when.

This could probably be handled by either padding the number manually in the relevant function or using another lib to parse the string.

Juju version: 4
Python version: 3.10.19</issue_description>

<agent_instructions>You need to keep support for Python 3.10. Do not add a new dependency. Examples of the output are in the second comment on the issue. Make sure tests are added. Comments are for explaining why, not what.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@tonyandrewmeyer Juju 3.6:
tameyer@tam-canonical-2:~$ juju exec --unit beszel/0 -- secret-info-get secret://058042ef-6ba4-443b-8753-d5ed36dcdc64/d5e3m5nmp25c769jhv20 --format=json
{"d5e3m5nmp25c769jhv20":{"revision":1,"label":"","owner":"application","rotation":"never","expiry":"2026-01-05T23:28:38Z"}}

Juju 4.0:

tameyer@tam-canonical-2:~$ juju exec --unit ubuntu-lite/0 -- secret-info-get secret://865a57a5-67c0-4827-82c5-b802b2e34df4/d5e3osd8kg3s5i7jvnmg --format=json
{"d5e3osd8kg3s5i7jvnmg":{"revision":1,"label":"","owner":"application","rotation":"never","expiry":"2026-01-05T23:34:25.50029526Z"}}
```</body></comment_new>
</comments>


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits January 5, 2026 22:42
Co-authored-by: tonyandrewmeyer <826522+tonyandrewmeyer@users.noreply.github.com>
Co-authored-by: tonyandrewmeyer <826522+tonyandrewmeyer@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix datetime parsing error in fromisoformat method fix: normalize fractional seconds in datetime parsing for Python 3.10 Jan 5, 2026
Copilot AI requested a review from tonyandrewmeyer January 5, 2026 22:46
Copy link
Collaborator

@tonyandrewmeyer tonyandrewmeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot (a) you've gone a bit overboard with the tests here. You could parametrise the number of digits, but really just the edge cases should be sufficient.

(b) the repo already has code for handling Go style timestamps in ops/_private/timeconv.py - it'd be better to re-use that than reimplement it in the same package.

Co-authored-by: tonyandrewmeyer <826522+tonyandrewmeyer@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 6, 2026

@copilot (a) you've gone a bit overboard with the tests here. You could parametrise the number of digits, but really just the edge cases should be sufficient.

(b) the repo already has code for hand...

Updated in c74d1d0:

  • Reduced tests to 6 edge-case scenarios using parametrization
  • Replaced custom parsing logic with existing parse_rfc3339 from ops._private.timeconv

Copilot AI changed the title fix: normalize fractional seconds in datetime parsing for Python 3.10 fix: use parse_rfc3339 for datetime parsing to support Python 3.10 Jan 6, 2026
Copilot AI requested a review from tonyandrewmeyer January 6, 2026 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Failed to parse datetime in datetime.datetime.fromisoformat()

2 participants