aniketwaghh opened a new issue, #72694:
URL: https://github.com/apache/airflow/issues/72694

   ### Apache Airflow version
   
   main (`31117014f3`)
   
   ### What happened and how to reproduce it?
   
   `td_format` renders a negative duration as a large positive one. A negative 
hour comes back as nearly thirty days.
   
   ```python
   from datetime import timedelta
   from airflow._shared.timezones.timezone import td_format
   
   td_format(timedelta(seconds=-3752))   # '29d:22h:57M:28s'
   td_format(timedelta(days=-5))         # '25d'
   td_format(timedelta(seconds=-0.4))    # '29d:23h:59M:59s'
   td_format(-3752)                      # '<1s'
   ```
   
   The last two lines are the same duration expressed two ways, and they 
disagree: the `timedelta` branch says thirty days, the numeric branch says 
under a second.
   
   The cause is the day-to-month conversion:
   
   ```python
   months, delta.days = divmod(delta.days, 30)
   ```
   
   `divmod` floors, so a `relativedelta` of `days=-1` becomes `months=-1, 
days=+29`. `_format_part` then drops any component below 1:
   
   ```python
   value = int(getattr(delta, key))
   if value < 1:
       return ""
   ```
   
   which removes the `-1 month` that would have cancelled the `+29 days`, and 
leaves the days behind. Stepping through `timedelta(seconds=-3752)`:
   
   ```
   relativedelta(-3752s)      -> days=-1, hours=+22, minutes=+57, seconds=+28
   divmod(-1, 30)             -> (-1, 29)
   after normalize            -> months=-1, days=+29, hours=+22, minutes=+57, 
seconds=+28
   months = -1                -> dropped by `value < 1`
   days   = +29               -> kept
   ```
   
   The numeric branch differs because `relativedelta(seconds=-3752)` keeps a 
single negative `seconds` field rather than borrowing a day, so every component 
is negative, every one is dropped, and the empty result falls through to `<1s`.
   
   ### What you think should happen instead?
   
   A negative duration should read as a negative duration — the magnitude 
formatted as it is today with a leading `-` — and both input types should agree 
for the same duration. `timedelta(seconds=-0.4)` should give `<1s` the way 
`timedelta(seconds=0.4)` does.
   
   ### Anything else?
   
   Worth being straight about the impact: nothing in the tree calls `td_format` 
today. It arrived in #20112 for the duration column in the old Flask views, and 
the React UI replaced those. So this is latent rather than user-visible right 
now.
   
   Two things still argue for fixing it. It lives in `shared/timezones`, which 
is vendored into both distributions — `airflow._shared.timezones` and 
`airflow.sdk._shared.timezones` — so it is importable by anything that depends 
on either. And #62123 fixed the zero-duration behaviour of this same function 
in February, touching exactly the two files this would touch, so the function 
is evidently still maintained.
   
   Negative durations are not hypothetical in a distributed scheduler: a task 
whose recorded end precedes its start, from clock skew between components, 
produces one.
   
   ### Are you willing to submit PR?
   
   Yes — happy to put one up (sign preserved, both branches agreed, 
parametrised tests alongside the existing `test_td_format`). Say the word if 
you would rather leave an uncalled helper alone and I will drop it.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to