ai-content-maker/.venv/Lib/site-packages/numba/np/npdatetime_helpers.py

213 lines
6.5 KiB
Python

"""
Helper functions for np.timedelta64 and np.datetime64.
For now, multiples-of-units (for example timedeltas expressed in tens
of seconds) are not supported.
"""
import numpy as np
DATETIME_UNITS = {
'Y': 0, # Years
'M': 1, # Months
'W': 2, # Weeks
# Yes, there's a gap here
'D': 4, # Days
'h': 5, # Hours
'm': 6, # Minutes
's': 7, # Seconds
'ms': 8, # Milliseconds
'us': 9, # Microseconds
'ns': 10, # Nanoseconds
'ps': 11, # Picoseconds
'fs': 12, # Femtoseconds
'as': 13, # Attoseconds
'': 14, # "generic", i.e. unit-less
}
NAT = np.timedelta64('nat').astype(np.int64)
# NOTE: numpy has several inconsistent functions for timedelta casting:
# - can_cast_timedelta64_{metadata,units}() disallows "safe" casting
# to and from generic units
# - cast_timedelta_to_timedelta() allows casting from (but not to)
# generic units
# - compute_datetime_metadata_greatest_common_divisor() allows casting from
# generic units (used for promotion)
def same_kind(src, dest):
"""
Whether the *src* and *dest* units are of the same kind.
"""
return (DATETIME_UNITS[src] < 5) == (DATETIME_UNITS[dest] < 5)
def can_cast_timedelta_units(src, dest):
# Mimic NumPy's "safe" casting and promotion
# `dest` must be more precise than `src` and they must be compatible
# for conversion.
# XXX should we switch to enforcing "same-kind" for Numpy 1.10+ ?
src = DATETIME_UNITS[src]
dest = DATETIME_UNITS[dest]
if src == dest:
return True
if src == 14:
return True
if src > dest:
return False
if dest == 14:
# unit-less timedelta64 is not compatible with anything else
return False
if src <= 1 and dest > 1:
# Cannot convert between months or years and other units
return False
return True
# Exact conversion factors from one unit to the immediately more precise one
_factors = {
0: (1, 12), # Years -> Months
2: (4, 7), # Weeks -> Days
4: (5, 24), # Days -> Hours
5: (6, 60), # Hours -> Minutes
6: (7, 60), # Minutes -> Seconds
7: (8, 1000),
8: (9, 1000),
9: (10, 1000),
10: (11, 1000),
11: (12, 1000),
12: (13, 1000),
}
def _get_conversion_multiplier(big_unit_code, small_unit_code):
"""
Return an integer multiplier allowing to convert from *big_unit_code*
to *small_unit_code*.
None is returned if the conversion is not possible through a
simple integer multiplication.
"""
# Mimics get_datetime_units_factor() in NumPy's datetime.c,
# with a twist to allow no-op conversion from generic units.
if big_unit_code == 14:
return 1
c = big_unit_code
factor = 1
while c < small_unit_code:
try:
c, mult = _factors[c]
except KeyError:
# No possible conversion
return None
factor *= mult
if c == small_unit_code:
return factor
else:
return None
def get_timedelta_conversion_factor(src_unit, dest_unit):
"""
Return an integer multiplier allowing to convert from timedeltas
of *src_unit* to *dest_unit*.
"""
return _get_conversion_multiplier(DATETIME_UNITS[src_unit],
DATETIME_UNITS[dest_unit])
def get_datetime_timedelta_conversion(datetime_unit, timedelta_unit):
"""
Compute a possible conversion for combining *datetime_unit* and
*timedelta_unit* (presumably for adding or subtracting).
Return (result unit, integer datetime multiplier, integer timedelta
multiplier). RuntimeError is raised if the combination is impossible.
"""
# XXX now unused (I don't know where / how Numpy uses this)
dt_unit_code = DATETIME_UNITS[datetime_unit]
td_unit_code = DATETIME_UNITS[timedelta_unit]
if td_unit_code == 14 or dt_unit_code == 14:
return datetime_unit, 1, 1
if td_unit_code < 2 and dt_unit_code >= 2:
# Cannot combine Y or M timedelta64 with a finer-grained datetime64
raise RuntimeError("cannot combine datetime64(%r) and timedelta64(%r)"
% (datetime_unit, timedelta_unit))
dt_factor, td_factor = 1, 1
# If years or months, the datetime unit is first scaled to weeks or days,
# then conversion continues below. This is the same algorithm as used
# in Numpy's get_datetime_conversion_factor() (src/multiarray/datetime.c):
# """Conversions between years/months and other units use
# the factor averaged over the 400 year leap year cycle."""
if dt_unit_code == 0:
if td_unit_code >= 4:
dt_factor = 97 + 400 * 365
td_factor = 400
dt_unit_code = 4
elif td_unit_code == 2:
dt_factor = 97 + 400 * 365
td_factor = 400 * 7
dt_unit_code = 2
elif dt_unit_code == 1:
if td_unit_code >= 4:
dt_factor = 97 + 400 * 365
td_factor = 400 * 12
dt_unit_code = 4
elif td_unit_code == 2:
dt_factor = 97 + 400 * 365
td_factor = 400 * 12 * 7
dt_unit_code = 2
if td_unit_code >= dt_unit_code:
factor = _get_conversion_multiplier(dt_unit_code, td_unit_code)
assert factor is not None, (dt_unit_code, td_unit_code)
return timedelta_unit, dt_factor * factor, td_factor
else:
factor = _get_conversion_multiplier(td_unit_code, dt_unit_code)
assert factor is not None, (dt_unit_code, td_unit_code)
return datetime_unit, dt_factor, td_factor * factor
def combine_datetime_timedelta_units(datetime_unit, timedelta_unit):
"""
Return the unit result of combining *datetime_unit* with *timedelta_unit*
(e.g. by adding or subtracting). None is returned if combining
those units is forbidden.
"""
dt_unit_code = DATETIME_UNITS[datetime_unit]
td_unit_code = DATETIME_UNITS[timedelta_unit]
if dt_unit_code == 14:
return timedelta_unit
elif td_unit_code == 14:
return datetime_unit
if td_unit_code < 2 and dt_unit_code >= 2:
return None
if dt_unit_code > td_unit_code:
return datetime_unit
else:
return timedelta_unit
def get_best_unit(unit_a, unit_b):
"""
Get the best (i.e. finer-grained) of two units.
"""
a = DATETIME_UNITS[unit_a]
b = DATETIME_UNITS[unit_b]
if a == 14:
return unit_b
if b == 14:
return unit_a
if b > a:
return unit_b
return unit_a
def datetime_minimum(a, b):
pass
def datetime_maximum(a, b):
pass