@@ -347,79 +347,41 @@ def _quotient_and_remainder(
347347    unit : Unit ,
348348    minimum_unit : Unit ,
349349    suppress : Iterable [Unit ],
350+     format : str ,
350351) ->  tuple [float , float ]:
351352    """Divide `value` by `divisor`, returning the quotient and remainder. 
352353
353-     If `unit` is `minimum_unit`, the quotient will be a float number and the remainder  
354-     will be zero. The rationale is that if `unit` is  the unit of the quotient, we cannot  
355-     represent the remainder because it would require a unit smaller than  the 
356-     `minimum_unit`. 
354+     If `unit` is `minimum_unit`, the quotient will be the rounding of `value / divisor`  
355+     according to the `format` string and  the remainder will be zero. The rationale is  
356+     that if `unit` is the unit of the quotient, we cannot represent  the remainder  
357+     because it would require a unit smaller than the  `minimum_unit`. 
357358
358359    >>> from humanize.time import _quotient_and_remainder, Unit 
359-     >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.DAYS, []) 
360+     >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.DAYS, [], "%0.2f" ) 
360361    (1.5, 0) 
361362
362363    If `unit` is in `suppress`, the quotient will be zero and the remainder will be the 
363364    initial value. The idea is that if we cannot use `unit`, we are forced to use a 
364365    lower unit, so we cannot do the division. 
365366
366-     >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [Unit.DAYS]) 
367+     >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [Unit.DAYS], "%0.2f" ) 
367368    (0, 36) 
368369
369370    In other cases, return the quotient and remainder as `divmod` would do it. 
370371
371-     >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, []) 
372+     >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [], "%0.2f" ) 
372373    (1, 12) 
373374
374375    """ 
375376    if  unit  ==  minimum_unit :
376-         return  value  /  divisor , 0 
377+         return  _rounding_by_fmt ( format ,  value  /  divisor ) , 0 
377378
378379    if  unit  in  suppress :
379380        return  0 , value 
380381
381382    return  divmod (value , divisor )
382383
383384
384- def  _carry (
385-     value1 : float ,
386-     value2 : float ,
387-     ratio : float ,
388-     unit : Unit ,
389-     min_unit : Unit ,
390-     suppress : Iterable [Unit ],
391- ) ->  tuple [float , float ]:
392-     """Return a tuple with two values. 
393- 
394-     If `unit` is in `suppress`, multiply `value1` by `ratio` and add it to `value2` 
395-     (carry to right). The idea is that if we cannot represent `value1`, we need to 
396-     represent it in a lower unit. 
397- 
398-     >>> from humanize.time import _carry, Unit 
399-     >>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, [Unit.DAYS]) 
400-     (0, 54) 
401- 
402-     If `unit` is the minimum unit, divide `value2` by `ratio` and add it to `value1` 
403-     (carry to left). We assume that `value2` has a lower unit, so we need to 
404-     carry it to `value1`. 
405- 
406-     >>> _carry(2, 6, 24, Unit.DAYS, Unit.DAYS, []) 
407-     (2.25, 0) 
408- 
409-     Otherwise, just return the same input: 
410- 
411-     >>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, []) 
412-     (2, 6) 
413-     """ 
414-     if  unit  ==  min_unit :
415-         return  value1  +  value2  /  ratio , 0 
416- 
417-     if  unit  in  suppress :
418-         return  0 , value2  +  value1  *  ratio 
419- 
420-     return  value1 , value2 
421- 
422- 
423385def  _suitable_minimum_unit (min_unit : Unit , suppress : Iterable [Unit ]) ->  Unit :
424386    """Return a minimum unit suitable that is not suppressed. 
425387
@@ -574,23 +536,54 @@ def precisedelta(
574536    #       years, days = divmod(years, days) 
575537    # 
576538    # The same applies for months, hours, minutes and milliseconds below 
577-     years , days  =  _quotient_and_remainder (days , 365 , YEARS , min_unit , suppress_set )
578-     months , days  =  _quotient_and_remainder (days , 30.5 , MONTHS , min_unit , suppress_set )
539+     years , days  =  _quotient_and_remainder (
540+         days , 365 , YEARS , min_unit , suppress_set , format 
541+     )
542+     months , days  =  _quotient_and_remainder (
543+         days , 30.5 , MONTHS , min_unit , suppress_set , format 
544+     )
579545
580546    secs  =  days  *  24  *  3600  +  secs 
581-     days , secs  =  _quotient_and_remainder (secs , 24  *  3600 , DAYS , min_unit , suppress_set )
547+     days , secs  =  _quotient_and_remainder (
548+         secs , 24  *  3600 , DAYS , min_unit , suppress_set , format 
549+     )
582550
583-     hours , secs  =  _quotient_and_remainder (secs , 3600 , HOURS , min_unit , suppress_set )
584-     minutes , secs  =  _quotient_and_remainder (secs , 60 , MINUTES , min_unit , suppress_set )
551+     hours , secs  =  _quotient_and_remainder (
552+         secs , 3600 , HOURS , min_unit , suppress_set , format 
553+     )
554+     minutes , secs  =  _quotient_and_remainder (
555+         secs , 60 , MINUTES , min_unit , suppress_set , format 
556+     )
585557
586-     secs , usecs  =  _carry (secs , usecs , 1e6 , SECONDS , min_unit , suppress_set )
558+     usecs  =  secs  *  1e6  +  usecs 
559+     secs , usecs  =  _quotient_and_remainder (
560+         usecs , 1e6 , SECONDS , min_unit , suppress_set , format 
561+     )
587562
588563    msecs , usecs  =  _quotient_and_remainder (
589-         usecs , 1000 , MILLISECONDS , min_unit , suppress_set 
564+         usecs , 1000 , MILLISECONDS , min_unit , suppress_set ,  format 
590565    )
591566
592-     # if _unused != 0 we have lost some precision 
593-     usecs , _unused  =  _carry (usecs , 0 , 1 , MICROSECONDS , min_unit , suppress_set )
567+     # Due to rounding, it could be that a unit is high enough to be promoted to a higher 
568+     # unit. Example: 59.9 minutes was rounded to 60 minutes, and thus it should become 0 
569+     # minutes and one hour more. 
570+     if  msecs  >=  1_000  and  SECONDS  not  in   suppress_set :
571+         msecs  -=  1_000 
572+         secs  +=  1 
573+     if  secs  >=  60  and  MINUTES  not  in   suppress_set :
574+         secs  -=  60 
575+         minutes  +=  1 
576+     if  minutes  >=  60  and  HOURS  not  in   suppress_set :
577+         minutes  -=  60 
578+         hours  +=  1 
579+     if  hours  >=  24  and  DAYS  not  in   suppress_set :
580+         hours  -=  24 
581+         days  +=  1 
582+     # When adjusting we should not deal anymore with fractional days as all rounding has 
583+     # been already made. We promote 31 days to an extra month. 
584+     if  days  >=  31  and  MONTHS  not  in   suppress_set :
585+         days  -=  31 
586+         months  +=  1 
594587
595588    fmts  =  [
596589        ("%d year" , "%d years" , years ),
@@ -606,10 +599,6 @@ def precisedelta(
606599    texts : list [str ] =  []
607600    for  unit , fmt  in  zip (reversed (Unit ), fmts ):
608601        singular_txt , plural_txt , fmt_value  =  fmt 
609- 
610-         if  unit  ==  min_unit :
611-             fmt_value  =  _rounding_by_fmt (format , fmt_value )
612- 
613602        if  fmt_value  >  0  or  (not  texts  and  unit  ==  min_unit ):
614603            _fmt_value  =  2  if  1  <  fmt_value  <  2  else  int (fmt_value )
615604            fmt_txt  =  _ngettext (singular_txt , plural_txt , _fmt_value )
0 commit comments