What happened?
SeriesResource.airTime is a wall-clock time, but it's typed as a Duration and parsed with DurationParser. Sonarr sends airTime as "21:00" meaning 9pm; DurationParser reads that as minutes-and-seconds, so once the groupCount guards are fixed it comes out as PT21M — 21 minutes.
Both readings of "21:00" are legitimate, which is the problem: for a runTime it really is 21 minutes, and for an airTime it's 9pm. One parser can't tell them apart, because the ambiguity is in the field's meaning rather than in the string.
What did you expect to happen?
airTime to come back as a time of day. "21:00" → 21:00 local, not a 21-minute duration.
Steps to reproduce
mvn -pl Lib install (or use Lib/target/classes)
- Call
DurationParser.parse("21:00", true)
- Result is
PT-24H-39M today; PT21M once the guard bug is fixed. Either way it isn't 9pm.
Relevant logs or screenshots
parse("21:00") = PT-24H-39M (current; PT21M with the guards fixed)
parse("5:30") = PT-24H-54M-30S
parse("1:02:03:04") = PT99H1M2S (4d 3h 1m 2s)
Suspected root cause
Type confusion rather than a parsing bug — SeriesResource.java:25 declares private final Duration airTime; and :73 fills it from DurationParser.get. A LocalTime and a separate parser alongside the existing InstantParser would keep the two meanings apart, and airTime() would stop handing plugins a Duration that means a clock time.
Two smaller things in the same area, both only visible once the guards are fixed, and I'm less sure about these:
- Three- and four-field values read
mm:ss:hh and mm:ss:hh:dd, since groups map left-to-right from the first field. Two-field mm:ss matches the usual short-duration convention, but the longer forms are normally hh:mm:ss / dd:hh:mm:ss. Anchoring the assignment from the right, based on how many groups actually matched, would give the shifting behaviour.
- Whether any
runTime/duration field actually arrives in colon form is worth confirming before changing that — the *arr APIs send most of them as integer minutes, which take the parseInt path and never reach this block.
Environment
- Fetcharr version: repo at
23b0e6c261137afe1a7d5badd983b88629833e18 (main)
- Not running the app — called the built
Lib/target/classes directly
- JDK 25 (class files are 21), tinylog + unirest from
~/.m2
- OS: AlmaLinux 9
Other context
Separate from #35, though they touch the same block — fixing the guards makes this one visible rather than fixing it.
Claude Code
What happened?
SeriesResource.airTimeis a wall-clock time, but it's typed as aDurationand parsed withDurationParser. Sonarr sendsairTimeas"21:00"meaning 9pm;DurationParserreads that as minutes-and-seconds, so once thegroupCountguards are fixed it comes out asPT21M— 21 minutes.Both readings of
"21:00"are legitimate, which is the problem: for arunTimeit really is 21 minutes, and for anairTimeit's 9pm. One parser can't tell them apart, because the ambiguity is in the field's meaning rather than in the string.What did you expect to happen?
airTimeto come back as a time of day."21:00"→ 21:00 local, not a 21-minute duration.Steps to reproduce
mvn -pl Lib install(or useLib/target/classes)DurationParser.parse("21:00", true)PT-24H-39Mtoday;PT21Monce the guard bug is fixed. Either way it isn't 9pm.Relevant logs or screenshots
Suspected root cause
Type confusion rather than a parsing bug —
SeriesResource.java:25declaresprivate final Duration airTime;and:73fills it fromDurationParser.get. ALocalTimeand a separate parser alongside the existingInstantParserwould keep the two meanings apart, andairTime()would stop handing plugins aDurationthat means a clock time.Two smaller things in the same area, both only visible once the guards are fixed, and I'm less sure about these:
mm:ss:hhandmm:ss:hh:dd, since groups map left-to-right from the first field. Two-fieldmm:ssmatches the usual short-duration convention, but the longer forms are normallyhh:mm:ss/dd:hh:mm:ss. Anchoring the assignment from the right, based on how many groups actually matched, would give the shifting behaviour.runTime/durationfield actually arrives in colon form is worth confirming before changing that — the *arr APIs send most of them as integer minutes, which take theparseIntpath and never reach this block.Environment
23b0e6c261137afe1a7d5badd983b88629833e18(main)Lib/target/classesdirectly~/.m2Other context
Separate from #35, though they touch the same block — fixing the guards makes this one visible rather than fixing it.
Claude Code