U
    dSG                     @  s  d Z ddlmZ ddlZddlZddlZddlZddl	m
Z
 ddlmZ ddlmZ ddlmZ dd	lmZ d
ddddgZeG dd de
ZddddZdddddZddddddddZdGd"d#d$d$d%d&d
ZdHd(d#d#d$dd$d)d*dZdId,d$d$d-d.dZd,d$d/d0dZd1d1ddd2d3d4d5d6Zd1d1d1ddd7d3d8d9d:Zdd7dd;d<d=Zdd7d>d;d?d@ZdJdCd$dDd$d$dEdFdZ dS )KzYTime humanizing functions.

These are largely borrowed from Django's `contrib.humanize`.
    )annotationsN)Enum)total_ordering   )_gettext)	_ngettext)intcommanaturaldeltanaturaltime
naturaldaynaturaldateprecisedeltac                   @  s<   e Zd ZdZdZdZdZdZdZdZ	dZ
d	d	d
ddZdS )Unitr   r                     
typing.Any)otherreturnc                 C  s   | j |j kr| j|jk S tS N)	__class__valueNotImplemented)selfr    r   1/tmp/pip-unpacked-wheel-kd4adnh7/humanize/time.py__lt__(   s    zUnit.__lt__N)__name__
__module____qualname__MICROSECONDSMILLISECONDSSECONDSMINUTESHOURSDAYSMONTHSYEARSr   r   r   r   r   r      s   r   zdt.datetime)r   c                   C  s
   t j S r   )dtdatetimenowr   r   r   r   _now.   s    r.   zdt.timedelta)deltar   c                 C  s    | j dk rt }|||   S | S )zReturn an "absolute" value for a timedelta, always representing a time distance.

    Args:
        delta (datetime.timedelta): Input timedelta.

    Returns:
        datetime.timedelta: Absolute timedelta.
    r   )daysr.   )r/   r-   r   r   r   _abs_timedelta2   s    	
r1   r-   r   zdt.datetime | Noneztuple[typing.Any, typing.Any])r   r-   r   c             	   C  s   |s
t  }t| tjr$| }||  }n\t| tjr>||  }| }nBz t| } tj| d}|| }W n  ttfk
r~   d| f Y S X |t|fS )zTurn a value into a date and a timedelta which represents how long ago it was.

    If that's not possible, return `(None, value)`.
    secondsN)	r.   
isinstancer+   r,   	timedeltaint
ValueError	TypeErrorr1   )r   r-   dater/   r   r   r   _date_and_deltaA   s    
r;   Tr4   zdt.timedelta | floatboolstr)r   monthsminimum_unitr   c              	   C  s  t |  }|t jt jt jfkr4d| d}t||}t| tjrJ| }n:zt	| } tj| d}W n  tt
fk
r   t|  Y S X |}t|j}t|j}	|	d }
|	d }	t	|	d }|
s"|	dk r"|dkrV|t jkr|jdk rtd	d
|j|j S |t jks0|t jkrNd|j  kr,dk rNn n|jd }tddt	|| S tdS |dkrhtdS |dk rtdd|| S d|  krdk rn ntdS d|  krdk rn n|d }tdd|| S d|  krdk rn ntdS d|k r|d }tdd|| S n|
dkr|	dkr>tdS |sTtdd|	|	 S |sjtdd|	|	 S |dkr|tdS td d!|| S |
dkr|s|	std"S |std#d$|	|	 S |r|dkrtd%S td&d'|| S td#d$|	|	 S td(d)|
d*d+t|
 S ),aT  Return a natural representation of a timedelta or number of seconds.

    This is similar to `naturaltime`, but does not add tense to the result.

    Args:
        value (datetime.timedelta, int or float): A timedelta or a number of seconds.
        months (bool): If `True`, then a number of months (based on 30.5 days) will be
            used for fuzziness between years.
        minimum_unit (str): The lowest unit that can be used.

    Returns:
        str (str or `value`): A natural representation of the amount of time
            elapsed unless `value` is not datetime.timedelta or cannot be
            converted to int. In that case, a `value` is returned unchanged.

    Raises:
        OverflowError: If `value` is too large to convert to datetime.timedelta.

    Examples
        Compare two timestamps in a custom local timezone::

        import datetime as dt
        from dateutil.tz import gettz

        berlin = gettz("Europe/Berlin")
        now = dt.datetime.now(tz=berlin)
        later = now + dt.timedelta(minutes=30)

        assert naturaldelta(later - now) == "30 minutes"
    zMinimum unit 'z' not supportedr3   m       >@r   r     %d microsecond%d microsecondsi@B %d millisecond%d millisecondsa momentza second<   	%d second
%d secondsx   za minute  	%d minute
%d minutesi   zan hour%d hour%d hoursza day%d day%d daysza month%d month	%d monthsza yearz1 year, %d dayz1 year, %d daysz1 year, 1 monthz1 year, %d monthz1 year, %d months%d year%d years%d%s)r   upperr%   r$   r#   r8   r5   r+   r6   r7   r9   r=   absr4   r0   microsecondsr   _replacer   )r   r>   r?   tmpmsgmin_unitr/   Z
use_monthsr4   r0   yearsZ
num_monthsZmillisecondsminuteshoursr   r   r   r	   Z   s    #


 










Fz"dt.datetime | dt.timedelta | float)r   futurer>   r?   whenr   c           	      C  s   |pt  }t| |d\}}|dkr*t| S t| tjtjfrD||k}|rPtdntd}t|||}|tdkrxtdS t|| S )a  Return a natural representation of a time in a resolution that makes sense.

    This is more or less compatible with Django's `naturaltime` filter.

    Args:
        value (datetime.datetime, datetime.timedelta, int or float): A `datetime`, a
            `timedelta`, or a number of seconds.
        future (bool): Ignored for `datetime`s and `timedelta`s, where the tense is
            always figured out based on the current time. For integers and floats, the
            return value will be past tense by default, unless future is `True`.
        months (bool): If `True`, then a number of months (based on 30.5 days) will be
            used for fuzziness between years.
        minimum_unit (str): The lowest unit that can be used.
        when (datetime.datetime): Point in time relative to which _value_ is
            interpreted.  Defaults to the current time in the local timezone.

    Returns:
        str: A natural representation of the input in a resolution that makes sense.
    r2   Nz%s from nowz%s agorG   r-   )	r.   r;   r=   r5   r+   r,   r6   r\   r	   )	r   rd   r>   r?   re   r-   r:   r/   Zagor   r   r   r
      s    
%b %dzdt.date | dt.datetime)r   formatr   c              	   C  s   zt | j| j| j} W n: tk
r4   t|  Y S  ttfk
rR   t|  Y S X | t j	  }|j
dkrttdS |j
dkrtdS |j
dkrtdS | |S )zReturn a natural day.

    For date values that are tomorrow, today or yesterday compared to
    present day return representing string. Otherwise, return a string
    formatted according to `format`.

    r   todayr   ZtomorrowZ	yesterday)r+   r:   yearmonthdayAttributeErrorr=   OverflowErrorr8   rh   r0   r\   strftime)r   rg   r/   r   r   r   r   	  s    


)r   r   c              	   C  s   zt | j| j| j} W n: tk
r4   t|  Y S  ttfk
rR   t|  Y S X t	| t j
  }|jdkrzt| dS t| S )zKLike `naturalday`, but append a year for dates more than ~five months away.gc@z%b %d %Y)r+   r:   rj   rk   rl   rm   r=   rn   r8   r1   rh   r0   r   )r   r/   r   r   r   r   '  s    

floatzcollections.abc.Iterable[Unit]ztuple[float, float])r   divisorunitr?   suppressr   c                 C  s.   ||kr| | dfS ||kr$d| fS t | |S )a  Divide `value` by `divisor` returning the quotient and remainder.

    If `unit` is `minimum_unit`, makes the quotient a float number and the remainder
    will be zero. The rational is that if `unit` is the unit of the quotient, we cannot
    represent the remainder because it would require a unit smaller than the
    `minimum_unit`.

    >>> from humanize.time import _quotient_and_remainder, Unit
    >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.DAYS, [])
    (1.5, 0)

    If unit is in `suppress`, the quotient will be zero and the remainder will be the
    initial value. The idea is that if we cannot use `unit`, we are forced to use a
    lower unit so we cannot do the division.

    >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [Unit.DAYS])
    (0, 36)

    In other case return quotient and remainder as `divmod` would do it.

    >>> _quotient_and_remainder(36, 24, Unit.DAYS, Unit.HOURS, [])
    (1, 12)

    r   )divmod)r   rq   rr   r?   rs   r   r   r   _quotient_and_remainder7  s
    ru   ztyping.Iterable[Unit])value1value2ratiorr   r`   rs   r   c                 C  s8   ||kr| ||  dfS ||kr0d|| |  fS | |fS )a  Return a tuple with two values.

    If the unit is in `suppress`, multiply `value1` by `ratio` and add it to `value2`
    (carry to right). The idea is that if we cannot represent `value1` we need to
    represent it in a lower unit.

    >>> from humanize.time import _carry, Unit
    >>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, [Unit.DAYS])
    (0, 54)

    If the unit is the minimum unit, `value2` is divided by `ratio` and added to
    `value1` (carry to left). We assume that `value2` has a lower unit so we need to
    carry it to `value1`.

    >>> _carry(2, 6, 24, Unit.DAYS, Unit.DAYS, [])
    (2.25, 0)

    Otherwise, just return the same input:

    >>> _carry(2, 6, 24, Unit.DAYS, Unit.SECONDS, [])
    (2, 6)
    r   r   )rv   rw   rx   rr   r`   rs   r   r   r   _carry_  s
    ry   )r`   rs   r   c                 C  s:   | |kr6t D ]}|| kr||kr|  S qd}t|| S )a  Return a minimum unit suitable that is not suppressed.

    If not suppressed, return the same unit:

    >>> from humanize.time import _suitable_minimum_unit, Unit
    >>> _suitable_minimum_unit(Unit.HOURS, []).name
    'HOURS'

    But if suppressed, find a unit greater than the original one that is not
    suppressed:

    >>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS]).name
    'DAYS'

    >>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS, Unit.DAYS]).name
    'MONTHS'
    z@Minimum unit is suppressed and no suitable replacement was found)r   r8   )r`   rs   rr   r_   r   r   r   _suitable_minimum_unit  s    
rz   z	set[Unit]c                 C  s,   t |}tD ]}|| kr q(|| q|S )a  Extend suppressed units (if any) with all units lower than the minimum unit.

    >>> from humanize.time import _suppress_lower_units, Unit
    >>> [x.name for x in sorted(_suppress_lower_units(Unit.SECONDS, [Unit.DAYS]))]
    ['MICROSECONDS', 'MILLISECONDS', 'DAYS']
    )setr   add)r`   rs   rr   r   r   r   _suppress_lower_units  s    r}   r   %0.2fzdt.timedelta | int | Noneztyping.Iterable[str])r   r?   rs   rg   r   c           #   
   C  sd  t | \}}|dkrt| S dd |D }t|  }t||}~t||}|j}|j}	|j}
t	t\}}}}}}}}t
|d|||\}}t
|d|||\}}t||	d|||\}}	t
|	d|||\}}	t
|	d|||\}}	t|	|
d	|||\}	}
t
|
d
|||\}}
t|
dd|||\}
}dd|fdd|fdd|fdd|fdd|fdd|	fdd|fdd|
fg}g }ttt|D ]\}}|\}}}|dks|s||krt|||} ||krt|d dkr| d|} n,||kr| dd} || t|  qr|| |  ||krr q$qrt|dkr:|d S d|dd  }!|d  }"td!|!|"f S )"a%  Return a precise representation of a timedelta.

    ```pycon
    >>> import datetime as dt
    >>> from humanize.time import precisedelta

    >>> delta = dt.timedelta(seconds=3633, days=2, microseconds=123000)
    >>> precisedelta(delta)
    '2 days, 1 hour and 33.12 seconds'

    ```

    A custom `format` can be specified to control how the fractional part
    is represented:

    ```pycon
    >>> precisedelta(delta, format="%0.4f")
    '2 days, 1 hour and 33.1230 seconds'

    ```

    Instead, the `minimum_unit` can be changed to have a better resolution;
    the function will still readjust the unit to use the greatest of the
    units that does not lose precision.

    For example setting microseconds but still representing the date with milliseconds:

    ```pycon
    >>> precisedelta(delta, minimum_unit="microseconds")
    '2 days, 1 hour, 33 seconds and 123 milliseconds'

    ```

    If desired, some units can be suppressed: you will not see them represented and the
    time of the other units will be adjusted to keep representing the same timedelta:

    ```pycon
    >>> precisedelta(delta, suppress=['days'])
    '49 hours and 33.12 seconds'

    ```

    Note that microseconds precision is lost if the seconds and all
    the units below are suppressed:

    ```pycon
    >>> delta = dt.timedelta(seconds=90, microseconds=100)
    >>> precisedelta(delta, suppress=['seconds', 'milliseconds', 'microseconds'])
    '1.50 minutes'

    ```

    If the delta is too small to be represented with the minimum unit,
    a value of zero will be returned:

    ```pycon
    >>> delta = dt.timedelta(seconds=1)
    >>> precisedelta(delta, minimum_unit="minutes")
    '0.02 minutes'

    >>> delta = dt.timedelta(seconds=0.1)
    >>> precisedelta(delta, minimum_unit="minutes")
    '0 minutes'

    ```
    Nc                 S  s   h | ]}t |  qS r   )r   rY   ).0sr   r   r   	<setcomp>  s     zprecisedelta.<locals>.<setcomp>r@   rA   iQ rL   rH   g    .ArB   r   r   rU   rV   rS   rT   rQ   rR   rO   rP   rM   rN   rI   rJ   rE   rF   rC   rD   rW   rX   z, ri   z	%s and %s)r;   r=   r   rY   rz   r}   r0   r4   r[   listru   ry   zipreversedr   mathmodfr]   appendr   lenjoinr\   )#r   r?   rs   rg   r:   r/   Zsuppress_setr`   r0   ZsecsZusecsr#   r$   r%   r&   r'   r(   r)   r*   ra   r>   rc   rb   msecsZ_unusedZfmtsZtextsrr   fmtZsingular_txtZ
plural_txtZ	fmt_valueZfmt_txtheadtailr   r   r   r     sp    H

    



)Tr4   )FTr4   N)rf   )r4   r   r~   )!__doc__
__future__r   collections.abccollectionsr,   r+   r   typingenumr   	functoolsr   Zi18nr   r\   r   numberr   __all__r   r.   r1   r;   r	   r
   r   r   ru   ry   rz   r}   r   r   r   r   r   <module>   sR   	       +('   